diff --git a/crates/autopilot/src/database.rs b/crates/autopilot/src/database.rs index 33927a98d0..f641263cb5 100644 --- a/crates/autopilot/src/database.rs +++ b/crates/autopilot/src/database.rs @@ -28,12 +28,19 @@ impl Postgres { let metrics = Metrics::get(); // update table row metrics - for &table in database::ALL_TABLES { + for &table in database::TABLES { let mut ex = self.0.acquire().await?; let count = count_rows_in_table(&mut ex, table).await?; metrics.table_rows.with_label_values(&[table]).set(count); } + // update table row metrics + for &table in database::LARGE_TABLES { + let mut ex = self.0.acquire().await?; + let count = estimate_rows_in_table(&mut ex, table).await?; + metrics.table_rows.with_label_values(&[table]).set(count); + } + // update unused app data metric { let mut ex = self.0.acquire().await?; @@ -50,6 +57,11 @@ async fn count_rows_in_table(ex: &mut PgConnection, table: &str) -> sqlx::Result sqlx::query_scalar(&query).fetch_one(ex).await } +async fn estimate_rows_in_table(ex: &mut PgConnection, table: &str) -> sqlx::Result { + let query = format!("SELECT reltuples::bigint FROM pg_class WHERE relname='{table}';"); + sqlx::query_scalar(&query).fetch_one(ex).await +} + async fn count_unused_app_data(ex: &mut PgConnection) -> sqlx::Result { let query = r#" SELECT diff --git a/crates/autopilot/src/run.rs b/crates/autopilot/src/run.rs index df1f949afc..5a452f8218 100644 --- a/crates/autopilot/src/run.rs +++ b/crates/autopilot/src/run.rs @@ -619,7 +619,7 @@ pub async fn run(args: Arguments) { .await; let run = RunLoop { solvable_orders_cache, - database: db, + database: Arc::new(db), drivers: args.drivers.into_iter().map(Driver::new).collect(), current_block: current_block_stream, web3, diff --git a/crates/autopilot/src/run_loop.rs b/crates/autopilot/src/run_loop.rs index a137f0db3d..35b132ee5a 100644 --- a/crates/autopilot/src/run_loop.rs +++ b/crates/autopilot/src/run_loop.rs @@ -44,7 +44,7 @@ use { pub struct RunLoop { pub solvable_orders_cache: Arc, - pub database: Postgres, + pub database: Arc, pub drivers: Vec, pub current_block: CurrentBlockStream, pub web3: Web3, @@ -299,6 +299,12 @@ impl RunLoop { tracing::warn!(?err, driver = %driver.name, "settlement failed"); } } + let unsettled_orders: Vec<_> = solutions + .iter() + .flat_map(|p| p.solution.orders.keys()) + .filter(|uid| !solution.orders.contains_key(uid)) + .collect(); + Metrics::matched_unsettled(driver, unsettled_orders.as_slice()); } } @@ -313,17 +319,22 @@ impl RunLoop { ); let request = &request; - let start = Instant::now(); - self.database - .store_order_events( - &auction - .orders - .iter() - .map(|o| (o.metadata.uid, OrderEventLabel::Ready)) - .collect_vec(), - ) - .await; - tracing::debug!(elapsed=?start.elapsed(), aution_id=%id, "storing order events took"); + let db = self.database.clone(); + let events = auction + .orders + .iter() + .map(|o| (o.metadata.uid, OrderEventLabel::Ready)) + .collect_vec(); + // insert into `order_events` table operations takes a while and the result is + // ignored, so we run it in the background + tokio::spawn( + async move { + let start = Instant::now(); + db.store_order_events(&events).await; + tracing::debug!(elapsed=?start.elapsed(), events_count=events.len(), "stored order events"); + } + .instrument(tracing::Span::current()), + ); let start = Instant::now(); futures::future::join_all(self.drivers.iter().map(|driver| async move { @@ -641,6 +652,11 @@ struct Metrics { /// Tracks the result of driver `/settle` requests. #[metric(labels("driver", "result"))] settle: prometheus::IntCounterVec, + + /// Tracks the number of orders that were part of some but not the winning + /// solution together with the winning driver that did't include it. + #[metric(labels("ignored_by"))] + matched_unsettled: prometheus::IntCounterVec, } impl Metrics { @@ -719,4 +735,14 @@ impl Metrics { .with_label_values(&[&driver.name, label]) .inc(); } + + fn matched_unsettled(winning: &Driver, unsettled: &[&OrderUid]) { + if !unsettled.is_empty() { + tracing::debug!(?unsettled, "some orders were matched but not settled"); + } + Self::get() + .matched_unsettled + .with_label_values(&[&winning.name]) + .inc_by(unsettled.len() as u64); + } } diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs index cf17d547fb..77046a684e 100644 --- a/crates/database/src/lib.rs +++ b/crates/database/src/lib.rs @@ -44,10 +44,9 @@ use { pub type PgTransaction<'a> = sqlx::Transaction<'a, sqlx::Postgres>; -/// The names of all tables we use in the db. -pub const ALL_TABLES: &[&str] = &[ +/// The names of tables we use in the db. +pub const TABLES: &[&str] = &[ "orders", - "order_events", "trades", "invalidations", "quotes", @@ -69,10 +68,17 @@ pub const ALL_TABLES: &[&str] = &[ "app_data", ]; +/// The names of potentially big volume tables we use in the db. +pub const LARGE_TABLES: &[&str] = &["order_events"]; + +pub fn all_tables() -> impl Iterator { + TABLES.iter().copied().chain(LARGE_TABLES.iter().copied()) +} + /// Delete all data in the database. Only used by tests. #[allow(non_snake_case)] pub async fn clear_DANGER_(ex: &mut PgTransaction<'_>) -> sqlx::Result<()> { - for table in ALL_TABLES { + for table in all_tables() { ex.execute(format!("TRUNCATE {table};").as_str()).await?; } Ok(()) diff --git a/crates/driver/src/domain/competition/solution/settlement.rs b/crates/driver/src/domain/competition/solution/settlement.rs index 10b4e832a3..d71df212b3 100644 --- a/crates/driver/src/domain/competition/solution/settlement.rs +++ b/crates/driver/src/domain/competition/solution/settlement.rs @@ -310,8 +310,18 @@ impl Settlement { .fold(Default::default(), |mut acc, solution| { for trade in solution.user_trades() { let order = acc.entry(trade.order().uid).or_default(); - order.sell = trade.sell_amount(&solution.prices).unwrap_or_default(); - order.buy = trade.buy_amount(&solution.prices).unwrap_or_default(); + order.sell = trade.sell_amount(&solution.prices, solution.weth).unwrap_or_else(|| { + // This should never happen, returning 0 is better than panicking, but we + // should still alert. + tracing::error!(uid = ?trade.order().uid, "could not compute sell_amount"); + 0.into() + }); + order.buy = trade.buy_amount(&solution.prices, solution.weth).unwrap_or_else(|| { + // This should never happen, returning 0 is better than panicking, but we + // should still alert. + tracing::error!(uid = ?trade.order().uid, "could not compute buy_amount"); + 0.into() + }); } acc }) diff --git a/crates/driver/src/domain/competition/solution/trade.rs b/crates/driver/src/domain/competition/solution/trade.rs index 67038e6299..ac4d1c4f9f 100644 --- a/crates/driver/src/domain/competition/solution/trade.rs +++ b/crates/driver/src/domain/competition/solution/trade.rs @@ -92,14 +92,15 @@ impl Fulfillment { pub fn sell_amount( &self, prices: &HashMap, + weth: eth::WethAddress, ) -> Option { let before_fee = match self.order.side { order::Side::Sell => self.executed.0, order::Side::Buy => self .executed .0 - .checked_mul(*prices.get(&self.order.buy.token)?)? - .checked_div(*prices.get(&self.order.sell.token)?)?, + .checked_mul(*prices.get(&self.order.buy.token.wrap(weth))?)? + .checked_div(*prices.get(&self.order.sell.token.wrap(weth))?)?, }; Some(eth::TokenAmount( before_fee.checked_add(self.solver_fee().0)?, @@ -110,14 +111,15 @@ impl Fulfillment { pub fn buy_amount( &self, prices: &HashMap, + weth: eth::WethAddress, ) -> Option { let amount = match self.order.side { order::Side::Buy => self.executed.0, order::Side::Sell => self .executed .0 - .checked_mul(*prices.get(&self.order.sell.token)?)? - .checked_div(*prices.get(&self.order.buy.token)?)?, + .checked_mul(*prices.get(&self.order.sell.token.wrap(weth))?)? + .checked_div(*prices.get(&self.order.buy.token.wrap(weth))?)?, }; Some(eth::TokenAmount(amount)) } diff --git a/crates/driver/src/infra/api/routes/solve/mod.rs b/crates/driver/src/infra/api/routes/solve/mod.rs index 997995f5cb..07fc1916fa 100644 --- a/crates/driver/src/infra/api/routes/solve/mod.rs +++ b/crates/driver/src/infra/api/routes/solve/mod.rs @@ -30,7 +30,7 @@ async fn route( .tap_err(|err| { observe::invalid_dto(err, "auction"); })?; - tracing::debug!(elapsed=?start.elapsed(), auction_id=%auction_id, "auction task execution time"); + tracing::debug!(elapsed = ?start.elapsed(), "auction task execution time"); let auction = state.pre_processor().prioritize(auction).await; let competition = state.competition(); let result = competition.solve(&auction).await; diff --git a/crates/driver/src/infra/observe/metrics.rs b/crates/driver/src/infra/observe/metrics.rs index bf2f957508..330e250867 100644 --- a/crates/driver/src/infra/observe/metrics.rs +++ b/crates/driver/src/infra/observe/metrics.rs @@ -16,6 +16,9 @@ pub struct Metrics { /// The results of the quoting process. #[metric(labels("solver", "result"))] pub quotes: prometheus::IntCounterVec, + /// The results of the mempool submission. + #[metric(labels("mempool", "result"))] + pub mempool_submission: prometheus::IntCounterVec, } /// Setup the metrics registry. diff --git a/crates/driver/src/infra/observe/mod.rs b/crates/driver/src/infra/observe/mod.rs index 9b0d353293..b18e29c4e9 100644 --- a/crates/driver/src/infra/observe/mod.rs +++ b/crates/driver/src/infra/observe/mod.rs @@ -333,6 +333,15 @@ pub fn mempool_executed( ); } } + let result = match res { + Ok(_) => "Success", + Err(mempools::Error::Revert(_) | mempools::Error::SimulationRevert) => "Revert", + Err(mempools::Error::Other(_)) => "Other", + }; + metrics::get() + .mempool_submission + .with_label_values(&[&mempool.to_string(), result]) + .inc(); } /// Observe that an invalid DTO was received. diff --git a/crates/driver/src/infra/tokens.rs b/crates/driver/src/infra/tokens.rs index f255943bf6..946c7319b6 100644 --- a/crates/driver/src/infra/tokens.rs +++ b/crates/driver/src/infra/tokens.rs @@ -3,10 +3,14 @@ use { domain::eth, infra::{blockchain, Ethereum}, }, + anyhow::Result, ethrpc::current_block::{self, CurrentBlockStream}, - futures::StreamExt, + futures::{FutureExt, StreamExt}, + itertools::Itertools, + model::order::BUY_ETH_ADDRESS, + shared::request_sharing::BoxRequestSharing, std::{ - collections::{HashMap, HashSet}, + collections::HashMap, sync::{Arc, RwLock}, }, tracing::Instrument, @@ -29,6 +33,7 @@ impl Fetcher { let inner = Arc::new(Inner { eth, cache: RwLock::new(HashMap::new()), + requests: BoxRequestSharing::labelled("token_info".into()), }); tokio::task::spawn( update_task(block_stream, Arc::downgrade(&inner)) @@ -70,10 +75,6 @@ async fn update_balances(inner: Arc) -> Result<(), blockchain::Error> { let futures = { let cache = inner.cache.read().unwrap(); let tokens = cache.keys().cloned().collect::>(); - tracing::debug!( - tokens = tokens.len(), - "updating settlement contract balances" - ); tokens.into_iter().map(|token| { let erc20 = inner.eth.erc20(token); async move { @@ -85,6 +86,11 @@ async fn update_balances(inner: Arc) -> Result<(), blockchain::Error> { }) }; + tracing::debug!( + tokens = futures.len(), + "updating settlement contract balances" + ); + // Don't hold on to the lock while fetching balances to allow concurrent // updates. This may lead to new entries arriving in the meantime, however // their balances should already be up-to-date. @@ -93,14 +99,22 @@ async fn update_balances(inner: Arc) -> Result<(), blockchain::Error> { .into_iter() .collect::>(); - let mut cache = inner.cache.write().unwrap(); - for (key, entry) in cache.iter_mut() { - if let Some(balance) = balances.remove(key) { - entry.balance = balance; - } else { - tracing::info!(?key, "key without balance update"); + let mut keys_without_balances = vec![]; + { + let mut cache = inner.cache.write().unwrap(); + for (key, entry) in cache.iter_mut() { + if let Some(balance) = balances.remove(key) { + entry.balance = balance; + } else { + // Avoid logging while holding the exclusive lock. + keys_without_balances.push(*key); + } } } + if !keys_without_balances.is_empty() { + tracing::info!(keys = ?keys_without_balances, "updated keys without balance"); + } + Ok(()) } @@ -108,60 +122,88 @@ async fn update_balances(inner: Arc) -> Result<(), blockchain::Error> { struct Inner { eth: Ethereum, cache: RwLock>, + requests: BoxRequestSharing>, } impl Inner { /// Fetches `Metadata` of the requested tokens from a node. async fn fetch_token_infos( &self, - tokens: HashSet, - ) -> Vec> { + tokens: &[eth::TokenAddress], + ) -> Vec> { let settlement = self.eth.contracts().settlement().address().into(); - let futures = tokens.into_iter().map(|token| async move { - let token = self.eth.erc20(token); - // Use `try_join` because these calls get batched under the hood - // so if one of them fails the others will as well. - // Also this way we won't get incomplete data for a token. - let (decimals, symbol, balance) = futures::future::try_join3( - token.decimals(), - token.symbol(), - token.balance(settlement), - ) - .await?; - Ok(( - token.address(), - Metadata { - decimals, - symbol, - balance, - }, - )) + let futures = tokens.iter().map(|token| { + let build_request = |token: ð::TokenAddress| { + let token = self.eth.erc20(*token); + async move { + // Use `try_join` because these calls get batched under the hood + // so if one of them fails the others will as well. + // Also this way we won't get incomplete data for a token. + let (decimals, symbol, balance) = futures::future::try_join3( + token.decimals(), + token.symbol(), + token.balance(settlement), + ) + .await + .ok()?; + + Some(( + token.address(), + Metadata { + decimals, + symbol, + balance, + }, + )) + } + .boxed() + }; + + self.requests.shared_or_else(*token, build_request) }); futures::future::join_all(futures).await } + /// Ensures that all the missing tokens are in the cache afterwards while + /// taking into account that the function might be called multiple times + /// for the same tokens. + async fn cache_missing_tokens(&self, tokens: &[eth::TokenAddress]) { + if tokens.is_empty() { + return; + } + + let fetched = self.fetch_token_infos(tokens).await; + { + let cache = self.cache.read().unwrap(); + if tokens.iter().all(|token| cache.contains_key(token)) { + // Often multiple callers are racing to fetch the same Metadata. + // If somebody else already cached the data we don't want to take an + // exclusive lock for nothing. + return; + } + } + self.cache + .write() + .unwrap() + .extend(fetched.into_iter().flatten()); + } + async fn get(&self, addresses: &[eth::TokenAddress]) -> HashMap { - let to_fetch: HashSet<_> = { + let to_fetch: Vec<_> = { let cache = self.cache.read().unwrap(); // Compute set of requested addresses that are not in cache. addresses .iter() - .filter(|address| !cache.contains_key(*address)) + // BUY_ETH_ADDRESS is just a marker and not a real address. We'll never be able to + // fetch data for it so ignore it to avoid taking exclusive locks all the time. + .filter(|address| !cache.contains_key(*address) && address.0.0 != BUY_ETH_ADDRESS) .cloned() + .unique() .collect() }; - // Fetch token infos not yet in cache. - if !to_fetch.is_empty() { - let fetched = self.fetch_token_infos(to_fetch).await; - - // Add valid token infos to cache. - self.cache - .write() - .unwrap() - .extend(fetched.into_iter().flatten()); - }; + self.cache_missing_tokens(&to_fetch).await; let cache = self.cache.read().unwrap(); // Return token infos from the cache. diff --git a/crates/driver/src/tests/cases/buy_eth.rs b/crates/driver/src/tests/cases/buy_eth.rs index e1314a82d6..a3541c91f9 100644 --- a/crates/driver/src/tests/cases/buy_eth.rs +++ b/crates/driver/src/tests/cases/buy_eth.rs @@ -14,6 +14,6 @@ async fn test() { .done() .await; - test.solve().await.ok(); + test.solve().await.ok().orders(&[eth_order().name]); test.settle().await.ok().await.eth_order_executed().await; } diff --git a/crates/driver/src/tests/setup/mod.rs b/crates/driver/src/tests/setup/mod.rs index 6078a396c3..3df34c8579 100644 --- a/crates/driver/src/tests/setup/mod.rs +++ b/crates/driver/src/tests/setup/mod.rs @@ -24,7 +24,6 @@ use { }, ethcontract::BlockId, hyper::StatusCode, - itertools::Itertools, secp256k1::SecretKey, serde_with::serde_as, std::{ @@ -823,35 +822,34 @@ impl<'a> SolveOk<'a> { /// Check that the solution contains the expected orders. pub fn orders(self, order_names: &[&str]) -> Self { - let expected_order_uids = order_names - .iter() - .map(|name| { - self.fulfillments - .iter() - .find(|f| f.quoted_order.order.name == *name) - .unwrap_or_else(|| { - panic!( - "unexpected orders {order_names:?}: fulfillment not found in {:?}", - self.fulfillments, - ) - }) - .quoted_order - .order_uid(self.blockchain) - .to_string() - }) - .sorted() - .collect_vec(); let solution = self.solution(); assert!(solution.get("orders").is_some()); - let order_uids = serde_json::from_value::>( + let trades = serde_json::from_value::>( solution.get("orders").unwrap().clone(), ) - .unwrap() - .keys() - .cloned() - .sorted() - .collect_vec(); - assert_eq!(order_uids, expected_order_uids); + .unwrap(); + + for expected in order_names.iter().map(|name| { + self.fulfillments + .iter() + .find(|f| f.quoted_order.order.name == *name) + .unwrap_or_else(|| { + panic!( + "unexpected orders {order_names:?}: fulfillment not found in {:?}", + self.fulfillments, + ) + }) + }) { + let uid = expected.quoted_order.order_uid(self.blockchain); + let trade = trades + .get(&uid.to_string()) + .expect("Didn't find expected trade in solution"); + let u256 = |value: &serde_json::Value| { + eth::U256::from_dec_str(value.as_str().unwrap()).unwrap() + }; + assert!(u256(trade.get("buyAmount").unwrap()) == expected.quoted_order.buy); + assert!(u256(trade.get("sellAmount").unwrap()) == expected.quoted_order.sell); + } self } } diff --git a/crates/shared/src/arguments.rs b/crates/shared/src/arguments.rs index 9dc63df69e..059ba21d5f 100644 --- a/crates/shared/src/arguments.rs +++ b/crates/shared/src/arguments.rs @@ -177,7 +177,6 @@ pub struct Arguments { /// a previous one fails. Individual estimators support different /// networks. `EthGasStation`: supports mainnet. /// `GasNow`: supports mainnet. - /// `GnosisSafe`: supports mainnet and goerli. /// `Web3`: supports every network. /// `Native`: supports every network. #[clap( diff --git a/crates/shared/src/gas_price_estimation.rs b/crates/shared/src/gas_price_estimation.rs index 242a5bf25f..8649f8a09c 100644 --- a/crates/shared/src/gas_price_estimation.rs +++ b/crates/shared/src/gas_price_estimation.rs @@ -8,7 +8,6 @@ use { GasNowGasStation, GasPrice1559, GasPriceEstimating, - GnosisSafeGasStation, PriorityGasPriceEstimating, Transport, }, @@ -22,7 +21,6 @@ use { pub enum GasEstimatorType { EthGasStation, GasNow, - GnosisSafe, Web3, BlockNative, Native, @@ -92,9 +90,6 @@ pub async fn create_priority_estimator( ensure!(is_mainnet(&network_id), "GasNow only supports mainnet"); estimators.push(Box::new(GasNowGasStation::new(client()))) } - GasEstimatorType::GnosisSafe => estimators.push(Box::new( - GnosisSafeGasStation::with_network_id(&network_id, client())?, - )), GasEstimatorType::Web3 => estimators.push(Box::new(web3.clone())), GasEstimatorType::Native => { match NativeGasEstimator::new(web3.transport().clone(), None).await { diff --git a/crates/shared/src/network.rs b/crates/shared/src/network.rs index 4e846d6087..7b4e650b61 100644 --- a/crates/shared/src/network.rs +++ b/crates/shared/src/network.rs @@ -1,162 +1,17 @@ use std::time::Duration; /// Maps (NetworkId, ChainId) to the network name. -/// Contents of the "match" block obtained via: -/// wget -O - -o /dev/null https://chainid.network/chains.json | jq -r '.[] | [.networkId, .chainId, .name] | @tsv' | gawk '{print("(\""$1"\", "$2") => \""$3"\",")}' +/// If the output is from a known network, it represents the canonical name of +/// the network on CoW Protocol. pub fn network_name(network_id: &str, chain_id: u64) -> &'static str { + // You can find a list of available networks by network and chain id here: + // https://chainid.network/chains.json match (network_id, chain_id) { ("1", 1) => "Ethereum / Mainnet", - ("10", 10) => "Optimistic", - ("100", 100) => "xDAI", - ("10000", 10000) => "Smart", - ("10001", 10001) => "Smart", - ("1001", 1001) => "Klaytn", - ("1007", 1007) => "Newton", - ("1", 101) => "EtherInc", - ("1010", 1010) => "Evrice", - ("1012", 1012) => "Newton", - ("102", 102) => "Web3Games", - ("1023", 1023) => "Clover", - ("1024", 1024) => "Clover", - ("108", 108) => "ThunderCore", - ("11", 11) => "Metadium", - ("1122334455", 1122334455) => "IPOS", - ("1139", 1139) => "MathChain", - ("1140", 1140) => "MathChain", - ("12", 12) => "Metadium", - ("122", 122) => "Fuse", - ("128", 128) => "Huobi", - ("1284", 1284) => "Moonbeam", - ("1285", 1285) => "Moonriver", - ("1286", 1286) => "Moonrock", - ("1287", 1287) => "Moonbeam", - ("13", 13) => "Diode", - ("1313114", 1313114) => "Ether-1", - ("1313161554", 1313161554) => "NEAR", - ("1313161555", 1313161555) => "NEAR", - ("1313161556", 1313161556) => "NEAR", - ("1313500", 1313500) => "Xerom", - ("13371337", 13371337) => "PepChain", - ("137", 137) => "Matic", - ("14", 14) => "Flare", - ("15", 15) => "Diode", - ("16", 16) => "Flare", - ("162", 162) => "Lightstreams", - ("11235813", 1620) => "Atheios", - ("163", 163) => "Lightstreams", - ("1666600000", 1666600000) => "Harmony", - ("1666600001", 1666600001) => "Harmony", - ("1666600002", 1666600002) => "Harmony", - ("1666600003", 1666600003) => "Harmony", - ("1666700000", 1666700000) => "Harmony", - ("1666700001", 1666700001) => "Harmony", - ("1666700002", 1666700002) => "Harmony", - ("1666700003", 1666700003) => "Harmony", - ("17", 17) => "ThaiChain", - ("170", 170) => "HOO", - ("18", 18) => "ThunderCore", - ("18289463", 18289463) => "IOLite", - ("1", 1856) => "Teslafunds", - ("1987", 1987) => "EtherGem", - ("1", 2) => "Expanse", - ("20", 20) => "ELA-ETH-Sidechain", - ("200625", 200625) => "Akroma", - ("2020", 2020) => "420coin", - ("2021", 2021) => "Edgeware", - ("2022", 2022) => "Beresheet", - ("21", 21) => "ELA-ETH-Sidechain", - ("0", 211) => "Freight", - ("22", 22) => "ELA-DID-Sidechain", - ("23", 23) => "ELA-DID-Sidechain", - ("37129", 24484) => "Webchain", - ("246", 246) => "Energy", - ("246529", 246529) => "ARTIS", - ("246785", 246785) => "ARTIS", - ("37480", 24734) => "MintMe.com", - ("250", 250) => "Fantom", - ("256", 256) => "Huobi", - ("100", 269) => "High", - ("28945486", 28945486) => "Auxilium", - ("3", 3) => "Ethereum / Ropsten", - ("30", 30) => "RSK", - ("31", 31) => "RSK", - ("1", 31102) => "Ethersocial", - ("3125659152", 3125659152) => "Pirl", - ("322", 322) => "KuCoin", - ("32659", 32659) => "Fusion", - ("33", 33) => "GoodData", - ("35", 35) => "TBWG", - ("35855456", 35855456) => "Joys", - ("38", 38) => "Valorbit", - ("385", 385) => "Lisinski", - ("39797", 39797) => "Energi", - ("4", 4) => "Ethereum / Rinkeby", - ("40", 40) => "Telos", - ("41", 41) => "Telos", - ("42", 42) => "Ethereum / Kovan", - ("420", 420) => "Optimistic", - ("42069", 42069) => "pegglecoin", - ("42220", 42220) => "Celo", - ("43", 43) => "Darwinia", - ("43110", 43110) => "Athereum", - ("1", 43113) => "Avalanche", - ("1", 43114) => "Avalanche", - ("44", 44) => "Darwinia", - ("44787", 44787) => "Celo", - ("4689", 4689) => "IoTeX", - ("4690", 4690) => "IoTeX", - ("49797", 49797) => "Energi", - ("499", 499) => "Rupaya", ("5", 5) => "Ethereum / Goerli", - ("50", 50) => "XinFin", - ("51", 51) => "XinFin", - ("52", 52) => "CoinEx", - ("53", 53) => "CoinEx", - ("558", 558) => "Tao", - ("56", 56) => "Binance", - ("5869", 5869) => "Wegochain", - ("595", 595) => "Acala", - ("6", 6) => "Ethereum Classic / Kotti", - ("60", 60) => "GoChain", - ("1", 61) => "Ethereum Classic / Mainnet", - ("61717561", 61717561) => "Aquachain", - ("2", 62) => "Ethereum Classic / Morden", - ("62320", 62320) => "Celo", - ("7", 63) => "Ethereum Classic / Mordor", - ("64", 64) => "Ellaism", - ("65", 65) => "OKExChain", - ("66", 66) => "OKExChain", - ("67", 67) => "DBChain", - ("68", 68) => "SoterOne", - ("686", 686) => "Karura", - ("69", 69) => "Optimistic", - ("7", 7) => "ThaiChain", - ("73799", 73799) => "Energy", - ("76", 76) => "Mix", - ("77", 77) => "POA", - ("7762959", 7762959) => "Musicoin", - ("777", 777) => "Ethermint", - ("78", 78) => "PrimusChain", - ("78110", 78110) => "Firenze", - ("787", 787) => "Acala", - ("88", 8) => "Ubiq", - ("80001", 80001) => "Matic", - ("8029", 8029) => "MDGL", - ("82", 82) => "Meter", - ("1", 820) => "Callisto", - ("2", 821) => "Callisto", - ("8217", 8217) => "Klaytn", - ("8285", 8285) => "KorthoTest", - ("88", 88) => "TomoChain", - ("888", 888) => "Wanchain", - ("8995", 8995) => "bloxberg", - ("2", 9) => "Ubiq", - ("97", 97) => "Binance", - ("977", 977) => "Nepal", - ("99", 99) => "POA", - ("99415706", 99415706) => "Joys", - ("999", 999) => "Wanchain", - _ => "", + ("100", 100) => "xDAI", + ("11155111", 11155111) => "Ethereum / Sepolia", + _ => panic!("Unknown network (network_id={network_id}, chain_id={chain_id})"), } } diff --git a/crates/solvers/src/infra/config/dex/file.rs b/crates/solvers/src/infra/config/dex/file.rs index 9f126618da..244954353d 100644 --- a/crates/solvers/src/infra/config/dex/file.rs +++ b/crates/solvers/src/infra/config/dex/file.rs @@ -78,15 +78,15 @@ fn default_smallest_partial_fill() -> eth::U256 { } fn default_back_off_growth_factor() -> f64 { - 1.0 + 2.0 } fn default_min_back_off() -> u64 { - Default::default() + 1 } fn default_max_back_off() -> u64 { - Default::default() + 8 } /// Loads the base solver configuration from a TOML file.