diff --git a/crates/alerter/src/lib.rs b/crates/alerter/src/lib.rs index fe6d412428..76cf64a6b5 100644 --- a/crates/alerter/src/lib.rs +++ b/crates/alerter/src/lib.rs @@ -92,7 +92,7 @@ impl OrderBookApi { // untouched. fn convert_eth_to_weth(token: Address) -> Address { const WETH: Address = address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); - if token.as_slice() == BUY_ETH_ADDRESS.as_bytes() { + if token == BUY_ETH_ADDRESS { WETH } else { token diff --git a/crates/autopilot/src/database/auction_prices.rs b/crates/autopilot/src/database/auction_prices.rs index 7411a8e0f5..19a0ae0145 100644 --- a/crates/autopilot/src/database/auction_prices.rs +++ b/crates/autopilot/src/database/auction_prices.rs @@ -1,13 +1,13 @@ use { super::Postgres, + alloy::primitives::Address, anyhow::Result, bigdecimal::BigDecimal, - primitive_types::H160, std::collections::HashMap, }; impl Postgres { - pub async fn fetch_latest_prices(&self) -> Result> { + pub async fn fetch_latest_prices(&self) -> Result> { let _timer = super::Metrics::get() .database_queries .with_label_values(&["fetch_latest_prices"]) @@ -17,7 +17,7 @@ impl Postgres { Ok(database::auction_prices::fetch_latest_prices(&mut ex) .await? .into_iter() - .map(|auction_price| (H160::from(auction_price.token.0), auction_price.price)) + .map(|auction_price| (Address::new(auction_price.token.0), auction_price.price)) .collect::>()) } } diff --git a/crates/autopilot/src/run.rs b/crates/autopilot/src/run.rs index 1db5c26fa7..72cd5bd12a 100644 --- a/crates/autopilot/src/run.rs +++ b/crates/autopilot/src/run.rs @@ -31,7 +31,7 @@ use { ethcontract::H160, ethrpc::{ Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, + alloy::conversions::IntoLegacy, block_stream::block_number_to_block_number_hash, }, futures::StreamExt, @@ -321,7 +321,7 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { )); let mut allowed_tokens = args.allowed_tokens.clone(); allowed_tokens.extend(base_tokens.tokens().iter()); - allowed_tokens.push(model::order::BUY_ETH_ADDRESS.into_alloy()); + allowed_tokens.push(model::order::BUY_ETH_ADDRESS); let unsupported_tokens = args.unsupported_tokens.clone(); let finder = token_owner_finder::init( @@ -380,16 +380,15 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { web3: web3.clone(), simulation_web3, chain, - settlement: eth.contracts().settlement().address().into_legacy(), - native_token: eth.contracts().weth().address().into_legacy(), + settlement: *eth.contracts().settlement().address(), + native_token: *eth.contracts().weth().address(), authenticator: eth .contracts() .settlement() .authenticator() .call() .await - .expect("failed to query solver authenticator address") - .into_legacy(), + .expect("failed to query solver authenticator address"), base_tokens: base_tokens.clone(), block_stream: eth.current_block().clone(), }, @@ -528,14 +527,14 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { bad_token_detector.clone(), native_price_estimator.clone(), signature_validator.clone(), - eth.contracts().weth().address().into_legacy(), + *eth.contracts().weth().address(), args.limit_order_price_factor .try_into() .expect("limit order price factor can't be converted to BigDecimal"), domain::ProtocolFees::new(&args.fee_policies_config), cow_amm_registry.clone(), args.run_loop_native_price_timeout, - eth.contracts().settlement().address().into_legacy(), + *eth.contracts().settlement().address(), args.disable_order_balance_filter, args.disable_1271_order_sig_filter, args.disable_1271_order_balance_filter, diff --git a/crates/autopilot/src/solvable_orders.rs b/crates/autopilot/src/solvable_orders.rs index 835c875ac0..2710551d1a 100644 --- a/crates/autopilot/src/solvable_orders.rs +++ b/crates/autopilot/src/solvable_orders.rs @@ -18,7 +18,7 @@ use { time::now_in_epoch_seconds, }, number::conversions::alloy::u256_to_big_decimal, - primitive_types::{H160, H256, U256}, + primitive_types::{H256, U256}, prometheus::{Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec}, shared::{ account_balances::{BalanceFetching, Query}, @@ -96,12 +96,12 @@ pub struct SolvableOrdersCache { native_price_estimator: Arc, signature_validator: Arc, metrics: &'static Metrics, - weth: H160, + weth: Address, limit_order_price_factor: BigDecimal, protocol_fees: domain::ProtocolFees, cow_amm_registry: cow_amm::Registry, native_price_timeout: Duration, - settlement_contract: H160, + settlement_contract: Address, disable_order_balance_filter: bool, disable_1271_order_sig_filter: bool, disable_1271_order_balance_filter: bool, @@ -124,12 +124,12 @@ impl SolvableOrdersCache { bad_token_detector: Arc, native_price_estimator: Arc, signature_validator: Arc, - weth: H160, + weth: Address, limit_order_price_factor: BigDecimal, protocol_fees: domain::ProtocolFees, cow_amm_registry: cow_amm::Registry, native_price_timeout: Duration, - settlement_contract: H160, + settlement_contract: Address, disable_order_balance_filter: bool, disable_1271_order_sig_filter: bool, disable_1271_order_balance_filter: bool, @@ -204,7 +204,7 @@ impl SolvableOrdersCache { let orders = orders_with_balance( orders, &balances, - self.settlement_contract.into_alloy(), + self.settlement_contract, self.disable_1271_order_balance_filter, ); let removed = counter.checkpoint("insufficient_balance", &orders); @@ -219,7 +219,7 @@ impl SolvableOrdersCache { let cow_amm_tokens = cow_amms .iter() - .flat_map(|cow_amm| cow_amm.traded_tokens().iter().map(|t| t.into_legacy())) + .flat_map(|cow_amm| cow_amm.traded_tokens().iter().copied()) .collect::>(); // create auction @@ -242,7 +242,7 @@ impl SolvableOrdersCache { .timed_future( "weth_price_fetch", self.native_price_estimator - .estimate_native_price(self.weth.into_alloy(), Default::default()), + .estimate_native_price(self.weth, Default::default()), ) .await .expect("weth price fetching can never fail"); @@ -281,7 +281,7 @@ impl SolvableOrdersCache { .iter() .filter(|cow_amm| { cow_amm.traded_tokens().iter().all(|token| { - let price_exist = prices.contains_key(&token.into_legacy()); + let price_exist = prices.contains_key(token); if !price_exist { tracing::debug!( cow_amm = ?cow_amm.address(), @@ -310,7 +310,8 @@ impl SolvableOrdersCache { prices: prices .into_iter() .map(|(key, value)| { - Price::try_new(value.into()).map(|price| (eth::TokenAddress(key), price)) + Price::try_new(value.into_legacy().into()) + .map(|price| (eth::TokenAddress(key.into_legacy()), price)) }) .collect::>()?, surplus_capturing_jit_order_owners, @@ -471,10 +472,10 @@ async fn find_banned_user_orders(orders: &[Order], banned_users: &banned::Users) } async fn get_native_prices( - tokens: &[H160], + tokens: &[Address], native_price_estimator: &CachingNativePriceEstimator, timeout: Duration, -) -> BTreeMap { +) -> BTreeMap { native_price_estimator .estimate_native_prices_with_timeout(tokens, timeout) .await @@ -619,17 +620,12 @@ async fn get_orders_with_native_prices( orders: Vec, native_price_estimator: &CachingNativePriceEstimator, metrics: &Metrics, - additional_tokens: impl IntoIterator, + additional_tokens: impl IntoIterator, timeout: Duration, -) -> (Vec, BTreeMap) { +) -> (Vec, BTreeMap) { let traded_tokens = orders .iter() - .flat_map(|order| { - [ - order.data.sell_token.into_legacy(), - order.data.buy_token.into_legacy(), - ] - }) + .flat_map(|order| [order.data.sell_token, order.data.buy_token]) .chain(additional_tokens) .collect::>(); @@ -644,7 +640,7 @@ async fn get_orders_with_native_prices( let mut filtered_market_orders = 0_i64; let (usable, filtered): (Vec<_>, Vec<_>) = orders.into_iter().partition(|order| { let (t0, t1) = (&order.data.sell_token, &order.data.buy_token); - match (prices.get(&t0.into_legacy()), prices.get(&t1.into_legacy())) { + match (prices.get(t0), prices.get(t1)) { (Some(_), Some(_)) => true, _ => { filtered_market_orders += i64::from(order.metadata.class == OrderClass::Market); @@ -670,7 +666,7 @@ async fn get_orders_with_native_prices( /// For the remaining orders we prioritize token prices that are needed the most /// often. That way we have the chance to make a majority of orders solvable /// with very few fetch requests. -fn prioritize_missing_prices(mut orders: Vec) -> IndexSet { +fn prioritize_missing_prices(mut orders: Vec) -> IndexSet
{ /// How old an order can be at most to be considered a market order. const MARKET_ORDER_AGE: chrono::Duration = chrono::Duration::minutes(30); let now = chrono::Utc::now(); @@ -679,10 +675,10 @@ fn prioritize_missing_prices(mut orders: Vec) -> IndexSet { orders.sort_by_key(|o| std::cmp::Reverse(o.metadata.creation_date)); let mut high_priority_tokens = IndexSet::new(); - let mut most_used_tokens = HashMap::::new(); + let mut most_used_tokens = HashMap::::new(); for order in orders { - let sell_token = order.data.sell_token.into_legacy(); - let buy_token = order.data.buy_token.into_legacy(); + let sell_token = order.data.sell_token; + let buy_token = order.data.buy_token; let is_market = now.signed_duration_since(order.metadata.creation_date) <= MARKET_ORDER_AGE; if is_market { @@ -754,7 +750,7 @@ async fn find_unsupported_tokens( /// token price. fn filter_mispriced_limit_orders( mut orders: Vec, - prices: &BTreeMap, + prices: &BTreeMap, price_factor: &BigDecimal, ) -> Vec { orders.retain(|order| { @@ -762,14 +758,8 @@ fn filter_mispriced_limit_orders( return true; } - let sell_price = prices - .get(&order.data.sell_token.into_legacy()) - .unwrap() - .into_alloy(); - let buy_price = prices - .get(&order.data.buy_token.into_legacy()) - .unwrap() - .into_alloy(); + let sell_price = *prices.get(&order.data.sell_token).unwrap(); + let buy_price = *prices.get(&order.data.buy_token).unwrap(); // Convert the sell and buy price to the native token (ETH) and make sure that // sell is higher than buy with the configurable price factor. @@ -993,8 +983,8 @@ mod tests { assert_eq!( prices, btreemap! { - token1.into_legacy() => U256::from(2_000_000_000_000_000_000_u128), - token3.into_legacy() => U256::from(250_000_000_000_000_000_u128), + token1 => alloy::primitives::U256::from(2_000_000_000_000_000_000_u128), + token3 => alloy::primitives::U256::from(250_000_000_000_000_000_u128), } ); } @@ -1079,7 +1069,7 @@ mod tests { orders.clone(), &native_price_estimator, metrics, - vec![token5.into_legacy()], + vec![token5], Duration::ZERO, ) .await; @@ -1094,7 +1084,7 @@ mod tests { orders.clone(), &native_price_estimator, metrics, - vec![token5.into_legacy()], + vec![token5], Duration::ZERO, ) .await; @@ -1103,9 +1093,9 @@ mod tests { assert_eq!( prices, btreemap! { - token1.into_legacy() => U256::from(2_000_000_000_000_000_000_u128), - token3.into_legacy() => U256::from(250_000_000_000_000_000_u128), - token5.into_legacy() => U256::from(5_000_000_000_000_000_000_u128), + token1 => alloy::primitives::U256::from(2_000_000_000_000_000_000_u128), + token3 => alloy::primitives::U256::from(250_000_000_000_000_000_u128), + token5 => alloy::primitives::U256::from(5_000_000_000_000_000_000_u128), } ); } @@ -1116,8 +1106,8 @@ mod tests { let token2 = Address::repeat_byte(2); let token3 = Address::repeat_byte(3); - let token_approx1 = H160([4; 20]); - let token_approx2 = H160([5; 20]); + let token_approx1 = Address::repeat_byte(4); + let token_approx2 = Address::repeat_byte(5); let orders = vec![ OrderBuilder::default() @@ -1149,12 +1139,12 @@ mod tests { native_price_estimator .expect_estimate_native_price() .times(1) - .withf(move |token, _| *token == token_approx1.into_alloy()) + .withf(move |token, _| *token == token_approx1) .returning(|_, _| async { Ok(40.) }.boxed()); native_price_estimator .expect_estimate_native_price() .times(1) - .withf(move |token, _| *token == token_approx2.into_alloy()) + .withf(move |token, _| *token == token_approx2) .returning(|_, _| async { Ok(50.) }.boxed()); let native_price_estimator = CachingNativePriceEstimator::new( @@ -1165,10 +1155,7 @@ mod tests { Default::default(), 3, // Set to use native price approximations for the following tokens - HashMap::from([ - (token1.into_legacy(), token_approx1), - (token2.into_legacy(), token_approx2), - ]), + HashMap::from([(token1, token_approx1), (token2, token_approx2)]), HEALTHY_PRICE_ESTIMATION_TIME, ); let metrics = Metrics::instance(observe::metrics::get_storage_registry()).unwrap(); @@ -1185,9 +1172,9 @@ mod tests { assert_eq!( prices, btreemap! { - token1.into_legacy() => U256::from(40_000_000_000_000_000_000_u128), - token2.into_legacy() => U256::from(50_000_000_000_000_000_000_u128), - token3.into_legacy() => U256::from(3_000_000_000_000_000_000_u128), + token1 => alloy::primitives::U256::from(40_000_000_000_000_000_000_u128), + token2 => alloy::primitives::U256::from(50_000_000_000_000_000_000_u128), + token3 => alloy::primitives::U256::from(3_000_000_000_000_000_000_u128), } ); } @@ -1379,22 +1366,22 @@ mod tests { #[test] fn filters_mispriced_orders() { - let sell_token = H160([1; 20]); - let buy_token = H160([2; 20]); + let sell_token = Address::repeat_byte(1); + let buy_token = Address::repeat_byte(2); // Prices are set such that 1 sell token is equivalent to 2 buy tokens. // Additionally, they are scaled to large values to allow for overflows. let prices = btreemap! { - sell_token => U256::MAX / 100, - buy_token => U256::MAX / 200, + sell_token => alloy::primitives::U256::MAX / alloy::primitives::U256::from(100), + buy_token => alloy::primitives::U256::MAX / alloy::primitives::U256::from(200), }; let price_factor = "0.95".parse().unwrap(); let order = |sell_amount: u8, buy_amount: u8| Order { data: OrderData { - sell_token: sell_token.into_alloy(), + sell_token, sell_amount: alloy::primitives::U256::from(sell_amount), - buy_token: buy_token.into_alloy(), + buy_token, buy_amount: alloy::primitives::U256::from(buy_amount), ..Default::default() }, @@ -1557,7 +1544,6 @@ mod tests { #[test] fn prioritizes_missing_prices() { let now = chrono::Utc::now(); - let token = H160::from_low_u64_be; let order = |sell_token, buy_token, age| Order { metadata: OrderMetadata { @@ -1583,12 +1569,12 @@ mod tests { ]; let result = prioritize_missing_prices(orders); assert!(result.into_iter().eq([ - token(1), // coming from youngest market order - token(3), // coming from youngest market order - token(2), // coming from older market order - token(6), // coming from limit order (part of 3 orders) - token(4), // coming from limit order (part of 2 orders) - token(5), // coming from limit order (part of 1 orders) + Address::with_last_byte(1), // coming from youngest market order + Address::with_last_byte(3), // coming from youngest market order + Address::with_last_byte(2), // coming from older market order + Address::with_last_byte(6), // coming from limit order (part of 3 orders) + Address::with_last_byte(4), // coming from limit order (part of 2 orders) + Address::with_last_byte(5), // coming from limit order (part of 1 orders) ])); } } diff --git a/crates/driver/src/domain/competition/pre_processing.rs b/crates/driver/src/domain/competition/pre_processing.rs index 15bb8d3e8a..1630051ee8 100644 --- a/crates/driver/src/domain/competition/pre_processing.rs +++ b/crates/driver/src/domain/competition/pre_processing.rs @@ -273,8 +273,8 @@ impl Utilities { && order.app_data.flashloan() == first.app_data.flashloan() }); Query { - owner: trader.0.0, - token: token.0.0, + owner: trader.0.0.into_alloy(), + token: token.0.0.into_alloy(), source: match source { SellTokenBalance::Erc20 => SellTokenSource::Erc20, SellTokenBalance::Internal => SellTokenSource::Internal, @@ -318,8 +318,8 @@ impl Utilities { let balance = balance.ok()?; Some(( ( - order::Trader(query.owner.into()), - query.token.into(), + order::Trader(query.owner.into_legacy().into()), + query.token.into_legacy().into(), match query.source { SellTokenSource::Erc20 => SellTokenBalance::Erc20, SellTokenSource::Internal => SellTokenBalance::Internal, diff --git a/crates/driver/src/infra/tokens.rs b/crates/driver/src/infra/tokens.rs index cd8eca650b..376b581c46 100644 --- a/crates/driver/src/infra/tokens.rs +++ b/crates/driver/src/infra/tokens.rs @@ -5,7 +5,7 @@ use { }, anyhow::Result, ethrpc::{ - alloy::conversions::IntoLegacy, + alloy::conversions::{IntoAlloy, IntoLegacy}, block_stream::{self, CurrentBlockWatcher}, }, futures::{FutureExt, StreamExt}, @@ -213,7 +213,7 @@ impl Inner { .iter() // 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) + .filter(|address| !cache.contains_key(*address) && address.0.0.into_alloy() != BUY_ETH_ADDRESS) .cloned() .unique() .collect() diff --git a/crates/e2e/tests/e2e/eth_integration.rs b/crates/e2e/tests/e2e/eth_integration.rs index 23b2cdd7f4..3f28cc54ae 100644 --- a/crates/e2e/tests/e2e/eth_integration.rs +++ b/crates/e2e/tests/e2e/eth_integration.rs @@ -77,25 +77,18 @@ async fn eth_integration(web3: Web3) { services.submit_quote(&request).await } }; - quote(*token.address(), BUY_ETH_ADDRESS.into_alloy()) - .await - .unwrap(); + quote(*token.address(), BUY_ETH_ADDRESS).await.unwrap(); // Eth is only supported as the buy token - let (status, body) = quote(BUY_ETH_ADDRESS.into_alloy(), *token.address()) - .await - .unwrap_err(); + let (status, body) = quote(BUY_ETH_ADDRESS, *token.address()).await.unwrap_err(); assert_eq!(status, 400, "{body}"); // Place Orders - assert_ne!( - onchain.contracts().weth.address().into_legacy(), - BUY_ETH_ADDRESS - ); + assert_ne!(*onchain.contracts().weth.address(), BUY_ETH_ADDRESS); let order_buy_eth_a = OrderCreation { kind: OrderKind::Buy, sell_token: token.address().into_legacy(), sell_amount: to_wei(50), - buy_token: BUY_ETH_ADDRESS, + buy_token: BUY_ETH_ADDRESS.into_legacy(), buy_amount: to_wei(49), valid_to: model::time::now_in_epoch_seconds() + 300, ..Default::default() @@ -110,7 +103,7 @@ async fn eth_integration(web3: Web3) { kind: OrderKind::Sell, sell_token: token.address().into_legacy(), sell_amount: to_wei(50), - buy_token: BUY_ETH_ADDRESS, + buy_token: BUY_ETH_ADDRESS.into_legacy(), buy_amount: to_wei(49), valid_to: model::time::now_in_epoch_seconds() + 300, ..Default::default() diff --git a/crates/e2e/tests/e2e/eth_safe.rs b/crates/e2e/tests/e2e/eth_safe.rs index b3569ce341..6987c9567d 100644 --- a/crates/e2e/tests/e2e/eth_safe.rs +++ b/crates/e2e/tests/e2e/eth_safe.rs @@ -71,7 +71,7 @@ async fn test(web3: Web3) { from: Some(safe.address().into_legacy()), sell_token: token.address().into_legacy(), sell_amount: to_wei(4), - buy_token: BUY_ETH_ADDRESS, + buy_token: BUY_ETH_ADDRESS.into_legacy(), buy_amount: to_wei(3), valid_to: model::time::now_in_epoch_seconds() + 300, partially_fillable: true, diff --git a/crates/e2e/tests/e2e/quote_verification.rs b/crates/e2e/tests/e2e/quote_verification.rs index c67e307270..329280e63b 100644 --- a/crates/e2e/tests/e2e/quote_verification.rs +++ b/crates/e2e/tests/e2e/quote_verification.rs @@ -152,8 +152,8 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { Arc::new(web3.clone()), Arc::new(BalanceOverrides::default()), block_stream, - onchain.contracts().gp_settlement.address().into_legacy(), - onchain.contracts().weth.address().into_legacy(), + *onchain.contracts().gp_settlement.address(), + *onchain.contracts().weth.address(), BigDecimal::zero(), Default::default(), ) @@ -166,10 +166,8 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { verifier .verify( &PriceQuery { - sell_token: H160::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599") - .unwrap(), - buy_token: H160::from_str("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") - .unwrap(), + sell_token: address!("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"), + buy_token: address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), kind: OrderKind::Sell, in_amount: NonZeroU256::new(12.into()).unwrap(), }, @@ -199,7 +197,7 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { }; let verified_quote = Estimate { - out_amount: 16380122291179526144u128.into(), + out_amount: U256::from(16380122291179526144u128), gas: 225000, solver: H160::from_str("0xe3067c7c27c1038de4e8ad95a83b927d23dfbd99").unwrap(), verified: true, diff --git a/crates/model/src/order.rs b/crates/model/src/order.rs index 970c50db0f..3f20e87896 100644 --- a/crates/model/src/order.rs +++ b/crates/model/src/order.rs @@ -32,7 +32,7 @@ use { /// The flag denoting that an order is buying ETH (or the chain's native token). /// It is used in place of an actual buy token address in an order. -pub const BUY_ETH_ADDRESS: H160 = H160([0xee; 20]); +pub const BUY_ETH_ADDRESS: Address = Address::repeat_byte(0xee); #[derive(Eq, PartialEq, Clone, Debug, Default, Deserialize, Serialize)] pub struct Interactions { diff --git a/crates/number/src/conversions.rs b/crates/number/src/conversions.rs index feae5770b4..e9327b42c9 100644 --- a/crates/number/src/conversions.rs +++ b/crates/number/src/conversions.rs @@ -63,6 +63,7 @@ pub mod alloy { bigdecimal::{BigDecimal, num_bigint::ToBigInt}, num::{BigInt, BigRational, BigUint, Zero, bigint::Sign}, }; + pub fn big_uint_to_u256(input: &BigUint) -> Result { let bytes = input.to_bytes_be(); ensure!(bytes.len() <= 32, "too large"); diff --git a/crates/orderbook/src/run.rs b/crates/orderbook/src/run.rs index 8baa897800..e5052391f0 100644 --- a/crates/orderbook/src/run.rs +++ b/crates/orderbook/src/run.rs @@ -22,7 +22,7 @@ use { WETH9, support::Balances, }, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethrpc::alloy::conversions::IntoLegacy, futures::{FutureExt, StreamExt}, model::{DomainSeparator, order::BUY_ETH_ADDRESS}, num::ToPrimitive, @@ -230,7 +230,7 @@ pub async fn run(args: Arguments) { )); let mut allowed_tokens = args.allowed_tokens.clone(); allowed_tokens.extend(base_tokens.tokens().iter()); - allowed_tokens.push(BUY_ETH_ADDRESS.into_alloy()); + allowed_tokens.push(BUY_ETH_ADDRESS); let unsupported_tokens = args.unsupported_tokens.clone(); let uniswapv3_factory = IUniswapV3Factory::Instance::deployed(&web3.alloy) @@ -299,14 +299,13 @@ pub async fn run(args: Arguments) { web3: web3.clone(), simulation_web3, chain, - settlement: settlement_contract.address().into_legacy(), - native_token: native_token.address().into_legacy(), + settlement: *settlement_contract.address(), + native_token: *native_token.address(), authenticator: settlement_contract .authenticator() .call() .await - .expect("failed to query solver authenticator address") - .into_legacy(), + .expect("failed to query solver authenticator address"), base_tokens: base_tokens.clone(), block_stream: current_block_stream.clone(), }, @@ -328,13 +327,7 @@ pub async fn run(args: Arguments) { ) .await .unwrap(); - let prices = postgres_write - .fetch_latest_prices() - .await - .unwrap() - .into_iter() - .map(|(k, v)| (k.into_legacy(), v)) - .collect(); + let prices = postgres_write.fetch_latest_prices().await.unwrap(); native_price_estimator.initialize_cache(prices); let price_estimator = price_estimator_factory diff --git a/crates/shared/src/account_balances/cached.rs b/crates/shared/src/account_balances/cached.rs index 4f87854ef0..101d5d0a1e 100644 --- a/crates/shared/src/account_balances/cached.rs +++ b/crates/shared/src/account_balances/cached.rs @@ -202,15 +202,15 @@ mod tests { use { super::*, crate::account_balances::MockBalanceFetching, - ethcontract::H160, + alloy::primitives::Address, ethrpc::block_stream::BlockInfo, model::order::SellTokenSource, }; fn query(token: u8) -> Query { Query { - owner: H160([1; 20]), - token: H160([token; 20]), + owner: Address::repeat_byte(1), + token: Address::repeat_byte(token), source: SellTokenSource::Erc20, interactions: vec![], balance_override: None, diff --git a/crates/shared/src/account_balances/mod.rs b/crates/shared/src/account_balances/mod.rs index 2f8a2be1c1..e61eb89d94 100644 --- a/crates/shared/src/account_balances/mod.rs +++ b/crates/shared/src/account_balances/mod.rs @@ -3,14 +3,13 @@ use { BalanceOverrideRequest, BalanceOverriding, }, - alloy::sol_types::{SolCall, SolType, sol_data}, + alloy::{ + primitives::Address, + sol_types::{SolCall, SolType, sol_data}, + }, contracts::alloy::{GPv2Settlement, support::Balances}, ethcontract::state_overrides::StateOverrides, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, + ethrpc::{Web3, alloy::conversions::IntoAlloy, block_stream::CurrentBlockWatcher}, model::{ interaction::InteractionData, order::{Order, SellTokenSource}, @@ -25,8 +24,8 @@ mod simulation; #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Query { - pub owner: H160, - pub token: H160, + pub owner: Address, + pub token: Address, pub source: SellTokenSource, pub interactions: Vec, pub balance_override: Option, @@ -35,8 +34,8 @@ pub struct Query { impl Query { pub fn from_order(o: &Order) -> Self { Self { - owner: o.metadata.owner.into_legacy(), - token: o.data.sell_token.into_legacy(), + owner: o.metadata.owner, + token: o.data.sell_token, source: o.data.sell_token_balance, interactions: o.interactions.pre.clone(), // TODO eventually delete together with the balance diff --git a/crates/shared/src/account_balances/simulation.rs b/crates/shared/src/account_balances/simulation.rs index e0319989cc..e453ac95af 100644 --- a/crates/shared/src/account_balances/simulation.rs +++ b/crates/shared/src/account_balances/simulation.rs @@ -51,8 +51,8 @@ impl Balances { let simulation = self .balance_simulator .simulate( - query.owner, - query.token, + query.owner.into_legacy(), + query.token.into_legacy(), query.source, &query.interactions, None, @@ -73,9 +73,8 @@ impl Balances { ) -> Result { let usable_balance = match query.source { SellTokenSource::Erc20 => { - let balance = token.balanceOf(query.owner.into_alloy()); - let allowance = - token.allowance(query.owner.into_alloy(), self.vault_relayer().into_alloy()); + let balance = token.balanceOf(query.owner); + let allowance = token.allowance(query.owner, self.vault_relayer().into_alloy()); let (balance, allowance) = futures::try_join!( balance.call().into_future(), allowance.call().into_future() @@ -84,13 +83,10 @@ impl Balances { } SellTokenSource::External => { let vault = BalancerV2Vault::new(self.vault().into_alloy(), &self.web3.alloy); - let balance = token.balanceOf(query.owner.into_alloy()); - let approved = vault.hasApprovedRelayer( - query.owner.into_alloy(), - self.vault_relayer().into_alloy(), - ); - let allowance = - token.allowance(query.owner.into_alloy(), self.vault().into_alloy()); + let balance = token.balanceOf(query.owner); + let approved = + vault.hasApprovedRelayer(query.owner, self.vault_relayer().into_alloy()); + let allowance = token.allowance(query.owner, self.vault().into_alloy()); let (balance, approved, allowance) = futures::try_join!( balance.call().into_future(), approved.call().into_future(), @@ -104,12 +100,9 @@ impl Balances { } SellTokenSource::Internal => { let vault = BalancerV2Vault::new(self.vault().into_alloy(), &self.web3.alloy); - let balance = vault - .getInternalBalance(query.owner.into_alloy(), vec![query.token.into_alloy()]); - let approved = vault.hasApprovedRelayer( - query.owner.into_alloy(), - self.vault_relayer().into_alloy(), - ); + let balance = vault.getInternalBalance(query.owner, vec![query.token]); + let approved = + vault.hasApprovedRelayer(query.owner, self.vault_relayer().into_alloy()); let (balance, approved) = futures::try_join!( balance.call().into_future(), approved.call().into_future() @@ -134,8 +127,7 @@ impl BalanceFetching for Balances { .iter() .map(|query| async { if query.interactions.is_empty() { - let token = - ERC20::Instance::new(query.token.into_alloy(), self.web3.alloy.clone()); + let token = ERC20::Instance::new(query.token, self.web3.alloy.clone()); self.tradable_balance_simple(query, &token).await } else { self.tradable_balance_simulated(query).await @@ -154,8 +146,8 @@ impl BalanceFetching for Balances { let simulation = self .balance_simulator .simulate( - query.owner, - query.token, + query.owner.into_legacy(), + query.token.into_legacy(), query.source, &query.interactions, Some(amount), @@ -221,8 +213,8 @@ mod tests { balances .can_transfer( &Query { - owner, - token, + owner: owner.into_alloy(), + token: token.into_alloy(), source, interactions: vec![], balance_override: None, diff --git a/crates/shared/src/encoded_settlement.rs b/crates/shared/src/encoded_settlement.rs index dc20aac189..6908b3f724 100644 --- a/crates/shared/src/encoded_settlement.rs +++ b/crates/shared/src/encoded_settlement.rs @@ -80,8 +80,8 @@ fn order_flags(order: &OrderData, signature: &Signature) -> U256 { #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct EncodedSettlement { - pub tokens: Vec, - pub clearing_prices: Vec, + pub tokens: Vec
, + pub clearing_prices: Vec, pub trades: Vec, pub interactions: [Vec; 3], } diff --git a/crates/shared/src/external_prices.rs b/crates/shared/src/external_prices.rs index 63da862b19..c9607aa06a 100644 --- a/crates/shared/src/external_prices.rs +++ b/crates/shared/src/external_prices.rs @@ -9,7 +9,6 @@ use { crate::conversions::U256Ext, alloy::primitives::{Address, U256}, anyhow::{Result, bail}, - ethrpc::alloy::conversions::IntoAlloy, model::order::BUY_ETH_ADDRESS, num::{BigInt, BigRational, One as _, ToPrimitive as _}, std::{ @@ -33,7 +32,7 @@ impl ExternalPrices { // wrapped asset price exist with a value of 1. This protects us from // malformed input (in case there are issues with the prices from the // `/auction` endpoint for example). - for token in [native_token, BUY_ETH_ADDRESS.into_alloy()] { + for token in [native_token, BUY_ETH_ADDRESS] { match xrates.get(&token) { Some(price) if !price.is_one() => { let price = price.to_f64().unwrap_or(f64::NAN); @@ -138,7 +137,7 @@ mod tests { hashmap! { Address::repeat_byte(1) => BigRational::new(1.into(), 10.into()), native_token => BigRational::one(), - BUY_ETH_ADDRESS.into_alloy() => BigRational::one(), + BUY_ETH_ADDRESS => BigRational::one(), }, ); } @@ -159,7 +158,7 @@ mod tests { ExternalPrices::try_from_auction_prices( native_token, btreemap! { - BUY_ETH_ADDRESS.into_alloy() => U256::from(13_370_000_000_000_000_000_u128), + BUY_ETH_ADDRESS => U256::from(13_370_000_000_000_000_000_u128), }, ) .is_err() diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 9d7bd35de6..2f63570e5f 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -17,7 +17,7 @@ use { anyhow::{Context, Result}, chrono::{DateTime, Duration, Utc}, database::quotes::{Quote as QuoteRow, QuoteKind}, - ethcontract::{H160, U256}, + ethcontract::U256, ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::TryFutureExt, gas_estimation::GasPriceEstimating, @@ -492,10 +492,10 @@ impl OrderQuoter { } | OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: sell_amount }, - } => (sell_amount.get(), trade_estimate.out_amount), + } => (sell_amount.get().into_alloy(), trade_estimate.out_amount), OrderQuoteSide::Buy { buy_amount_after_fee: buy_amount, - } => (trade_estimate.out_amount, buy_amount.get()), + } => (trade_estimate.out_amount, buy_amount.get().into_alloy()), }; let fee_parameters = FeeParameters { gas_amount: trade_estimate.gas as _, @@ -510,8 +510,8 @@ impl OrderQuoter { let quote = QuoteData { sell_token: parameters.sell_token, buy_token: parameters.buy_token, - quoted_sell_amount: quoted_sell_amount.into_alloy(), - quoted_buy_amount: quoted_buy_amount.into_alloy(), + quoted_sell_amount, + quoted_buy_amount, fee_parameters, kind: trade_query.kind, expiration, @@ -534,7 +534,7 @@ impl OrderQuoter { &self, estimate: &Estimate, parameters: &QuoteParameters, - sell_amount: U256, + sell_amount: alloy::primitives::U256, ) -> Result<(), CalculateQuoteError> { if estimate.verified || !matches!( @@ -547,10 +547,7 @@ impl OrderQuoter { } let balance = match self - .get_balance( - ¶meters.verification, - parameters.sell_token.into_legacy(), - ) + .get_balance(¶meters.verification, parameters.sell_token) .await { Ok(balance) => balance, @@ -569,9 +566,13 @@ impl OrderQuoter { Ok(()) } - async fn get_balance(&self, verification: &Verification, token: H160) -> Result { + async fn get_balance( + &self, + verification: &Verification, + token: Address, + ) -> Result { let query = Query { - owner: verification.from.into_legacy(), + owner: verification.from, token, source: verification.sell_token_source, interactions: verification @@ -587,7 +588,10 @@ impl OrderQuoter { balance_override: None, }; let mut balances = self.balance_fetcher.get_balances(&[query]).await; - balances.pop().context("missing balance result")? + balances + .pop() + .map(|head| head.map(IntoAlloy::into_alloy)) + .context("missing balance result")? } } @@ -694,10 +698,10 @@ impl From<&OrderQuoteRequest> for PreOrderData { fn from(quote_request: &OrderQuoteRequest) -> Self { let owner = quote_request.from; Self { - owner: owner.into_legacy(), - sell_token: quote_request.sell_token.into_legacy(), - buy_token: quote_request.buy_token.into_legacy(), - receiver: quote_request.receiver.unwrap_or(owner).into_legacy(), + owner, + sell_token: quote_request.sell_token, + buy_token: quote_request.buy_token, + receiver: quote_request.receiver.unwrap_or(owner), valid_to: quote_request.validity.actual_valid_to(), partially_fillable: false, buy_token_balance: quote_request.buy_token_balance, @@ -796,7 +800,7 @@ mod tests { native::MockNativePriceEstimating, }, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256 as AlloyU256}, chrono::Utc, ethcontract::H160, futures::FutureExt, @@ -883,7 +887,7 @@ mod tests { .returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 42.into(), + out_amount: AlloyU256::from(42), gas: 3, solver: H160([1; 20]), verified: false, @@ -1024,7 +1028,7 @@ mod tests { .returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 42.into(), + out_amount: AlloyU256::from(42), gas: 3, solver: H160([1; 20]), verified: false, @@ -1160,7 +1164,7 @@ mod tests { .returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 100.into(), + out_amount: AlloyU256::from(100), gas: 3, solver: H160([1; 20]), verified: false, @@ -1281,7 +1285,7 @@ mod tests { price_estimator.expect_estimate().returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 100.into(), + out_amount: AlloyU256::from(100), gas: 200, solver: H160([1; 20]), verified: false, @@ -1355,7 +1359,7 @@ mod tests { price_estimator.expect_estimate().returning(|_| { async { Ok(price_estimation::Estimate { - out_amount: 100.into(), + out_amount: AlloyU256::from(100), gas: 200, solver: H160([1; 20]), verified: false, diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index 0b04f7bab8..7ab7aa6455 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -113,7 +113,7 @@ pub enum PartialValidationError { UnsupportedBuyTokenDestination(BuyTokenDestination), UnsupportedSellTokenSource(SellTokenSource), UnsupportedOrderType, - UnsupportedToken { token: H160, reason: String }, + UnsupportedToken { token: Address, reason: String }, Other(anyhow::Error), } @@ -187,10 +187,9 @@ impl From for ValidationError { CalculateQuoteError::Price { source: PriceEstimationError::UnsupportedToken { token, reason }, .. - } => ValidationError::Partial(PartialValidationError::UnsupportedToken { - token: token.into_legacy(), - reason, - }), + } => { + ValidationError::Partial(PartialValidationError::UnsupportedToken { token, reason }) + } CalculateQuoteError::Price { source: PriceEstimationError::ProtocolInternal(err), .. @@ -238,10 +237,10 @@ pub struct OrderValidator { #[derive(Debug, Eq, PartialEq, Default)] pub struct PreOrderData { - pub owner: H160, - pub sell_token: H160, - pub buy_token: H160, - pub receiver: H160, + pub owner: Address, + pub sell_token: Address, + pub buy_token: Address, + pub receiver: Address, pub valid_to: u32, pub partially_fillable: bool, pub buy_token_balance: BuyTokenDestination, @@ -250,25 +249,21 @@ pub struct PreOrderData { pub class: OrderClass, } -fn actual_receiver(owner: H160, order: &OrderData) -> H160 { +fn actual_receiver(owner: Address, order: &OrderData) -> Address { let receiver = order.receiver.unwrap_or_default(); - if receiver.is_zero() { - owner - } else { - receiver.into_legacy() - } + if receiver.is_zero() { owner } else { receiver } } impl PreOrderData { pub fn from_order_creation( - owner: H160, + owner: Address, order: &OrderData, signing_scheme: SigningScheme, ) -> Self { Self { owner, - sell_token: order.sell_token.into_legacy(), - buy_token: order.buy_token.into_legacy(), + sell_token: order.sell_token, + buy_token: order.buy_token, receiver: actual_receiver(owner, order), valid_to: order.valid_to, partially_fillable: order.partially_fillable, @@ -398,8 +393,8 @@ impl OrderValidator { .balance_fetcher .can_transfer( &account_balances::Query { - token: order.data().sell_token.into_legacy(), - owner, + token: order.data().sell_token, + owner: owner.into_alloy(), source: order.data().sell_token_balance, interactions: app_data.interactions.pre.clone(), balance_override: app_data.inner.protocol.flashloan.as_ref().map(|loan| { @@ -459,7 +454,7 @@ impl OrderValidating for OrderValidator { async fn partial_validate(&self, order: PreOrderData) -> Result<(), PartialValidationError> { if !self .banned_users - .banned([order.receiver.into_alloy(), order.owner.into_alloy()]) + .banned([order.receiver, order.owner]) .await .is_empty() { @@ -489,14 +484,14 @@ impl OrderValidating for OrderValidator { if has_same_buy_and_sell_token(&order, self.native_token.address()) { return Err(PartialValidationError::SameBuyAndSellToken); } - if order.sell_token.into_alloy() == BUY_ETH_ADDRESS.into_alloy() { + if order.sell_token == BUY_ETH_ADDRESS { return Err(PartialValidationError::InvalidNativeSellToken); } for &token in &[order.sell_token, order.buy_token] { if let TokenQuality::Bad { reason } = self .bad_token_detector - .detect(token.into_alloy()) + .detect(token) .await .map_err(PartialValidationError::Other)? { @@ -629,7 +624,8 @@ impl OrderValidating for OrderValidator { return Err(ValidationError::ZeroAmount); } - let pre_order = PreOrderData::from_order_creation(owner, &data, signing_scheme); + let pre_order = + PreOrderData::from_order_creation(owner.into_alloy(), &data, signing_scheme); let class = pre_order.class; self.partial_validate(pre_order) .await @@ -858,8 +854,7 @@ pub enum OrderValidToError { /// This also checks for orders selling wrapped native token for native token. fn has_same_buy_and_sell_token(order: &PreOrderData, native_token: &Address) -> bool { order.sell_token == order.buy_token - || (order.sell_token == native_token.into_legacy() - && order.buy_token.into_alloy() == BUY_ETH_ADDRESS.into_alloy()) + || (order.sell_token == *native_token && order.buy_token == BUY_ETH_ADDRESS) } /// Retrieves the quote for an order that is being created and verify that its @@ -1046,18 +1041,18 @@ mod tests { #[test] fn detects_orders_with_same_buy_and_sell_token() { - let native_token = [0xef; 20].into(); + let native_token = Address::repeat_byte(0xef); assert!(has_same_buy_and_sell_token( &PreOrderData { - sell_token: H160([0x01; 20]), - buy_token: H160([0x01; 20]), + sell_token: Address::repeat_byte(0x01), + buy_token: Address::repeat_byte(0x01), ..Default::default() }, &native_token, )); assert!(has_same_buy_and_sell_token( &PreOrderData { - sell_token: native_token.into_legacy(), + sell_token: native_token, buy_token: BUY_ETH_ADDRESS, ..Default::default() }, @@ -1066,8 +1061,8 @@ mod tests { assert!(!has_same_buy_and_sell_token( &PreOrderData { - sell_token: H160([0x01; 20]), - buy_token: H160([0x02; 20]), + sell_token: Address::repeat_byte(0x01), + buy_token: Address::repeat_byte(0x02), ..Default::default() }, &native_token, @@ -1077,7 +1072,7 @@ mod tests { assert!(!has_same_buy_and_sell_token( &PreOrderData { sell_token: BUY_ETH_ADDRESS, - buy_token: native_token.into_legacy(), + buy_token: native_token, ..Default::default() }, &native_token, @@ -1131,7 +1126,7 @@ mod tests { assert!(matches!( validator .partial_validate(PreOrderData { - owner: H160::from_low_u64_be(1), + owner: Address::with_last_byte(1), ..Default::default() }) .await, @@ -1140,7 +1135,7 @@ mod tests { assert!(matches!( validator .partial_validate(PreOrderData { - receiver: H160::from_low_u64_be(1), + receiver: Address::with_last_byte(1), ..Default::default() }) .await, @@ -1210,8 +1205,8 @@ mod tests { validator .partial_validate(PreOrderData { valid_to: legit_valid_to, - buy_token: H160::from_low_u64_be(2), - sell_token: H160::from_low_u64_be(2), + buy_token: Address::with_last_byte(2), + sell_token: Address::with_last_byte(2), ..Default::default() }) .await, @@ -1275,8 +1270,8 @@ mod tests { valid_to: time::now_in_epoch_seconds() + validity_configuration.min.as_secs() as u32 + 2, - sell_token: H160::from_low_u64_be(1), - buy_token: H160::from_low_u64_be(2), + sell_token: Address::with_last_byte(1), + buy_token: Address::with_last_byte(2), ..Default::default() }; @@ -1295,7 +1290,7 @@ mod tests { validator .partial_validate(PreOrderData { class: OrderClass::Limit, - owner: H160::from_low_u64_be(0x42), + owner: Address::with_last_byte(0x42), valid_to: time::now_in_epoch_seconds() + validity_configuration.max_market.as_secs() as u32 + 2, @@ -1309,7 +1304,7 @@ mod tests { .partial_validate(PreOrderData { partially_fillable: true, class: OrderClass::Liquidity, - owner: H160::from_low_u64_be(0x42), + owner: Address::with_last_byte(0x42), valid_to: u32::MAX, ..order() }) diff --git a/crates/shared/src/price_estimation/competition/mod.rs b/crates/shared/src/price_estimation/competition/mod.rs index 9db12164b4..41722a2f05 100644 --- a/crates/shared/src/price_estimation/competition/mod.rs +++ b/crates/shared/src/price_estimation/competition/mod.rs @@ -248,7 +248,7 @@ mod tests { PriceEstimating, Query, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, anyhow::anyhow, futures::channel::oneshot::channel, model::order::OrderKind, @@ -308,12 +308,12 @@ mod tests { ]; let estimates = [ Estimate { - out_amount: 1.into(), + out_amount: U256::ONE, gas: 1, ..Default::default() }, Estimate { - out_amount: 2.into(), + out_amount: U256::from(2), gas: 1, ..Default::default() }, @@ -398,7 +398,7 @@ mod tests { fn estimate(amount: u64) -> Estimate { Estimate { - out_amount: amount.into(), + out_amount: U256::from(amount), gas: 1, ..Default::default() } @@ -459,7 +459,7 @@ mod tests { fn estimate(amount: u64) -> Estimate { Estimate { - out_amount: amount.into(), + out_amount: U256::from(amount), gas: 1, ..Default::default() } @@ -536,7 +536,7 @@ mod tests { fn estimate(amount: u64) -> Estimate { Estimate { - out_amount: amount.into(), + out_amount: U256::from(amount), gas: 1, ..Default::default() } diff --git a/crates/shared/src/price_estimation/competition/quote.rs b/crates/shared/src/price_estimation/competition/quote.rs index b061127cd2..30a168950d 100644 --- a/crates/shared/src/price_estimation/competition/quote.rs +++ b/crates/shared/src/price_estimation/competition/quote.rs @@ -138,7 +138,7 @@ impl RankingContext { /// trade route would report a higher `out_amount_in_eth`. This is also /// referred to as "bang-for-buck" and what matters most to traders. fn effective_eth_out(&self, estimate: &Estimate, kind: OrderKind) -> U256 { - let eth_out = estimate.out_amount.to_f64_lossy() * self.native_price; + let eth_out = f64::from(estimate.out_amount) * self.native_price; let fees = estimate.gas as f64 * self.gas_price; let effective_eth_out = match kind { // High fees mean receiving less `buy_token` from your sell order. @@ -163,13 +163,14 @@ mod tests { native::MockNativePriceEstimating, }, }, + alloy::primitives::U256, gas_estimation::GasPrice1559, model::order::OrderKind, }; fn price(out_amount: u128, gas: u64) -> PriceEstimateResult { Ok(Estimate { - out_amount: out_amount.into(), + out_amount: U256::from(out_amount), gas, ..Default::default() }) @@ -352,13 +353,13 @@ mod tests { #[tokio::test] async fn prefer_verified_over_unverified() { let worse_verified_quote = Ok(Estimate { - out_amount: 900_000.into(), + out_amount: U256::from(900_000), gas: 2_000, verified: true, ..Default::default() }); let better_unverified_quote = Ok(Estimate { - out_amount: 1_000_000.into(), + out_amount: U256::from(1_000_000), gas: 1_000, verified: false, ..Default::default() diff --git a/crates/shared/src/price_estimation/factory.rs b/crates/shared/src/price_estimation/factory.rs index 800dcfc311..3e99ae703b 100644 --- a/crates/shared/src/price_estimation/factory.rs +++ b/crates/shared/src/price_estimation/factory.rs @@ -27,13 +27,10 @@ use { tenderly_api::TenderlyCodeSimulator, token_info::TokenInfoFetching, }, + alloy::primitives::Address, anyhow::{Context as _, Result}, contracts::alloy::WETH9, - ethcontract::H160, - ethrpc::{ - alloy::conversions::{IntoAlloy, IntoLegacy}, - block_stream::CurrentBlockWatcher, - }, + ethrpc::{alloy::conversions::IntoLegacy, block_stream::CurrentBlockWatcher}, gas_estimation::GasPriceEstimating, number::nonzero::U256 as NonZeroU256, rate_limit::RateLimiter, @@ -62,9 +59,9 @@ pub struct Network { pub web3: Web3, pub simulation_web3: Option, pub chain: chain::Chain, - pub native_token: H160, - pub settlement: H160, - pub authenticator: H160, + pub native_token: Address, + pub settlement: Address, + pub authenticator: Address, pub base_tokens: Arc, pub block_stream: CurrentBlockWatcher, } @@ -131,15 +128,12 @@ impl<'a> PriceEstimatorFactory<'a> { NonZeroU256::try_from( self.args .amount_to_estimate_prices_with - .or_else(|| { - Some( - self.network - .chain - .default_amount_to_estimate_native_prices_with() - .into_legacy(), - ) + .unwrap_or_else(|| { + self.network + .chain + .default_amount_to_estimate_native_prices_with() }) - .context("No amount to estimate prices with set.")?, + .into_legacy(), ) } @@ -307,7 +301,7 @@ impl<'a> PriceEstimatorFactory<'a> { fn sanitized(&self, estimator: Arc) -> SanitizedPriceEstimator { SanitizedPriceEstimator::new( estimator, - self.network.native_token.into_alloy(), + self.network.native_token, self.components.bad_token_detector.clone(), ) } @@ -379,8 +373,8 @@ impl<'a> PriceEstimatorFactory<'a> { self.args.native_price_cache_concurrent_requests, self.args .native_price_approximation_tokens - .clone() - .into_iter() + .iter() + .copied() .collect(), self.args.quote_timeout, )); diff --git a/crates/shared/src/price_estimation/mod.rs b/crates/shared/src/price_estimation/mod.rs index 3d2d624ba6..f9c37e4dd0 100644 --- a/crates/shared/src/price_estimation/mod.rs +++ b/crates/shared/src/price_estimation/mod.rs @@ -4,10 +4,11 @@ use { arguments::{self, display_option, display_secret_option}, trade_finding::{Interaction, QuoteExecution}, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, anyhow::{Result, ensure}, bigdecimal::BigDecimal, - ethcontract::{H160, U256}, + ethcontract::H160, + ethrpc::alloy::conversions::IntoAlloy, futures::future::BoxFuture, itertools::Itertools, model::order::{BuyTokenDestination, OrderKind, SellTokenSource}, @@ -200,8 +201,8 @@ pub struct Arguments { /// The amount in native tokens atoms to use for price estimation. Should be /// reasonably large so that small pools do not influence the prices. If /// not set a reasonable default is used based on network id. - #[clap(long, env, value_parser = U256::from_dec_str)] - pub amount_to_estimate_prices_with: Option, + #[clap(long, env)] + pub amount_to_estimate_prices_with: Option, /// The API endpoint for the Balancer SOR API for solving. #[clap(long, env)] @@ -260,16 +261,16 @@ pub struct Arguments { long, env, value_delimiter = ',', - value_parser = parse_tuple:: + value_parser = parse_tuple:: )] - pub native_price_approximation_tokens: Vec<(H160, H160)>, + pub native_price_approximation_tokens: Vec<(Address, Address)>, /// Tokens for which quote verification should not be attempted. This is an /// escape hatch when there is a very bad but verifiable liquidity source /// that would win against a very good but unverifiable liquidity source /// (e.g. private liquidity that exists but can't be verified). #[clap(long, env, value_delimiter = ',')] - pub tokens_without_verification: Vec, + pub tokens_without_verification: Vec
, } /// Custom Clap parser for tuple pair @@ -542,8 +543,8 @@ impl Estimate { /// Returns (sell_amount, buy_amount). pub fn amounts(&self, query: &Query) -> (U256, U256) { match query.kind { - OrderKind::Buy => (self.out_amount, query.in_amount.get()), - OrderKind::Sell => (query.in_amount.get(), self.out_amount), + OrderKind::Buy => (self.out_amount, query.in_amount.get().into_alloy()), + OrderKind::Sell => (query.in_amount.get().into_alloy(), self.out_amount), } } @@ -553,7 +554,7 @@ impl Estimate { /// unit of sell_token (buy_amount / sell_amount). pub fn price_in_buy_token_f64(&self, query: &Query) -> f64 { let (sell_amount, buy_amount) = self.amounts(query); - buy_amount.to_f64_lossy() / sell_amount.to_f64_lossy() + f64::from(buy_amount) / f64::from(sell_amount) } } diff --git a/crates/shared/src/price_estimation/native/mod.rs b/crates/shared/src/price_estimation/native/mod.rs index 5070e93aa8..0b18d6fefd 100644 --- a/crates/shared/src/price_estimation/native/mod.rs +++ b/crates/shared/src/price_estimation/native/mod.rs @@ -2,11 +2,9 @@ use { crate::price_estimation::{PriceEstimating, PriceEstimationError, Query}, alloy::primitives::Address, bigdecimal::{BigDecimal, ToPrimitive}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::FutureExt, model::order::OrderKind, number::nonzero::U256 as NonZeroU256, - primitive_types::{H160, U256}, std::{ sync::{Arc, LazyLock}, time::Duration, @@ -37,12 +35,12 @@ pub fn from_normalized_price(price: BigDecimal) -> Option { } /// Convert from floating point price to normalized price -pub fn to_normalized_price(price: f64) -> Option { +pub fn to_normalized_price(price: f64) -> Option { let uint_max = 2.0_f64.powi(256); let price_in_eth = 1e18 * price; (price_in_eth.is_normal() && price_in_eth >= 1. && price_in_eth < uint_max) - .then_some(U256::from_f64_lossy(price_in_eth)) + .then_some(alloy::primitives::U256::saturating_from(price_in_eth)) } #[cfg_attr(any(test, feature = "test-util"), mockall::automock)] @@ -62,14 +60,14 @@ pub trait NativePriceEstimating: Send + Sync { /// compared to the current chain's native token. pub struct NativePriceEstimator { inner: Arc, - native_token: H160, + native_token: Address, price_estimation_amount: NonZeroU256, } impl NativePriceEstimator { pub fn new( inner: Arc, - native_token: H160, + native_token: Address, price_estimation_amount: NonZeroU256, ) -> Self { Self { @@ -80,10 +78,10 @@ impl NativePriceEstimator { } // TODO explain why we use BUY order type (shallow liquidity) - fn query(&self, token: &H160, timeout: Duration) -> Query { + fn query(&self, token: &Address, timeout: Duration) -> Query { Query { - sell_token: token.into_alloy(), - buy_token: self.native_token.into_alloy(), + sell_token: *token, + buy_token: self.native_token, in_amount: self.price_estimation_amount, kind: OrderKind::Buy, verification: Default::default(), @@ -101,7 +99,7 @@ impl NativePriceEstimating for NativePriceEstimator { timeout: Duration, ) -> futures::future::BoxFuture<'_, NativePriceEstimateResult> { async move { - let query = Arc::new(self.query(&token.into_legacy(), timeout)); + let query = Arc::new(self.query(&token, timeout)); let estimate = self.inner.estimate(query.clone()).await?; let price = estimate.price_in_buy_token_f64(&query); if is_price_malformed(price) { @@ -124,7 +122,8 @@ mod tests { use { super::*, crate::price_estimation::{Estimate, HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating}, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, + ethrpc::alloy::conversions::IntoLegacy, primitive_types::H160, std::str::FromStr, }; @@ -137,7 +136,7 @@ mod tests { assert!(query.sell_token == Address::with_last_byte(3)); async { Ok(Estimate { - out_amount: 123_456_789_000_000_000u128.into(), + out_amount: U256::from(123_456_789_000_000_000u128), gas: 0, solver: H160([1; 20]), verified: false, @@ -149,8 +148,11 @@ mod tests { let native_price_estimator = NativePriceEstimator { inner: Arc::new(inner), - native_token: H160::from_low_u64_be(7), - price_estimation_amount: NonZeroU256::try_from(U256::exp10(18)).unwrap(), + native_token: Address::with_last_byte(7), + price_estimation_amount: NonZeroU256::try_from( + U256::from(10).pow(U256::from(18)).into_legacy(), + ) + .unwrap(), }; let result = native_price_estimator @@ -170,8 +172,11 @@ mod tests { let native_price_estimator = NativePriceEstimator { inner: Arc::new(inner), - native_token: H160::from_low_u64_be(7), - price_estimation_amount: NonZeroU256::try_from(U256::exp10(18)).unwrap(), + native_token: Address::with_last_byte(7), + price_estimation_amount: NonZeroU256::try_from( + U256::from(10).pow(U256::from(18)).into_legacy(), + ) + .unwrap(), }; let result = native_price_estimator diff --git a/crates/shared/src/price_estimation/native_price_cache.rs b/crates/shared/src/price_estimation/native_price_cache.rs index adb6802366..5e95f7e45f 100644 --- a/crates/shared/src/price_estimation/native_price_cache.rs +++ b/crates/shared/src/price_estimation/native_price_cache.rs @@ -7,10 +7,8 @@ use { }, alloy::primitives::Address, bigdecimal::BigDecimal, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::{FutureExt, StreamExt}, indexmap::IndexSet, - primitive_types::H160, prometheus::{IntCounter, IntCounterVec, IntGauge}, rand::Rng, std::{ @@ -51,8 +49,8 @@ impl Metrics { pub struct CachingNativePriceEstimator(Arc); struct Inner { - cache: Mutex>, - high_priority: Mutex>, + cache: Mutex>, + high_priority: Mutex>, estimator: Box, max_age: Duration, concurrent_requests: usize, @@ -65,7 +63,7 @@ struct Inner { /// safe (e.g. csUSDL => Dai). /// It's very important that the 2 tokens have the same number of decimals. /// After startup this is a read only value. - approximation_tokens: HashMap, + approximation_tokens: HashMap, quote_timeout: Duration, } @@ -123,9 +121,9 @@ impl CachedResult { impl Inner { // Returns a single cached price and updates its `requested_at` field. fn get_cached_price( - token: H160, + token: Address, now: Instant, - cache: &mut MutexGuard>, + cache: &mut MutexGuard>, max_age: &Duration, create_missing_entry: bool, ) -> Option { @@ -157,9 +155,9 @@ impl Inner { } fn get_ready_to_use_cached_price( - token: H160, + token: Address, now: Instant, - cache: &mut MutexGuard>, + cache: &mut MutexGuard>, max_age: &Duration, create_missing_entry: bool, ) -> Option { @@ -174,10 +172,10 @@ impl Inner { /// have fetched some requested price in the meantime. fn estimate_prices_and_update_cache<'a>( &'a self, - tokens: &'a [H160], + tokens: &'a [Address], max_age: Duration, request_timeout: Duration, - ) -> futures::stream::BoxStream<'a, (H160, NativePriceEstimateResult)> { + ) -> futures::stream::BoxStream<'a, (Address, NativePriceEstimateResult)> { let estimates = tokens.iter().map(move |token| async move { let current_accumulative_errors_count = { // check if the price is cached by now @@ -197,7 +195,7 @@ impl Inner { let result = self .estimator - .estimate_native_price(token_to_fetch.into_alloy(), request_timeout) + .estimate_native_price(token_to_fetch, request_timeout) .await; // update price in cache @@ -219,7 +217,7 @@ impl Inner { } /// Tokens with highest priority first. - fn sorted_tokens_to_update(&self, max_age: Duration, now: Instant) -> Vec { + fn sorted_tokens_to_update(&self, max_age: Duration, now: Instant) -> Vec
{ let mut outdated: Vec<_> = self .cache .lock() @@ -230,7 +228,7 @@ impl Inner { .collect(); let high_priority = self.high_priority.lock().unwrap().clone(); - let index = |token: &H160| high_priority.get_index_of(token).unwrap_or(usize::MAX); + let index = |token: &Address| high_priority.get_index_of(token).unwrap_or(usize::MAX); outdated.sort_by_cached_key(|entry| { ( index(&entry.0), // important items have a low index @@ -300,7 +298,7 @@ impl UpdateTask { } impl CachingNativePriceEstimator { - pub fn initialize_cache(&self, prices: HashMap) { + pub fn initialize_cache(&self, prices: HashMap) { let mut rng = rand::thread_rng(); let now = std::time::Instant::now(); @@ -343,7 +341,7 @@ impl CachingNativePriceEstimator { update_size: Option, prefetch_time: Duration, concurrent_requests: usize, - approximation_tokens: HashMap, + approximation_tokens: HashMap, quote_timeout: Duration, ) -> Self { let inner = Arc::new(Inner { @@ -374,8 +372,8 @@ impl CachingNativePriceEstimator { /// background task. fn get_cached_prices( &self, - tokens: &[H160], - ) -> HashMap> { + tokens: &[Address], + ) -> HashMap> { let now = Instant::now(); let mut cache = self.0.cache.lock().unwrap(); let mut results = HashMap::default(); @@ -399,16 +397,16 @@ impl CachingNativePriceEstimator { results } - pub fn replace_high_priority(&self, tokens: IndexSet) { + pub fn replace_high_priority(&self, tokens: IndexSet
) { tracing::trace!(?tokens, "update high priority tokens"); *self.0.high_priority.lock().unwrap() = tokens; } pub async fn estimate_native_prices_with_timeout<'a>( &'a self, - tokens: &'a [H160], + tokens: &'a [Address], timeout: Duration, - ) -> HashMap { + ) -> HashMap { let mut prices = self.get_cached_prices(tokens); if timeout.is_zero() { return prices; @@ -416,7 +414,7 @@ impl CachingNativePriceEstimator { let uncached_tokens: Vec<_> = tokens .iter() - .filter(|t| !prices.contains_key(t)) + .filter(|t| !prices.contains_key(*t)) .copied() .collect(); let price_stream = @@ -448,13 +446,7 @@ impl NativePriceEstimating for CachingNativePriceEstimator { let cached = { let now = Instant::now(); let mut cache = self.0.cache.lock().unwrap(); - Inner::get_ready_to_use_cached_price( - token.into_legacy(), - now, - &mut cache, - &self.0.max_age, - false, - ) + Inner::get_ready_to_use_cached_price(token, now, &mut cache, &self.0.max_age, false) }; let label = if cached.is_some() { "hits" } else { "misses" }; @@ -468,7 +460,7 @@ impl NativePriceEstimating for CachingNativePriceEstimator { } self.0 - .estimate_prices_and_update_cache(&[token.into_legacy()], self.0.max_age, timeout) + .estimate_prices_and_update_cache(&[token], self.0.max_age, timeout) .next() .await .unwrap() @@ -505,9 +497,8 @@ mod tests { let min_age = Duration::from_secs(MAX_AGE_SECS * 49 / 100); let max_age = Duration::from_secs(MAX_AGE_SECS * 91 / 100); - let prices = HashMap::from_iter( - (0..10).map(|t| (token(t).into_legacy(), BigDecimal::try_from(1e18).unwrap())), - ); + let prices = + HashMap::from_iter((0..10).map(|t| (token(t), BigDecimal::try_from(1e18).unwrap()))); let estimator = CachingNativePriceEstimator::new( Box::new(inner), Duration::from_secs(MAX_AGE_SECS), @@ -593,8 +584,8 @@ mod tests { 1, // set token approximations for tokens 1 and 2 HashMap::from([ - (token(1).into_legacy(), token(100).into_legacy()), - (token(2).into_legacy(), token(200).into_legacy()), + (Address::with_last_byte(1), Address::with_last_byte(100)), + (Address::with_last_byte(2), Address::with_last_byte(200)), ]), HEALTHY_PRICE_ESTIMATION_TIME, ); @@ -602,7 +593,7 @@ mod tests { // no approximation token used for token 0 assert_eq!( estimator - .estimate_native_price(token(0), HEALTHY_PRICE_ESTIMATION_TIME) + .estimate_native_price(Address::with_last_byte(0), HEALTHY_PRICE_ESTIMATION_TIME) .await .unwrap() .to_i64() @@ -613,7 +604,7 @@ mod tests { // approximation price used for tokens 1 and 2 assert_eq!( estimator - .estimate_native_price(token(1), HEALTHY_PRICE_ESTIMATION_TIME) + .estimate_native_price(Address::with_last_byte(1), HEALTHY_PRICE_ESTIMATION_TIME) .await .unwrap() .to_i64() @@ -622,7 +613,7 @@ mod tests { ); assert_eq!( estimator - .estimate_native_price(token(2), HEALTHY_PRICE_ESTIMATION_TIME) + .estimate_native_price(Address::with_last_byte(2), HEALTHY_PRICE_ESTIMATION_TIME) .await .unwrap() .to_i64() @@ -978,8 +969,8 @@ mod tests { #[test] fn outdated_entries_prioritized() { - let t0 = H160::from_low_u64_be(0); - let t1 = H160::from_low_u64_be(1); + let t0 = Address::with_last_byte(0); + let t1 = Address::with_last_byte(1); let now = Instant::now(); let inner = Inner { cache: Mutex::new( diff --git a/crates/shared/src/price_estimation/sanitized.rs b/crates/shared/src/price_estimation/sanitized.rs index a8b20b6838..6144340bb9 100644 --- a/crates/shared/src/price_estimation/sanitized.rs +++ b/crates/shared/src/price_estimation/sanitized.rs @@ -66,7 +66,7 @@ impl PriceEstimating for SanitizedPriceEstimator { // buy_token == sell_token => 1 to 1 conversion if query.buy_token == query.sell_token { let estimation = Estimate { - out_amount: query.in_amount.get(), + out_amount: query.in_amount.get().into_alloy(), gas: 0, solver: Default::default(), verified: true, @@ -77,11 +77,9 @@ impl PriceEstimating for SanitizedPriceEstimator { } // sell WETH for ETH => 1 to 1 conversion with cost for unwrapping - if query.sell_token == self.native_token - && query.buy_token == BUY_ETH_ADDRESS.into_alloy() - { + if query.sell_token == self.native_token && query.buy_token == BUY_ETH_ADDRESS { let estimation = Estimate { - out_amount: query.in_amount.get(), + out_amount: query.in_amount.get().into_alloy(), gas: GAS_PER_WETH_UNWRAP, solver: Default::default(), verified: true, @@ -92,11 +90,9 @@ impl PriceEstimating for SanitizedPriceEstimator { } // sell ETH for WETH => 1 to 1 conversion with cost for wrapping - if query.sell_token == BUY_ETH_ADDRESS.into_alloy() - && query.buy_token == self.native_token - { + if query.sell_token == BUY_ETH_ADDRESS && query.buy_token == self.native_token { let estimation = Estimate { - out_amount: query.in_amount.get(), + out_amount: query.in_amount.get().into_alloy(), gas: GAS_PER_WETH_WRAP, solver: Default::default(), verified: true, @@ -112,14 +108,12 @@ impl PriceEstimating for SanitizedPriceEstimator { let mut adjusted_query = Query::clone(&*query); let modification = if query.sell_token != self.native_token - && query.buy_token == BUY_ETH_ADDRESS.into_alloy() + && query.buy_token == BUY_ETH_ADDRESS { tracing::debug!(?query, "estimate price for buying native asset"); adjusted_query.buy_token = self.native_token; Some(Modification::AddGas(GAS_PER_WETH_UNWRAP)) - } else if query.sell_token == BUY_ETH_ADDRESS.into_alloy() - && query.buy_token != self.native_token - { + } else if query.sell_token == BUY_ETH_ADDRESS && query.buy_token != self.native_token { tracing::debug!(?query, "estimate price for selling native asset"); adjusted_query.sell_token = self.native_token; Some(Modification::AddGas(GAS_PER_WETH_WRAP)) @@ -158,7 +152,7 @@ mod tests { bad_token::{MockBadTokenDetecting, TokenQuality}, price_estimation::{HEALTHY_PRICE_ESTIMATION_TIME, MockPriceEstimating}, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256 as AlloyU256}, ethrpc::alloy::conversions::IntoAlloy, model::order::OrderKind, number::nonzero::U256 as NonZeroU256, @@ -196,7 +190,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, gas: 100, solver: Default::default(), verified: false, @@ -210,14 +204,14 @@ mod tests { Query { verification: Default::default(), sell_token: Address::with_last_byte(1), - buy_token: BUY_ETH_ADDRESS.into_alloy(), + buy_token: BUY_ETH_ADDRESS, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Buy, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, //sanitized_estimator will add ETH_UNWRAP_COST to the gas of any //Query with ETH as the buy_token. gas: GAS_PER_WETH_UNWRAP + 100, @@ -231,7 +225,7 @@ mod tests { Query { verification: Default::default(), sell_token: Address::with_last_byte(1), - buy_token: BUY_ETH_ADDRESS.into_alloy(), + buy_token: BUY_ETH_ADDRESS, in_amount: NonZeroU256::try_from(U256::MAX).unwrap(), kind: OrderKind::Buy, block_dependent: false, @@ -247,7 +241,7 @@ mod tests { ( Query { verification: Default::default(), - sell_token: BUY_ETH_ADDRESS.into_alloy(), + sell_token: BUY_ETH_ADDRESS, buy_token: Address::with_last_byte(1), in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Buy, @@ -255,7 +249,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, //sanitized_estimator will add ETH_WRAP_COST to the gas of any //Query with ETH as the sell_token. gas: GAS_PER_WETH_WRAP + 100, @@ -277,7 +271,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, gas: 0, solver: Default::default(), verified: true, @@ -288,15 +282,15 @@ mod tests { ( Query { verification: Default::default(), - sell_token: BUY_ETH_ADDRESS.into_alloy(), - buy_token: BUY_ETH_ADDRESS.into_alloy(), + sell_token: BUY_ETH_ADDRESS, + buy_token: BUY_ETH_ADDRESS, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Sell, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, gas: 0, solver: Default::default(), verified: true, @@ -308,14 +302,14 @@ mod tests { Query { verification: Default::default(), sell_token: native_token, - buy_token: BUY_ETH_ADDRESS.into_alloy(), + buy_token: BUY_ETH_ADDRESS, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Sell, block_dependent: false, timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, // Sanitized estimator will report a 1:1 estimate when unwrapping native token. gas: GAS_PER_WETH_UNWRAP, solver: Default::default(), @@ -327,7 +321,7 @@ mod tests { ( Query { verification: Default::default(), - sell_token: BUY_ETH_ADDRESS.into_alloy(), + sell_token: BUY_ETH_ADDRESS, buy_token: native_token, in_amount: NonZeroU256::try_from(1).unwrap(), kind: OrderKind::Sell, @@ -335,7 +329,7 @@ mod tests { timeout: HEALTHY_PRICE_ESTIMATION_TIME, }, Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, // Sanitized estimator will report a 1:1 estimate when wrapping native token. gas: GAS_PER_WETH_WRAP, solver: Default::default(), @@ -403,7 +397,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, gas: 100, solver: Default::default(), verified: false, @@ -419,7 +413,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, gas: 100, solver: Default::default(), verified: false, @@ -435,7 +429,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, gas: u64::MAX, solver: Default::default(), verified: false, @@ -451,7 +445,7 @@ mod tests { .returning(|_| { async { Ok(Estimate { - out_amount: 1.into(), + out_amount: AlloyU256::ONE, gas: 100, solver: Default::default(), verified: false, diff --git a/crates/shared/src/price_estimation/trade_finder.rs b/crates/shared/src/price_estimation/trade_finder.rs index fa1314eca8..3775830ff1 100644 --- a/crates/shared/src/price_estimation/trade_finder.rs +++ b/crates/shared/src/price_estimation/trade_finder.rs @@ -72,8 +72,8 @@ impl Inner { if let Some(verifier) = &self.verifier { let trade = self.finder.get_trade(&query).await?; let price_query = PriceQuery { - sell_token: query.sell_token.into_legacy(), - buy_token: query.buy_token.into_legacy(), + sell_token: query.sell_token, + buy_token: query.buy_token, in_amount: query.in_amount, kind: query.kind, }; @@ -86,7 +86,7 @@ impl Inner { let quote = self.finder.get_quote(&query).await?; Ok(Estimate { - out_amount: quote.out_amount.into_legacy(), + out_amount: quote.out_amount, gas: quote.gas_estimate, solver: quote.solver.into_legacy(), verified: false, diff --git a/crates/shared/src/price_estimation/trade_verifier/mod.rs b/crates/shared/src/price_estimation/trade_verifier/mod.rs index 91073f1e97..07fbecf85a 100644 --- a/crates/shared/src/price_estimation/trade_verifier/mod.rs +++ b/crates/shared/src/price_estimation/trade_verifier/mod.rs @@ -70,16 +70,16 @@ pub struct TradeVerifier { balance_overrides: Arc, block_stream: CurrentBlockWatcher, settlement: GPv2Settlement::Instance, - native_token: H160, + native_token: Address, quote_inaccuracy_limit: BigRational, domain_separator: DomainSeparator, - tokens_without_verification: HashSet, + tokens_without_verification: HashSet
, } impl TradeVerifier { const DEFAULT_GAS: u64 = 12_000_000; const SPARDOSE: Address = address!("0000000000000000000000000000000000020000"); - const TRADER_IMPL: H160 = addr!("0000000000000000000000000000000000010000"); + const TRADER_IMPL: Address = address!("0000000000000000000000000000000000010000"); #[expect(clippy::too_many_arguments)] pub async fn new( @@ -88,13 +88,13 @@ impl TradeVerifier { code_fetcher: Arc, balance_overrides: Arc, block_stream: CurrentBlockWatcher, - settlement: H160, - native_token: H160, + settlement: Address, + native_token: Address, quote_inaccuracy_limit: BigDecimal, - tokens_without_verification: HashSet, + tokens_without_verification: HashSet
, ) -> Result { let settlement_contract = - GPv2Settlement::GPv2Settlement::new(settlement.into_alloy(), web3.alloy.clone()); + GPv2Settlement::GPv2Settlement::new(settlement, web3.alloy.clone()); let domain_separator = DomainSeparator(settlement_contract.domainSeparator().call().await?.0); Ok(Self { @@ -116,7 +116,7 @@ impl TradeVerifier { query: &PriceQuery, mut verification: Verification, trade: &TradeKind, - out_amount: &U256, + out_amount: &alloy::primitives::U256, ) -> Result { let start = std::time::Instant::now(); @@ -136,16 +136,16 @@ impl TradeVerifier { TradeKind::Legacy(_) => { let tokens = vec![query.sell_token, query.buy_token]; let prices = match query.kind { - OrderKind::Sell => vec![*out_amount, query.in_amount.get()], - OrderKind::Buy => vec![query.in_amount.get(), *out_amount], + OrderKind::Sell => { + vec![*out_amount, query.in_amount.get().into_alloy()] + } + OrderKind::Buy => { + vec![query.in_amount.get().into_alloy(), *out_amount] + } }; (tokens, prices) } - TradeKind::Regular(trade) => trade - .clearing_prices - .iter() - .map(|(addr, value)| (addr.into_legacy(), value.into_legacy())) - .unzip(), + TradeKind::Regular(trade) => trade.clearing_prices.iter().unzip(), }; let settlement = encode_settlement( @@ -157,7 +157,7 @@ impl TradeVerifier { out_amount, self.native_token, &self.domain_separator, - self.settlement.address().into_legacy(), + *self.settlement.address(), )?; let settlement = add_balance_queries(settlement, query, &verification, solver_address); @@ -167,7 +167,7 @@ impl TradeVerifier { let solver = Solver::Instance::new(solver_address, self.web3.alloy.clone()); let swap_simulation = solver.swap( *self.settlement.address(), - tokens.iter().cloned().map(IntoAlloy::into_alloy).collect(), + tokens.clone(), verification.receiver, settle_call.into(), ) @@ -236,8 +236,8 @@ impl TradeVerifier { // settlement buffers to make the quote happen. When the settlement contract // itself is the trader or receiver these values need to be adjusted slightly. let (sell_amount, buy_amount) = match query.kind { - OrderKind::Sell => (query.in_amount.get(), summary.out_amount), - OrderKind::Buy => (summary.out_amount, query.in_amount.get()), + OrderKind::Sell => (query.in_amount.get().into_alloy(), summary.out_amount), + OrderKind::Buy => (summary.out_amount, query.in_amount.get().into_alloy()), }; // It looks like the contract lost a lot of sell tokens but only because it was @@ -246,7 +246,9 @@ impl TradeVerifier { summary .tokens_lost .entry(query.sell_token) - .and_modify(|balance| *balance -= u256_to_big_rational(&sell_amount)); + .and_modify(|balance| { + *balance -= number::conversions::alloy::u256_to_big_rational(&sell_amount) + }); } // It looks like the contract gained a lot of buy tokens (negative loss) but // only because it was the receiver and got the payout. Adjust the tokens lost @@ -255,13 +257,15 @@ impl TradeVerifier { summary .tokens_lost .entry(query.buy_token) - .and_modify(|balance| *balance += u256_to_big_rational(&buy_amount)); + .and_modify(|balance| { + *balance += number::conversions::alloy::u256_to_big_rational(&buy_amount) + }); } } tracing::debug!( tokens_lost = ?summary.tokens_lost, - gas_diff = ?trade.gas_estimate().unwrap_or_default().abs_diff(summary.gas_used.as_u64()), + gas_diff = ?trade.gas_estimate().unwrap_or_default().abs_diff(summary.gas_used.saturating_to()), time = ?start.elapsed(), promised_out_amount = ?out_amount, verified_out_amount = ?summary.out_amount, @@ -298,14 +302,14 @@ impl TradeVerifier { match self .balance_overrides .state_override(BalanceOverrideRequest { - token: query.sell_token, + token: query.sell_token.into_legacy(), holder: Self::SPARDOSE.into_legacy(), amount: match query.kind { OrderKind::Sell => query.in_amount.get(), OrderKind::Buy => trade .out_amount( - &query.buy_token.into_alloy(), - &query.sell_token.into_alloy(), + &query.buy_token, + &query.sell_token, &query.in_amount.get().into_alloy(), &query.kind, )? @@ -351,7 +355,7 @@ impl TradeVerifier { .context("failed to fetch trader code")?; if !trader_impl.0.is_empty() { overrides.insert( - Self::TRADER_IMPL, + Self::TRADER_IMPL.into_legacy(), StateOverride { code: Some(trader_impl), ..Default::default() @@ -414,16 +418,8 @@ fn legacy_settlement_to_alloy( settlement: EncodedSettlement, ) -> GPv2Settlement::GPv2Settlement::settleCall { GPv2Settlement::GPv2Settlement::settleCall { - tokens: settlement - .tokens - .into_iter() - .map(|t| t.into_alloy()) - .collect(), - clearingPrices: settlement - .clearing_prices - .into_iter() - .map(|p| p.into_alloy()) - .collect(), + tokens: settlement.tokens, + clearingPrices: settlement.clearing_prices, interactions: settlement.interactions.map(|interactions| { interactions .into_iter() @@ -465,8 +461,8 @@ impl TradeVerifying for TradeVerifier { ) -> Result { let out_amount = trade .out_amount( - &query.buy_token.into_alloy(), - &query.sell_token.into_alloy(), + &query.buy_token, + &query.sell_token, &query.in_amount.get().into_alloy(), &query.kind, ) @@ -475,7 +471,7 @@ impl TradeVerifying for TradeVerifier { let unverified_result = trade .gas_estimate() .map(|gas| Estimate { - out_amount: out_amount.into_legacy(), + out_amount, gas, solver: trade.solver().into_legacy(), verified: false, @@ -487,7 +483,7 @@ impl TradeVerifying for TradeVerifier { }) .context("solver provided no gas estimate"); - let skip_verification = [&query.buy_token, &query.sell_token] + let skip_verification = [query.buy_token, query.sell_token] .iter() .any(|token| self.tokens_without_verification.contains(token)); if skip_verification { @@ -496,12 +492,7 @@ impl TradeVerifying for TradeVerifier { } match self - .verify_inner( - query, - verification.clone(), - &trade, - &out_amount.into_legacy(), - ) + .verify_inner(query, verification.clone(), &trade, &out_amount) .await { Ok(verified) => Ok(verified), @@ -526,12 +517,12 @@ fn encode_settlement( query: &PriceQuery, verification: &Verification, trade: &TradeKind, - tokens: &[H160], - clearing_prices: &[U256], - out_amount: &U256, - native_token: H160, + tokens: &[Address], + clearing_prices: &[alloy::primitives::U256], + out_amount: &alloy::primitives::U256, + native_token: Address, domain_separator: &DomainSeparator, - settlement: H160, + settlement: Address, ) -> Result { let mut trade_interactions = encode_interactions(&trade.interactions()); if query.buy_token == BUY_ETH_ADDRESS { @@ -541,16 +532,14 @@ fn encode_settlement( // ourselves here. let buy_amount = match query.kind { OrderKind::Sell => *out_amount, - OrderKind::Buy => query.in_amount.get(), + OrderKind::Buy => query.in_amount.get().into_alloy(), }; trade_interactions.push(( - native_token.into_alloy(), + native_token, alloy::primitives::U256::ZERO, - WETH9::WETH9::withdrawCall { - wad: buy_amount.into_alloy(), - } - .abi_encode() - .into(), + WETH9::WETH9::withdrawCall { wad: buy_amount } + .abi_encode() + .into(), )); tracing::trace!("adding unwrap interaction for paying out ETH"); } @@ -572,16 +561,16 @@ fn encode_settlement( // with helpful error messages. let trade_setup_interaction = { let sell_amount = match query.kind { - OrderKind::Sell => query.in_amount.get(), + OrderKind::Sell => query.in_amount.get().into_alloy(), OrderKind::Buy => *out_amount, }; let solver_address = trade.solver(); let setup_call = Solver::Solver::ensureTradePreconditionsCall { trader: verification.from, - settlementContract: settlement.into_alloy(), - sellToken: query.sell_token.into_alloy(), - sellAmount: sell_amount.into_alloy(), - nativeToken: native_token.into_alloy(), + settlementContract: settlement, + sellToken: query.sell_token, + sellAmount: sell_amount, + nativeToken: native_token, spardose: TradeVerifier::SPARDOSE, } .abi_encode(); @@ -613,25 +602,28 @@ fn encode_settlement( fn encode_fake_trade( query: &PriceQuery, verification: &Verification, - out_amount: &U256, - tokens: &[H160], + out_amount: &alloy::primitives::U256, + tokens: &[Address], ) -> Result { // Configure the most disadvantageous trade possible (while taking possible // overflows into account). Should the trader not receive the amount promised by // the [`Trade`] the simulation will still work and we can compute the actual // [`Trade::out_amount`] afterwards. let (sell_amount, buy_amount) = match query.kind { - OrderKind::Sell => (query.in_amount.get(), 0.into()), + OrderKind::Sell => ( + query.in_amount.get().into_alloy(), + alloy::primitives::U256::ZERO, + ), OrderKind::Buy => ( - (*out_amount).max(U256::from(u128::MAX)), - query.in_amount.get(), + (*out_amount).max(alloy::primitives::U256::from(u128::MAX)), + query.in_amount.get().into_alloy(), ), }; let fake_order = OrderData { - sell_token: query.sell_token.into_alloy(), - sell_amount: sell_amount.into_alloy(), - buy_token: query.buy_token.into_alloy(), - buy_amount: buy_amount.into_alloy(), + sell_token: query.sell_token, + sell_amount, + buy_token: query.buy_token, + buy_amount, receiver: Some(verification.receiver), valid_to: u32::MAX, app_data: Default::default(), @@ -664,7 +656,7 @@ fn encode_fake_trade( fn encode_jit_orders( jit_orders: &[dto::JitOrder], - tokens: &[H160], + tokens: &[Address], domain_separator: &DomainSeparator, ) -> Result, Error> { jit_orders @@ -697,11 +689,11 @@ fn encode_jit_orders( // the tokens set length is small so the linear search is acceptable tokens .iter() - .position(|token| token == &jit_order.sell_token) + .position(|token| token.into_legacy() == jit_order.sell_token) .context("missing jit order sell token index")?, tokens .iter() - .position(|token| token == &jit_order.buy_token) + .position(|token| token.into_legacy() == jit_order.buy_token) .context("missing jit order buy token index")?, &jit_order.executed_amount, )) @@ -763,7 +755,7 @@ fn add_balance_queries( OrderKind::Buy => (query.sell_token, verification.from), }; let query_balance_call = Solver::Solver::storeBalanceCall { - token: token.into_alloy(), + token, owner, countGas: true, } @@ -785,12 +777,12 @@ fn add_balance_queries( #[derive(Debug)] struct SettleOutput { /// Gas used for the `settle()` call. - gas_used: U256, + gas_used: alloy::primitives::U256, /// `out_amount` perceived by the trader (sell token for buy orders or buy /// token for sell order) - out_amount: U256, + out_amount: alloy::primitives::U256, /// Tokens difference of the settlement contract before and after the trade. - tokens_lost: HashMap, + tokens_lost: HashMap, } impl SettleOutput { @@ -800,7 +792,7 @@ impl SettleOutput { queriedBalances, }: Solver::Solver::swapReturn, kind: OrderKind, - tokens_vec: &[H160], + tokens_vec: &[Address], ) -> Result { // The balances are stored in the following order: // [...tokens_before, user_balance_before, user_balance_after, ...tokens_after] @@ -836,8 +828,8 @@ impl SettleOutput { let out_amount = out_amount.context("underflow during out_amount computation")?; Ok(SettleOutput { - gas_used: gasUsed.into_legacy(), - out_amount: out_amount.into_legacy(), + gas_used: gasUsed, + out_amount, tokens_lost, }) } @@ -853,12 +845,12 @@ fn ensure_quote_accuracy( ) -> std::result::Result { // amounts verified by the simulation let (sell_amount, buy_amount) = match query.kind { - OrderKind::Buy => (summary.out_amount, query.in_amount.get()), - OrderKind::Sell => (query.in_amount.get(), summary.out_amount), + OrderKind::Buy => (summary.out_amount, query.in_amount.get().into_alloy()), + OrderKind::Sell => (query.in_amount.get().into_alloy(), summary.out_amount), }; let (sell_amount, buy_amount) = ( - u256_to_big_rational(&sell_amount), - u256_to_big_rational(&buy_amount), + number::conversions::alloy::u256_to_big_rational(&sell_amount), + number::conversions::alloy::u256_to_big_rational(&buy_amount), ); let sell_token_lost_limit = inaccuracy_limit * &sell_amount; let buy_token_lost_limit = inaccuracy_limit * &buy_amount; @@ -878,7 +870,7 @@ fn ensure_quote_accuracy( Ok(Estimate { out_amount: summary.out_amount, - gas: summary.gas_used.as_u64(), + gas: summary.gas_used.saturating_to(), solver: trade.solver().into_legacy(), verified: true, execution: QuoteExecution { @@ -891,9 +883,9 @@ fn ensure_quote_accuracy( #[derive(Debug)] pub struct PriceQuery { - pub sell_token: H160, + pub sell_token: Address, // This should be `BUY_ETH_ADDRESS` if you actually want to trade `ETH` - pub buy_token: H160, + pub buy_token: Address, pub kind: OrderKind, pub in_amount: NonZeroU256, } @@ -911,7 +903,7 @@ enum Error { #[cfg(test)] mod tests { - use {super::*, maplit::hashmap, std::str::FromStr}; + use {super::*, alloy::primitives::U256, maplit::hashmap, std::str::FromStr}; #[test] fn discards_inaccurate_quotes() { @@ -920,8 +912,8 @@ mod tests { let low_threshold = big_decimal_to_big_rational(&BigDecimal::from_str("0.5").unwrap()); let high_threshold = big_decimal_to_big_rational(&BigDecimal::from_str("0.51").unwrap()); - let sell_token = H160([1u8; 20]); - let buy_token = H160([2u8; 20]); + let sell_token = Address::repeat_byte(1); + let buy_token = Address::repeat_byte(2); let query = PriceQuery { in_amount: 1_000.try_into().unwrap(), @@ -935,8 +927,8 @@ mod tests { sell_token => BigRational::from_integer(500.into()), }; let summary = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), + gas_used: U256::ZERO, + out_amount: U256::from(2_000), tokens_lost, }; let estimate = @@ -948,8 +940,8 @@ mod tests { buy_token => BigRational::from_integer(0.into()), }; let summary = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), + gas_used: U256::ZERO, + out_amount: U256::from(2_000), tokens_lost, }; @@ -963,8 +955,8 @@ mod tests { buy_token => BigRational::from_integer(0.into()), }; let summary = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), + gas_used: U256::ZERO, + out_amount: U256::from(2_000), tokens_lost, }; let estimate = @@ -977,8 +969,8 @@ mod tests { }; let sell_more = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), + gas_used: U256::ZERO, + out_amount: U256::from(2_000), tokens_lost, }; @@ -997,8 +989,8 @@ mod tests { }; let pay_out_more = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), + gas_used: U256::ZERO, + out_amount: U256::from(2_000), tokens_lost, }; @@ -1017,8 +1009,8 @@ mod tests { }; let sell_less = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), + gas_used: U256::ZERO, + out_amount: U256::from(2_000), tokens_lost, }; // Ending up with surplus in the buffers is always fine @@ -1032,8 +1024,8 @@ mod tests { }; let pay_out_less = SettleOutput { - gas_used: 0.into(), - out_amount: 2_000.into(), + gas_used: U256::ZERO, + out_amount: U256::from(2_000), tokens_lost, }; // Ending up with surplus in the buffers is always fine diff --git a/crates/shared/src/token_info.rs b/crates/shared/src/token_info.rs index 5e94e19ece..844316a5e4 100644 --- a/crates/shared/src/token_info.rs +++ b/crates/shared/src/token_info.rs @@ -3,10 +3,7 @@ use { anyhow::Result, async_trait::async_trait, contracts::alloy::ERC20, - ethrpc::{ - Web3, - alloy::{conversions::IntoAlloy, errors::ignore_non_node_error}, - }, + ethrpc::{Web3, alloy::errors::ignore_non_node_error}, futures::{ FutureExt, future::{BoxFuture, Shared}, @@ -48,7 +45,7 @@ pub struct TokenInfoFetcher { impl TokenInfoFetcher { async fn fetch_token(&self, address: Address) -> Result { - if address == BUY_ETH_ADDRESS.into_alloy() { + if address == BUY_ETH_ADDRESS { return Ok(TokenInfo { decimals: Some(18), symbol: Some("NATIVE_ASSET".to_string()), diff --git a/crates/shared/src/trade_finding/mod.rs b/crates/shared/src/trade_finding/mod.rs index 540289ddd8..d25483f7bf 100644 --- a/crates/shared/src/trade_finding/mod.rs +++ b/crates/shared/src/trade_finding/mod.rs @@ -138,7 +138,7 @@ pub struct LegacyTrade { /// A trade with JIT orders. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Trade { - pub clearing_prices: HashMap, + pub clearing_prices: HashMap, /// How many units of gas this trade will roughly cost. pub gas_estimate: Option, /// The onchain calls to run before sending user funds to the settlement diff --git a/crates/solver/src/settlement/mod.rs b/crates/solver/src/settlement/mod.rs index 5228053081..ca27ac43be 100644 --- a/crates/solver/src/settlement/mod.rs +++ b/crates/solver/src/settlement/mod.rs @@ -2,10 +2,11 @@ mod settlement_encoder; use { crate::liquidity::Settleable, + alloy::primitives::Address, anyhow::Result, ethrpc::alloy::conversions::IntoLegacy, model::order::{Order, OrderKind}, - primitive_types::{H160, U256}, + primitive_types::U256, shared::{ conversions::U256Ext as _, encoded_settlement::{EncodedSettlement, EncodedTrade, encode_trade}, @@ -25,8 +26,8 @@ pub struct Trade { #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct TradeExecution { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, pub sell_amount: U256, pub buy_amount: U256, pub fee_amount: U256, @@ -75,8 +76,8 @@ impl Trade { }; Some(TradeExecution { - sell_token: order.sell_token.into_legacy(), - buy_token: order.buy_token.into_legacy(), + sell_token: order.sell_token, + buy_token: order.buy_token, sell_amount, buy_amount, fee_amount: self.executed_fee()?, @@ -112,7 +113,7 @@ pub enum Revertable { impl Settlement { /// Creates a new settlement builder for the specified clearing prices. - pub fn new(clearing_prices: HashMap) -> Self { + pub fn new(clearing_prices: HashMap) -> Self { Self { encoder: SettlementEncoder::new(clearing_prices), } @@ -128,7 +129,7 @@ impl Settlement { } /// Returns the clearing prices map. - pub fn clearing_prices(&self) -> &HashMap { + pub fn clearing_prices(&self) -> &HashMap { self.encoder.clearing_prices() } @@ -157,13 +158,12 @@ pub mod tests { use { super::*, crate::liquidity::SettlementHandling, - ethrpc::alloy::conversions::IntoAlloy, maplit::hashmap, model::order::{OrderClass, OrderData, OrderKind, OrderMetadata}, }; pub fn assert_settlement_encoded_with( - prices: HashMap, + prices: HashMap, handler: S, execution: L::Execution, exec: impl FnOnce(&mut SettlementEncoder), @@ -187,7 +187,10 @@ pub mod tests { /// Helper function for creating a settlement for the specified prices and /// trades for testing objective value computations. - fn test_settlement(prices: HashMap, trades: Vec) -> Settlement { + fn test_settlement( + prices: HashMap, + trades: Vec, + ) -> Settlement { Settlement { encoder: SettlementEncoder::with_trades(prices, trades), } @@ -277,13 +280,13 @@ pub mod tests { // Test if passing a clearing price of zero makes it not possible to add // trades. - let token0 = H160::from_low_u64_be(0); - let token1 = H160::from_low_u64_be(1); + let token0 = Address::with_last_byte(0); + let token1 = Address::with_last_byte(1); let order = Order { data: OrderData { - sell_token: token0.into_alloy(), - buy_token: token1.into_alloy(), + sell_token: token0, + buy_token: token1, sell_amount: alloy::primitives::U256::from(10), buy_amount: alloy::primitives::U256::from(9), kind: OrderKind::Sell, @@ -413,8 +416,8 @@ pub mod tests { #[test] fn includes_limit_order_ucp() { - let sell_token = H160([1; 20]); - let buy_token = H160([2; 20]); + let sell_token = alloy::primitives::Address::repeat_byte(1); + let buy_token = alloy::primitives::Address::repeat_byte(2); let settlement = test_settlement( hashmap! { @@ -424,8 +427,8 @@ pub mod tests { vec![Trade { order: Order { data: OrderData { - sell_token: sell_token.into_alloy(), - buy_token: buy_token.into_alloy(), + sell_token, + buy_token, sell_amount: alloy::primitives::U256::from(100_000_u128), buy_amount: alloy::primitives::U256::from(99_000_u128), kind: OrderKind::Sell, @@ -453,10 +456,10 @@ pub mod tests { assert_eq!( settlement.clearing_prices, [ - 100_000_u128.into(), - 100_000_u128.into(), - 99_000_u128.into(), - 100_000_u128.into(), + alloy::primitives::U256::from(100_000_u128), + alloy::primitives::U256::from(100_000_u128), + alloy::primitives::U256::from(99_000_u128), + alloy::primitives::U256::from(100_000_u128), ], ); } diff --git a/crates/solver/src/settlement/settlement_encoder.rs b/crates/solver/src/settlement/settlement_encoder.rs index bc37bd788d..445e494b87 100644 --- a/crates/solver/src/settlement/settlement_encoder.rs +++ b/crates/solver/src/settlement/settlement_encoder.rs @@ -1,6 +1,7 @@ use { super::{Trade, TradeExecution}, crate::interactions::UnwrapWethInteraction, + alloy::primitives::Address, anyhow::{Context as _, Result, ensure}, ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, itertools::Either, @@ -8,7 +9,7 @@ use { interaction::InteractionData, order::{Order, OrderClass, OrderKind}, }, - primitive_types::{H160, U256}, + primitive_types::U256, shared::{ conversions::U256Ext, encoded_settlement::EncodedSettlement, @@ -39,8 +40,8 @@ pub struct SettlementEncoder { // Make sure to update the `merge` method when adding new fields. // Invariant: tokens is all keys in clearing_prices sorted. - tokens: Vec, - clearing_prices: HashMap, + tokens: Vec
, + clearing_prices: HashMap, trades: Vec, // This is an Arc so that this struct is Clone. Cannot require `Interaction: Clone` because it // would make the trait not be object safe which prevents using it through `dyn`. @@ -92,7 +93,7 @@ impl SettlementEncoder { /// /// The prices must be provided up front in order to ensure that all tokens /// included in the settlement are known when encoding trades. - pub(crate) fn new(clearing_prices: HashMap) -> Self { + pub(crate) fn new(clearing_prices: HashMap) -> Self { // Explicitly define a token ordering based on the supplied clearing // prices. This is done since `HashMap::keys` returns an iterator in // arbitrary order ([1]), meaning that we can't rely that the ordering @@ -116,7 +117,7 @@ impl SettlementEncoder { } #[cfg(test)] - pub fn with_trades(clearing_prices: HashMap, trades: Vec) -> Self { + pub fn with_trades(clearing_prices: HashMap, trades: Vec) -> Self { let mut result = Self::new(clearing_prices); for trade in trades { result @@ -126,7 +127,7 @@ impl SettlementEncoder { result } - pub(crate) fn clearing_prices(&self) -> &HashMap { + pub(crate) fn clearing_prices(&self) -> &HashMap { &self.clearing_prices } @@ -170,18 +171,18 @@ impl SettlementEncoder { verify_executed_amount(&order, executed_amount)?; let sell_price = self .clearing_prices - .get(&order.data.sell_token.into_legacy()) + .get(&order.data.sell_token) .context("settlement missing sell token")?; let sell_token_index = self - .token_index(order.data.sell_token.into_legacy()) + .token_index(order.data.sell_token) .expect("missing sell token with price"); let buy_price = self .clearing_prices - .get(&order.data.buy_token.into_legacy()) + .get(&order.data.buy_token) .context("settlement missing buy token")?; let buy_token_index = self - .token_index(order.data.buy_token.into_legacy()) + .token_index(order.data.buy_token) .expect("missing buy token with price"); let trade = EncoderTrade { @@ -286,11 +287,11 @@ impl SettlementEncoder { // while pocketing the `surplus_fee` from the `sell_token`s. let uniform_buy_price = *self .clearing_prices - .get(&order.data.buy_token.into_legacy()) + .get(&order.data.buy_token) .context("buy token price is missing")?; let uniform_sell_price = *self .clearing_prices - .get(&order.data.sell_token.into_legacy()) + .get(&order.data.sell_token) .context("sell token price is missing")?; let (sell_amount, buy_amount) = match order.data.kind { @@ -384,7 +385,11 @@ impl SettlementEncoder { } #[cfg(test)] - pub(crate) fn add_token_equivalency(&mut self, token_a: H160, token_b: H160) -> Result<()> { + pub(crate) fn add_token_equivalency( + &mut self, + token_a: Address, + token_b: Address, + ) -> Result<()> { let (new_token, existing_price) = match ( self.clearing_prices.get(&token_a), self.clearing_prices.get(&token_b), @@ -421,10 +426,10 @@ impl SettlementEncoder { self.trades[i].tokens = match self.trades[i].tokens { TokenReference::Indexed { .. } => TokenReference::Indexed { sell_token_index: self - .token_index(self.trades[i].data.order.data.sell_token.into_legacy()) + .token_index(self.trades[i].data.order.data.sell_token) .expect("missing sell token for existing trade"), buy_token_index: self - .token_index(self.trades[i].data.order.data.buy_token.into_legacy()) + .token_index(self.trades[i].data.order.data.buy_token) .expect("missing buy token for existing trade"), }, original @ TokenReference::CustomPrice { .. } => original, @@ -432,7 +437,7 @@ impl SettlementEncoder { } } - fn token_index(&self, token: H160) -> Option { + fn token_index(&self, token: Address) -> Option { self.tokens.binary_search(&token).ok() } @@ -457,10 +462,9 @@ impl SettlementEncoder { }) .collect(); - self.tokens - .retain(|token| traded_tokens.contains(&token.into_alloy())); + self.tokens.retain(|token| traded_tokens.contains(token)); self.clearing_prices - .retain(|token, _| traded_tokens.contains(&token.into_alloy())); + .retain(|token, _| traded_tokens.contains(token)); self.sort_tokens_and_update_indices(); } @@ -473,24 +477,21 @@ impl SettlementEncoder { let uniform_clearing_price_vec_length = self.tokens.len(); let mut tokens = self.tokens.clone(); - let mut clearing_prices: Vec = self + let mut clearing_prices: Vec<_> = self .tokens .iter() .map(|token| { - *self - .clearing_prices + self.clearing_prices .get(token) .expect("missing clearing price for token") + .into_alloy() }) .collect(); { // add tokens/prices for custom price orders, since they are not contained in // the UCP vector - let (mut custom_price_order_tokens, mut custom_price_order_prices): ( - Vec, - Vec, - ) = self + let (mut custom_price_order_tokens, mut custom_price_order_prices) = self .trades .iter() .filter_map(|trade| match trade.tokens { @@ -499,12 +500,12 @@ impl SettlementEncoder { buy_token_price, } => Some(vec![ ( - trade.data.order.data.sell_token.into_legacy(), - sell_token_price, + trade.data.order.data.sell_token, + sell_token_price.into_alloy(), ), ( - trade.data.order.data.buy_token.into_legacy(), - buy_token_price, + trade.data.order.data.buy_token, + buy_token_price.into_alloy(), ), ]), _ => None, @@ -608,7 +609,6 @@ pub mod tests { super::*, alloy::primitives::Address, contracts::alloy::WETH9, - ethrpc::alloy::conversions::IntoAlloy, maplit::hashmap, model::order::{Interactions, OrderBuilder, OrderData}, shared::interaction::{EncodedInteraction, Interaction}, @@ -640,8 +640,8 @@ pub mod tests { }; let mut settlement = SettlementEncoder::new(maplit::hashmap! { - token0.into_legacy() => 1.into(), - token1.into_legacy() => 1.into(), + token0 => 1.into(), + token1 => 1.into(), }); assert!(settlement.add_trade(order0, 1.into(), 1.into()).is_ok()); @@ -677,8 +677,8 @@ pub mod tests { #[test] fn settlement_reflects_different_price_for_normal_and_liquidity_order() { let mut settlement = SettlementEncoder::new(maplit::hashmap! { - token(0) => 3.into(), - token(1) => 10.into(), + Address::with_last_byte(0) => 3.into(), + Address::with_last_byte(1) => 10.into(), }); let order01 = OrderBuilder::default() @@ -702,11 +702,21 @@ pub mod tests { settlement.finish(InternalizationStrategy::SkipInternalizableInteraction); assert_eq!( finished_settlement.tokens, - vec![token(0), token(1), token(1), token(0)] + vec![ + Address::with_last_byte(0), + Address::with_last_byte(1), + Address::with_last_byte(1), + Address::with_last_byte(0) + ] ); assert_eq!( finished_settlement.clearing_prices, - vec![3.into(), 10.into(), 20.into(), 10.into()] + vec![ + alloy::primitives::U256::from(3), + alloy::primitives::U256::from(10), + alloy::primitives::U256::from(20), + alloy::primitives::U256::from(10) + ] ); assert_eq!( finished_settlement.trades[1].1, // <-- is the buy token index of liquidity order @@ -721,7 +731,7 @@ pub mod tests { #[test] fn settlement_inserts_sell_price_for_new_liquidity_order_if_price_did_not_exist() { let mut settlement = SettlementEncoder::new(maplit::hashmap! { - token(1) => 9.into(), + Address::with_last_byte(1) => 9.into(), }); let order01 = OrderBuilder::default() .with_sell_token(Address::with_last_byte(0)) @@ -737,20 +747,20 @@ pub mod tests { ); // ensures that the output of add_liquidity_order is not changed after adding // liquidity order - assert_eq!(settlement.tokens, vec![token(1)]); + assert_eq!(settlement.tokens, vec![Address::with_last_byte(1)]); let finished_settlement = settlement.finish(InternalizationStrategy::SkipInternalizableInteraction); // the initial price from:SettlementEncoder::new(maplit::hashmap! { // token(1) => 9.into(), // }); // gets dropped and replaced by the liquidity price - assert_eq!(finished_settlement.tokens, vec![token(0), token(1)]); + assert_eq!( + finished_settlement.tokens, + vec![Address::with_last_byte(0), Address::with_last_byte(1)] + ); assert_eq!( finished_settlement.clearing_prices, - vec![ - order01.data.buy_amount.into_legacy(), - order01.data.sell_amount.into_legacy() - ] + vec![order01.data.buy_amount, order01.data.sell_amount] ); assert_eq!( finished_settlement.trades[0].0, // <-- is the sell token index of liquidity order @@ -813,8 +823,8 @@ pub mod tests { #[test] fn settlement_encoder_add_token_equivalency() { - let token_a = H160([0x00; 20]); - let token_b = H160([0xff; 20]); + let token_a = Address::repeat_byte(0x00); + let token_b = Address::repeat_byte(0xff); let mut encoder = SettlementEncoder::new(hashmap! { token_a => 1.into(), token_b => 2.into(), @@ -823,9 +833,9 @@ pub mod tests { .add_trade( Order { data: OrderData { - sell_token: token_a.into_alloy(), + sell_token: token_a, sell_amount: alloy::primitives::U256::from(6), - buy_token: token_b.into_alloy(), + buy_token: token_b, buy_amount: alloy::primitives::U256::from(3), ..Default::default() }, @@ -845,7 +855,7 @@ pub mod tests { } ); - let token_c = H160([0xee; 20]); + let token_c = Address::repeat_byte(0xee); encoder.add_token_equivalency(token_a, token_c).unwrap(); assert_eq!(encoder.tokens, [token_a, token_c, token_b]); @@ -867,15 +877,15 @@ pub mod tests { let mut encoder = SettlementEncoder::new(HashMap::new()); assert!( encoder - .add_token_equivalency(H160([0; 20]), H160([1; 20])) + .add_token_equivalency(Address::repeat_byte(0), Address::repeat_byte(1)) .is_err() ); } #[test] fn settlement_encoder_non_equivalent_tokens() { - let token_a = H160([1; 20]); - let token_b = H160([2; 20]); + let token_a = Address::repeat_byte(1); + let token_b = Address::repeat_byte(2); let mut encoder = SettlementEncoder::new(hashmap! { token_a => 1.into(), token_b => 2.into(), @@ -883,13 +893,9 @@ pub mod tests { assert!(encoder.add_token_equivalency(token_a, token_b).is_err()); } - fn token(number: u64) -> H160 { - H160::from_low_u64_be(number) - } - #[test] fn trades_add_interactions_to_the_encoded_and_later_get_encoded() { - let prices = hashmap! { token(1) => 1.into(), token(3) => 3.into() }; + let prices = hashmap! { Address::with_last_byte(1) => 1.into(), Address::with_last_byte(3) => 3.into() }; let mut encoder = SettlementEncoder::new(prices); let i1 = InteractionData { target: Address::from_slice(&[12; 20]), @@ -960,8 +966,12 @@ pub mod tests { #[test] fn encoding_strips_unnecessary_tokens_and_prices() { - let prices = hashmap! {token(1) => 7.into(), token(2) => 2.into(), - token(3) => 9.into(), token(4) => 44.into()}; + let prices = hashmap! { + Address::with_last_byte(1) => 7.into(), + Address::with_last_byte(2) => 2.into(), + Address::with_last_byte(3) => 9.into(), + Address::with_last_byte(4) => 44.into() + }; let mut encoder = SettlementEncoder::new(prices); @@ -973,7 +983,7 @@ pub mod tests { .build(); encoder.add_trade(order_1_3, 11.into(), 0.into()).unwrap(); - let weth = WETH9::Instance::new(token(2).into_alloy(), ethrpc::mock::web3().alloy); + let weth = WETH9::Instance::new(Address::with_last_byte(2), ethrpc::mock::web3().alloy); encoder.add_unwrap(UnwrapWethInteraction { weth, amount: alloy::primitives::U256::from(12), @@ -982,11 +992,14 @@ pub mod tests { let encoded = encoder.finish(InternalizationStrategy::SkipInternalizableInteraction); // only token 1 and 2 have been included in orders by traders - let expected_tokens: Vec<_> = [1, 3].into_iter().map(token).collect(); + let expected_tokens: Vec<_> = [1, 3].into_iter().map(Address::with_last_byte).collect(); assert_eq!(expected_tokens, encoded.tokens); // only the prices for token 1 and 2 remain and they are in the correct order - let expected_prices: Vec<_> = [7, 9].into_iter().map(U256::from).collect(); + let expected_prices: Vec<_> = [7, 9] + .into_iter() + .map(alloy::primitives::U256::from) + .collect(); assert_eq!(expected_prices, encoded.clearing_prices); let encoded_trade = &encoded.trades[0]; @@ -1014,7 +1027,7 @@ pub mod tests { #[test] fn optionally_encodes_internalizable_transactions() { - let prices = hashmap! {token(1) => 7.into() }; + let prices = hashmap! {Address::with_last_byte(1) => 7.into() }; let mut encoder = SettlementEncoder::new(prices); encoder.append_to_execution_plan_internalizable(Arc::new(TestInteraction), true); @@ -1031,8 +1044,8 @@ pub mod tests { #[test] fn computes_custom_price_for_sell_limit_order_correctly() { - let weth = token(1); - let usdc = token(2); + let weth = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); let prices = hashmap! { // assumption 1 WETH == 1_000 USDC (all prices multiplied by 10^18) weth => U256::exp10(18), @@ -1043,9 +1056,9 @@ pub mod tests { // sell 1.01 WETH for 1_000 USDC with a fee of 0.01 WETH (or 10 USDC) let order = OrderBuilder::default() .with_class(OrderClass::Limit) - .with_sell_token(weth.into_alloy()) + .with_sell_token(weth) .with_sell_amount(alloy::primitives::U256::from(1_010_000_000_000_000_000u128)) // 1.01 WETH - .with_buy_token(usdc.into_alloy()) + .with_buy_token(usdc) .with_buy_amount(alloy::primitives::U256::from(10).pow(alloy::primitives::U256::from(9))) // 1_000 USDC .with_fee_amount(alloy::primitives::U256::ZERO) .with_kind(OrderKind::Sell) @@ -1085,8 +1098,8 @@ pub mod tests { #[test] fn computes_custom_price_for_buy_limit_order_correctly() { - let weth = token(1); - let usdc = token(2); + let weth = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); // assuming 1 WETH == 1_000 USDC let prices = hashmap! { weth => U256::exp10(18), @@ -1097,9 +1110,9 @@ pub mod tests { // buy 1 WETH for 1_010 USDC with a fee of 10 USDC let order = OrderBuilder::default() .with_class(OrderClass::Limit) - .with_buy_token(weth.into_alloy()) + .with_buy_token(weth) .with_buy_amount(alloy::primitives::U256::from(10).pow(alloy::primitives::U256::from(18))) // 1 WETH - .with_sell_token(usdc.into_alloy()) + .with_sell_token(usdc) .with_sell_amount(alloy::primitives::U256::from(1_010_000_000u128)) // 1_010 USDC .with_fee_amount(alloy::primitives::U256::ZERO) .with_kind(OrderKind::Buy)