From 4a4487253ad6122e6b3b199ee3b3b6daa9b1b6d3 Mon Sep 17 00:00:00 2001 From: ilya Date: Thu, 20 Nov 2025 13:10:33 +0000 Subject: [PATCH 001/470] Send `eth_createAccessList` lists RPC requests with the `latest` block tag (#3913) @ahhda noticed that `eth_createAccessList` calls have started to fail on Erigon and DRPC nodes when the block tag param is not provided, even though the official documentation states this param is optional https://ethereum.github.io/execution-apis/api-documentation/ By default, "latest" is used, so this PR shouldn't hurt. --- crates/driver/src/infra/blockchain/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/driver/src/infra/blockchain/mod.rs b/crates/driver/src/infra/blockchain/mod.rs index ec2d5e448d..25c109ca61 100644 --- a/crates/driver/src/infra/blockchain/mod.rs +++ b/crates/driver/src/infra/blockchain/mod.rs @@ -188,7 +188,7 @@ impl Ethereum { .transport() .execute( "eth_createAccessList", - vec![serde_json::to_value(&tx).unwrap()], + vec![serde_json::to_value(&tx).unwrap(), "latest".into()], ) .await?; if let Some(err) = json.get("error") { From facfa75ce83eb019679c1da3088f7d574bd968d8 Mon Sep 17 00:00:00 2001 From: ilya Date: Fri, 21 Nov 2025 10:04:47 +0000 Subject: [PATCH 002/470] Configurable nonce block number (#3914) Even though #3787 has helped mitigate some issues, it doesn't work well across different chains. The nonce block number is now configurable and uses the web3 lib's default behavior if set to None (basically, the original behavior). While the real issue is probably somewhere in our nodes config(since Alchemy works well with `pending` blocks), will try configuring the `latest` block on chains with the `nonce too low` issues that come from our nodes to avoid using Alchemy's expensive plan. --- crates/driver/src/domain/mempools.rs | 4 ++-- crates/driver/src/infra/config/file/load.rs | 1 + crates/driver/src/infra/config/file/mod.rs | 24 +++++++++++++++++++++ crates/driver/src/infra/mempool/mod.rs | 20 ++++++++--------- crates/driver/src/tests/setup/solver.rs | 1 + 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/crates/driver/src/domain/mempools.rs b/crates/driver/src/domain/mempools.rs index 672c892535..f2446f11bc 100644 --- a/crates/driver/src/domain/mempools.rs +++ b/crates/driver/src/domain/mempools.rs @@ -130,10 +130,10 @@ impl Mempools { } } - // Fetch the pending nonce to avoid race conditions between concurrent + // Fetch the nonce to avoid race conditions between concurrent // transactions (e.g., settlement tx and cancellation tx) from the same // solver address. - let nonce = mempool.get_pending_nonce(solver.address()).await?; + let nonce = mempool.get_nonce(solver.address()).await?; let hash = mempool .submit(tx.clone(), settlement.gas, solver, nonce) .await?; diff --git a/crates/driver/src/infra/config/file/load.rs b/crates/driver/src/infra/config/file/load.rs index a4a32a4e53..ffd20f214e 100644 --- a/crates/driver/src/infra/config/file/load.rs +++ b/crates/driver/src/infra/config/file/load.rs @@ -326,6 +326,7 @@ pub async fn load(chain: Chain, path: &Path) -> infra::Config { gas_price_cap: config.submission.gas_price_cap, target_confirm_time: config.submission.target_confirm_time, retry_interval: config.submission.retry_interval, + nonce_block_number: config.submission.nonce_block_number.map(Into::into), kind: match mempool { file::Mempool::Public { max_additional_tip, diff --git a/crates/driver/src/infra/config/file/mod.rs b/crates/driver/src/infra/config/file/mod.rs index d27579a3e1..109113f6d1 100644 --- a/crates/driver/src/infra/config/file/mod.rs +++ b/crates/driver/src/infra/config/file/mod.rs @@ -114,12 +114,36 @@ struct SubmissionConfig { #[serde(with = "humantime_serde", default = "default_retry_interval")] retry_interval: Duration, + /// Block number to use when fetching nonces. Options: "pending", + /// "latest", "earliest". If not specified, uses the web3 lib's default + /// behavior. + #[serde(default)] + nonce_block_number: Option, + /// The mempools to submit settlement transactions to. Can be the public /// mempool of a node or the private MEVBlocker mempool. #[serde(rename = "mempool", default)] mempools: Vec, } +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "lowercase")] +enum BlockNumber { + Pending, + Latest, + Earliest, +} + +impl From for web3::types::BlockNumber { + fn from(bn: BlockNumber) -> Self { + match bn { + BlockNumber::Pending => web3::types::BlockNumber::Pending, + BlockNumber::Latest => web3::types::BlockNumber::Latest, + BlockNumber::Earliest => web3::types::BlockNumber::Earliest, + } + } +} + #[serde_as] #[derive(Debug, Deserialize)] #[serde(tag = "mempool")] diff --git a/crates/driver/src/infra/mempool/mod.rs b/crates/driver/src/infra/mempool/mod.rs index f80d03ce04..c89413e9b4 100644 --- a/crates/driver/src/infra/mempool/mod.rs +++ b/crates/driver/src/infra/mempool/mod.rs @@ -14,6 +14,9 @@ pub struct Config { pub target_confirm_time: std::time::Duration, pub retry_interval: std::time::Duration, pub kind: Kind, + /// Optional block number to use when fetching nonces. If None, uses the + /// web3 lib's default behavior, which is `latest`. + pub nonce_block_number: Option, } #[derive(Debug, Clone)] @@ -76,21 +79,16 @@ impl Mempool { Self { config, transport } } - /// Fetches the pending transaction count (nonce) for the given address. - /// This includes both mined transactions and pending transactions in the - /// mempool. - pub async fn get_pending_nonce( - &self, - address: eth::Address, - ) -> Result { + /// Fetches the transaction count (nonce) for the given address at the + /// specified block number. If no block number is provided in the config, + /// uses the web3 lib's default behavior. + pub async fn get_nonce(&self, address: eth::Address) -> Result { self.transport .eth() - .transaction_count(address.into(), Some(web3::types::BlockNumber::Pending)) + .transaction_count(address.into(), self.config.nonce_block_number) .await .map_err(|err| { - mempools::Error::Other( - anyhow::Error::from(err).context("failed to fetch pending nonce"), - ) + mempools::Error::Other(anyhow::Error::from(err).context("failed to fetch nonce")) }) } diff --git a/crates/driver/src/tests/setup/solver.rs b/crates/driver/src/tests/setup/solver.rs index e14d79c3e6..fb1eea74a5 100644 --- a/crates/driver/src/tests/setup/solver.rs +++ b/crates/driver/src/tests/setup/solver.rs @@ -462,6 +462,7 @@ impl Solver { additional_tip_percentage: 0., revert_protection: infra::mempool::RevertProtection::Disabled, }, + nonce_block_number: None, }], ) .await From dbbe4fbe2353c86ed72b0988a53586f4c5e53c97 Mon Sep 17 00:00:00 2001 From: ilya Date: Mon, 24 Nov 2025 14:32:27 +0000 Subject: [PATCH 003/470] Don't solve empty auctions (#3915) There is a chance that after preprocessing, the auction can become empty due to filtering out orders for specific reasons. It doesn't make sense to send this kind of auction to solvers. One of the solvers already reported about this on BNB. --- crates/driver/src/domain/competition/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/driver/src/domain/competition/mod.rs b/crates/driver/src/domain/competition/mod.rs index d9cf51cbc9..1fb751b9ca 100644 --- a/crates/driver/src/domain/competition/mod.rs +++ b/crates/driver/src/domain/competition/mod.rs @@ -185,6 +185,11 @@ impl Competition { drop(timer); tracing::debug!(?elapsed, "auction task execution time"); + if auction.orders.is_empty() { + tracing::info!("no orders left after pre-processing; skipping solving"); + return Ok(None); + } + let auction = &auction; // Fetch the solutions from the solver. From b8863217afa58ac8baa14724fd4ec39c03eea2bf Mon Sep 17 00:00:00 2001 From: "Jan [Yann]" <4518474+fafk@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:56:27 +0100 Subject: [PATCH 004/470] Use standard hooks trampoline address (#3904) # Description Last months it wasn't possible to compile and deploy to Linea using emv=shanghai, so we had to use an older version which didn't produce the same bytecode hence a different address. They upgraded the chain sync then, so we redeployed the contract and can now use the standard address. --- crates/contracts/src/alloy.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/contracts/src/alloy.rs b/crates/contracts/src/alloy.rs index b575da1112..2729993c66 100644 --- a/crates/contracts/src/alloy.rs +++ b/crates/contracts/src/alloy.rs @@ -532,8 +532,7 @@ crate::bindings!( OPTIMISM => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), POLYGON => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), LENS => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - // compiled with an older, linea-compatible evm version - LINEA => address!("0xeFcf0d30DB41Ae0b136c5E3B4340dFeE2D099Ada"), + LINEA => address!("0x60bf78233f48ec42ee3f101b9a05ec7878728006"), PLASMA => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), } ); From 6cafabff8e59892509eb1ef00df79a7edb403b70 Mon Sep 17 00:00:00 2001 From: ilya Date: Mon, 24 Nov 2025 18:48:16 +0000 Subject: [PATCH 005/470] Optimize `user_orders_with_quote` SQL query (#3912) An attempt to optimize the `user_orders_with_quote` query, which has been performing poorly recently. Uses a similar approach as #3542. --- crates/database/src/orders.rs | 176 ++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 41 deletions(-) diff --git a/crates/database/src/orders.rs b/crates/database/src/orders.rs index 8e9658236a..8e7f189d50 100644 --- a/crates/database/src/orders.rs +++ b/crates/database/src/orders.rs @@ -825,15 +825,103 @@ pub fn open_orders_by_time_or_uids<'a>( uids: &'a [OrderUid], after_timestamp: DateTime, ) -> BoxStream<'a, Result> { + // Optimized version using the OPEN_ORDERS pattern with CTEs and LATERAL joins #[rustfmt::skip] - const OPEN_ORDERS_AFTER: &str = const_format::concatcp!( - "SELECT ", SELECT, - " FROM ", FROM, - " LEFT OUTER JOIN ethflow_orders eth_o on eth_o.uid = o.uid ", - " WHERE (o.creation_timestamp > $1 OR o.cancellation_timestamp > $1 OR o.uid = ANY($2))", - ); + const QUERY: &str = r#" +WITH selected_orders AS ( + SELECT o.* + FROM orders o + WHERE (o.creation_timestamp > $1 OR o.cancellation_timestamp > $1 OR o.uid = ANY($2)) +), +trades_agg AS ( + SELECT t.order_uid, + SUM(t.buy_amount) AS sum_buy, + SUM(t.sell_amount) AS sum_sell, + SUM(t.fee_amount) AS sum_fee + FROM trades t + JOIN selected_orders so ON so.uid = t.order_uid + GROUP BY t.order_uid +) +SELECT + so.uid, + so.owner, + so.creation_timestamp, + so.sell_token, + so.buy_token, + so.sell_amount, + so.buy_amount, + so.valid_to, + so.app_data, + so.fee_amount, + so.kind, + so.partially_fillable, + so.signature, + so.receiver, + so.signing_scheme, + so.settlement_contract, + so.sell_token_balance, + so.buy_token_balance, + so.class, + + COALESCE(ta.sum_buy, 0) AS sum_buy, + COALESCE(ta.sum_sell, 0) AS sum_sell, + COALESCE(ta.sum_fee, 0) AS sum_fee, + (so.cancellation_timestamp IS NOT NULL OR + EXISTS (SELECT 1 FROM invalidations WHERE order_uid = so.uid) OR + EXISTS (SELECT 1 FROM onchain_order_invalidations WHERE uid = so.uid) + ) AS invalidated, + (so.signing_scheme = 'presign' AND COALESCE(pe.unsigned, TRUE)) AS presignature_pending, + ARRAY( + SELECT (p.target, p.value, p.data) + FROM interactions p + WHERE p.order_uid = so.uid AND p.execution = 'pre' + ORDER BY p.index + ) AS pre_interactions, + ARRAY( + SELECT (p.target, p.value, p.data) + FROM interactions p + WHERE p.order_uid = so.uid AND p.execution = 'post' + ORDER BY p.index + ) AS post_interactions, + ed.ethflow_data, + opo.onchain_user, + opo.onchain_placement_error, + COALESCE(fee_agg.executed_fee,0) AS executed_fee, + COALESCE(fee_agg.executed_fee_token, so.sell_token) AS executed_fee_token, + ad.full_app_data +FROM selected_orders so +LEFT JOIN LATERAL ( + SELECT NOT signed AS unsigned + FROM presignature_events + WHERE order_uid = so.uid + ORDER BY block_number DESC, log_index DESC + LIMIT 1 + ) pe ON TRUE +LEFT JOIN LATERAL ( + SELECT sender AS onchain_user, + placement_error AS onchain_placement_error + FROM onchain_placed_orders + WHERE uid = so.uid + ORDER BY block_number DESC + LIMIT 1 + ) opo ON TRUE +LEFT JOIN LATERAL ( + SELECT ROW(tx_hash, eo.valid_to) AS ethflow_data + FROM ethflow_orders eo + LEFT JOIN ethflow_refunds r ON r.order_uid = eo.uid + WHERE eo.uid = so.uid + ) ed ON TRUE +LEFT JOIN LATERAL ( + SELECT SUM(executed_fee) AS executed_fee, + (ARRAY_AGG(executed_fee_token))[1] AS executed_fee_token + FROM order_execution + WHERE order_uid = so.uid +) fee_agg ON TRUE +LEFT JOIN app_data ad ON ad.contract_app_data = so.app_data +LEFT JOIN trades_agg ta ON ta.order_uid = so.uid +"#; - sqlx::query_as(OPEN_ORDERS_AFTER) + sqlx::query_as(QUERY) .bind(after_timestamp) .bind(uids) .fetch(ex) @@ -866,41 +954,47 @@ pub async fn user_orders_with_quote( min_valid_to: i64, owner: &Address, ) -> Result, sqlx::Error> { - // Same functionality as OPEN_ORDERS but not optimized to fetch all live orders - // at once. Performs better when used with filtering by user. + // Optimized version following the same pattern as OPEN_ORDERS #[rustfmt::skip] - const OPEN_ORDERS_EMBEDDABLE: &str = const_format::concatcp!( - "SELECT * FROM ( ", - "SELECT ", SELECT, - " FROM ", FROM, - " LEFT OUTER JOIN ethflow_orders eth_o on eth_o.uid = o.uid ", - " WHERE o.valid_to >= $1", - " AND CASE WHEN eth_o.valid_to IS NULL THEN true ELSE eth_o.valid_to >= $1 END", - r#") AS unfiltered - WHERE - CASE kind - WHEN 'sell' THEN sum_sell < sell_amount - WHEN 'buy' THEN sum_buy < buy_amount - END AND - (NOT invalidated) AND - (onchain_placement_error IS NULL) - "#); - - #[rustfmt::skip] - const QUERY: &str = const_format::concatcp!( - "SELECT o_quotes.sell_amount as quote_sell_amount, o.sell_amount as order_sell_amount,", - " o_quotes.buy_amount as quote_buy_amount, o.buy_amount as order_buy_amount,", - " o.kind as order_kind, o_quotes.gas_amount as quote_gas_amount,", - " o_quotes.gas_price as quote_gas_price, o_quotes.sell_token_price as quote_sell_token_price", - " FROM (", - " SELECT *", - " FROM (", OPEN_ORDERS_EMBEDDABLE, - " AND owner = $2", - " AND class = 'limit'", - " ) AS subquery", - " ) AS o", - " INNER JOIN order_quotes o_quotes ON o.uid = o_quotes.order_uid" - ); + const QUERY: &str = r#" +WITH live_orders AS ( + SELECT o.* + FROM orders o + LEFT JOIN ethflow_orders e ON e.uid = o.uid + WHERE o.cancellation_timestamp IS NULL + AND o.valid_to >= $1 + AND (e.valid_to IS NULL OR e.valid_to >= $1) + AND NOT EXISTS (SELECT 1 FROM invalidations i WHERE i.order_uid = o.uid) + AND NOT EXISTS (SELECT 1 FROM onchain_order_invalidations oi WHERE oi.uid = o.uid) + AND NOT EXISTS (SELECT 1 FROM onchain_placed_orders op WHERE op.uid = o.uid + AND op.placement_error IS NOT NULL) + AND o.owner = $2 + AND o.class = 'limit' +), +trades_agg AS ( + SELECT t.order_uid, + SUM(t.buy_amount) AS sum_buy, + SUM(t.sell_amount) AS sum_sell, + SUM(t.fee_amount) AS sum_fee + FROM trades t + JOIN live_orders lo ON lo.uid = t.order_uid + GROUP BY t.order_uid +) +SELECT + o_quotes.sell_amount as quote_sell_amount, + lo.sell_amount as order_sell_amount, + o_quotes.buy_amount as quote_buy_amount, + lo.buy_amount as order_buy_amount, + lo.kind as order_kind, + o_quotes.gas_amount as quote_gas_amount, + o_quotes.gas_price as quote_gas_price, + o_quotes.sell_token_price as quote_sell_token_price +FROM live_orders lo +LEFT JOIN trades_agg ta ON ta.order_uid = lo.uid +INNER JOIN order_quotes o_quotes ON lo.uid = o_quotes.order_uid +WHERE ((lo.kind = 'sell' AND COALESCE(ta.sum_sell,0) < lo.sell_amount) OR + (lo.kind = 'buy' AND COALESCE(ta.sum_buy ,0) < lo.buy_amount)) +"#; sqlx::query_as::<_, OrderWithQuote>(QUERY) .bind(min_valid_to) .bind(owner) From 914d13250284ab57806cb2500c1c190bc99c06d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Tue, 25 Nov 2025 10:40:48 +0000 Subject: [PATCH 006/470] Migrate orderbook::orderbook to alloy (#3911) # Description Migrate orderbook::orderbook to alloy (short and sweet) # Changes - [ ] Migrates the old bindings to alloy ## How to test --- crates/orderbook/src/orderbook.rs | 15 +++++++-------- crates/orderbook/src/run.rs | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/orderbook/src/orderbook.rs b/crates/orderbook/src/orderbook.rs index 6d33bf29e0..3677b18c4a 100644 --- a/crates/orderbook/src/orderbook.rs +++ b/crates/orderbook/src/orderbook.rs @@ -13,7 +13,7 @@ use { bigdecimal::ToPrimitive, chrono::Utc, database::order_events::OrderEventLabel, - ethrpc::alloy::conversions::IntoLegacy, + ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, model::{ DomainSeparator, order::{ @@ -29,7 +29,6 @@ use { solver_competition::{self, SolverCompetitionAPI}, }, observe::metrics::LivenessChecking, - primitive_types::H160, shared::{ fee::FeeParameters, order_quoting::Quote, @@ -217,21 +216,21 @@ pub enum OrderReplacementError { #[derive(Debug)] pub struct QuoteMetadata { pub id: Option, - pub solver: H160, + pub solver: Address, } impl From<&Quote> for QuoteMetadata { fn from(value: &Quote) -> Self { Self { id: value.id, - solver: value.data.solver, + solver: value.data.solver.into_alloy(), } } } pub struct Orderbook { domain_separator: DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, database: crate::database::Postgres, database_replica: crate::database::Postgres, order_validator: Arc, @@ -242,7 +241,7 @@ pub struct Orderbook { impl Orderbook { pub fn new( domain_separator: DomainSeparator, - settlement_contract: H160, + settlement_contract: Address, database: crate::database::Postgres, database_replica: crate::database::Postgres, order_validator: Arc, @@ -287,7 +286,7 @@ impl Orderbook { .validate_and_construct_order( payload, &self.domain_separator, - self.settlement_contract, + self.settlement_contract.into_legacy(), full_app_data_override, ) .await?; @@ -706,7 +705,7 @@ mod tests { database_replica, order_validator: Arc::new(order_validator), domain_separator: Default::default(), - settlement_contract: H160([0xba; 20]), + settlement_contract: Address::repeat_byte(0xba), app_data, active_order_competition_threshold: Default::default(), }; diff --git a/crates/orderbook/src/run.rs b/crates/orderbook/src/run.rs index cff280fe87..43bea7eec5 100644 --- a/crates/orderbook/src/run.rs +++ b/crates/orderbook/src/run.rs @@ -447,7 +447,7 @@ pub async fn run(args: Arguments) { )); let orderbook = Arc::new(Orderbook::new( domain_separator, - settlement_contract.address().into_legacy(), + *settlement_contract.address(), postgres_write.clone(), postgres_read.clone(), order_validator.clone(), From 3d88f35f3595008860d651a3a541e95298ea9c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Tue, 25 Nov 2025 11:54:03 +0000 Subject: [PATCH 007/470] Migrate orderbook::quoter into alloy (#3916) # Description Migrate orderbook::quoter into alloy, sets up more structures to migrate the QuoteData # Changes - [ ] Removes the import for ethcontract in the quoter - [ ] Adds the respective alloy types - [ ] Migrates the rest of the module ## How to test Existing tests --- crates/orderbook/src/quoter.rs | 77 ++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/crates/orderbook/src/quoter.rs b/crates/orderbook/src/quoter.rs index 489ad669f6..391ca35af4 100644 --- a/crates/orderbook/src/quoter.rs +++ b/crates/orderbook/src/quoter.rs @@ -3,12 +3,13 @@ use { app_data, arguments::{FeeFactor, VolumeFeeConfig}, }, + alloy::primitives::{U256, U512, Uint, ruint::UintTryFrom}, chrono::{TimeZone, Utc}, + ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, model::{ order::OrderCreationAppData, quote::{OrderQuote, OrderQuoteRequest, OrderQuoteResponse, OrderQuoteSide, PriceQuality}, }, - primitive_types::U256, shared::{ order_quoting::{CalculateQuoteError, OrderQuoting, Quote, QuoteParameters}, order_validation::{ @@ -131,8 +132,8 @@ impl QuoteHandler { sell_token: request.sell_token, buy_token: request.buy_token, receiver: request.receiver, - sell_amount: adjusted_quote.sell_amount, - buy_amount: adjusted_quote.buy_amount, + sell_amount: adjusted_quote.sell_amount.into_legacy(), + buy_amount: adjusted_quote.buy_amount.into_legacy(), valid_to, app_data: match &request.app_data { OrderCreationAppData::Full { full } => OrderCreationAppData::Both { @@ -172,8 +173,8 @@ fn get_adjusted_quote_data( .and_then(|config| config.factor) else { return Ok(AdjustedQuoteData { - sell_amount: quote.sell_amount, - buy_amount: quote.buy_amount, + sell_amount: quote.sell_amount.into_alloy(), + buy_amount: quote.buy_amount.into_alloy(), protocol_fee_bps: None, }); }; @@ -183,34 +184,38 @@ fn get_adjusted_quote_data( let (adjusted_sell_amount, adjusted_buy_amount) = match side { OrderQuoteSide::Sell { .. } => { // For SELL orders, fee is calculated on buy amount - let protocol_fee = quote - .buy_amount - .full_mul(U256::from(factor.to_bps())) - .checked_div(U256::from(FeeFactor::MAX_BPS).into()) - .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))? - .try_into() - .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; + let protocol_fee = U256::uint_try_from( + quote + .buy_amount + .into_alloy() + .widening_mul(U256::from(factor.to_bps())) + .checked_div(U512::from(FeeFactor::MAX_BPS)) + .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))?, + ) + .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; // Reduce buy amount by protocol fee - let adjusted_buy = quote.buy_amount.saturating_sub(protocol_fee); + let adjusted_buy = quote.buy_amount.into_alloy().saturating_sub(protocol_fee); - (quote.sell_amount, adjusted_buy) + (quote.sell_amount.into_alloy(), adjusted_buy) } OrderQuoteSide::Buy { .. } => { // For BUY orders, fee is calculated on sell amount + network fee. // Network fee is already in sell token, so it is added to get the total volume. let total_sell_volume = quote.sell_amount.saturating_add(quote.fee_amount); - let protocol_fee = total_sell_volume - .full_mul(U256::from(factor.to_bps())) - .checked_div(U256::from(FeeFactor::MAX_BPS).into()) - .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))? - .try_into() - .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; + let factor = U256::from(factor.to_bps()); + let volume_bps: Uint<512, 8> = total_sell_volume.into_alloy().widening_mul(factor); + let protocol_fee = U256::uint_try_from( + volume_bps + .checked_div(U512::from(FeeFactor::MAX_BPS)) + .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))?, + ) + .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; // Increase sell amount by protocol fee - let adjusted_sell = quote.sell_amount.saturating_add(protocol_fee); + let adjusted_sell = quote.sell_amount.into_alloy().saturating_add(protocol_fee); - (adjusted_sell, quote.buy_amount) + (adjusted_sell, quote.buy_amount.into_alloy()) } }; @@ -251,8 +256,8 @@ mod tests { use { super::*, crate::arguments::FeeFactor, + alloy::primitives::U256, model::quote::OrderQuoteSide, - primitive_types::U256, shared::order_quoting::{Quote, QuoteData}, }; @@ -266,8 +271,8 @@ mod tests { data: QuoteData { sell_token: Default::default(), buy_token: Default::default(), - quoted_sell_amount: sell_amount, - quoted_buy_amount: buy_amount, + quoted_sell_amount: sell_amount.into_legacy(), + quoted_buy_amount: buy_amount.into_legacy(), fee_parameters: Default::default(), kind: model::order::OrderKind::Sell, expiration: chrono::Utc::now(), @@ -276,9 +281,9 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount, - buy_amount, - fee_amount: U256::zero(), + sell_amount: sell_amount.into_legacy(), + buy_amount: buy_amount.into_legacy(), + fee_amount: U256::ZERO.into_legacy(), } } @@ -294,7 +299,7 @@ mod tests { let quote = create_test_quote(to_wei(100), to_wei(100)); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::U256::try_from(to_wei(100).into_legacy()).unwrap(), }, }; @@ -326,7 +331,8 @@ mod tests { // Buying 100 tokens, expecting to sell 100 tokens, with no network fee let quote = create_test_quote(to_wei(100), to_wei(100)); let side = OrderQuoteSide::Buy { - buy_amount_after_fee: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + buy_amount_after_fee: number::nonzero::U256::try_from(to_wei(100).into_legacy()) + .unwrap(), }; let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); @@ -354,9 +360,10 @@ mod tests { // Buying 100 tokens, expecting to sell 100 tokens, with 5 token network fee let mut quote = create_test_quote(to_wei(100), to_wei(100)); - quote.fee_amount = to_wei(5); // Network fee in sell token + quote.fee_amount = to_wei(5).into_legacy(); // Network fee in sell token let side = OrderQuoteSide::Buy { - buy_amount_after_fee: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + buy_amount_after_fee: number::nonzero::U256::try_from(to_wei(100).into_legacy()) + .unwrap(), }; let result = get_adjusted_quote_data("e, Some(&volume_fee_config), &side).unwrap(); @@ -390,7 +397,7 @@ mod tests { let quote = create_test_quote(to_wei(100), to_wei(200)); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::U256::try_from(to_wei(100).into_legacy()).unwrap(), }, }; @@ -424,7 +431,7 @@ mod tests { let quote = create_test_quote(to_wei(100), to_wei(100)); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::U256::try_from(to_wei(100).into_legacy()).unwrap(), }, }; @@ -447,7 +454,7 @@ mod tests { let quote = create_test_quote(to_wei(100), to_wei(100)); let side = OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::BeforeFee { - value: number::nonzero::U256::try_from(to_wei(100)).unwrap(), + value: number::nonzero::U256::try_from(to_wei(100).into_legacy()).unwrap(), }, }; From b750662add05dd145b0945174ff4c31afcf8d83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Tue, 25 Nov 2025 13:47:40 +0000 Subject: [PATCH 008/470] Migrate QuoteSearchParameters into alloy (#3917) # Description Migrate QuoteSearchParameters into alloy # Changes - [ ] Replaces the old types in the QuoteSearchParameters with the alloy types - [ ] Refactors the remaining code ## How to test Existing tests --- .../src/database/onchain_order_events/mod.rs | 10 +-- crates/shared/src/event_storing_helpers.rs | 11 ++-- crates/shared/src/order_quoting.rs | 65 ++++++++++--------- crates/shared/src/order_validation.rs | 51 ++++++++------- 4 files changed, 74 insertions(+), 63 deletions(-) diff --git a/crates/autopilot/src/database/onchain_order_events/mod.rs b/crates/autopilot/src/database/onchain_order_events/mod.rs index 52d9d578b5..222a31a145 100644 --- a/crates/autopilot/src/database/onchain_order_events/mod.rs +++ b/crates/autopilot/src/database/onchain_order_events/mod.rs @@ -550,11 +550,11 @@ async fn get_quote( .map_err(|_| OnchainOrderPlacementError::Other)?; let parameters = QuoteSearchParameters { - sell_token: order_data.sell_token.into_legacy(), - buy_token: order_data.buy_token.into_legacy(), - sell_amount: order_data.sell_amount.into_legacy(), - buy_amount: order_data.buy_amount.into_legacy(), - fee_amount: order_data.fee_amount.into_legacy(), + sell_token: order_data.sell_token, + buy_token: order_data.buy_token, + sell_amount: order_data.sell_amount, + buy_amount: order_data.buy_amount, + fee_amount: order_data.fee_amount, kind: order_data.kind, signing_scheme: quote_signing_scheme, additional_gas: 0, diff --git a/crates/shared/src/event_storing_helpers.rs b/crates/shared/src/event_storing_helpers.rs index aa43a0e0d1..635b3eb29f 100644 --- a/crates/shared/src/event_storing_helpers.rs +++ b/crates/shared/src/event_storing_helpers.rs @@ -9,6 +9,7 @@ use { byte_array::ByteArray, quotes::{Quote as DbQuote, QuoteSearchParameters as DbQuoteSearchParameters}, }, + ethrpc::alloy::conversions::IntoLegacy, number::conversions::u256_to_big_decimal, }; @@ -36,11 +37,11 @@ pub fn create_db_search_parameters( expiration: DateTime, ) -> DbQuoteSearchParameters { DbQuoteSearchParameters { - sell_token: ByteArray(params.sell_token.0), - buy_token: ByteArray(params.buy_token.0), - sell_amount_0: u256_to_big_decimal(¶ms.sell_amount), - sell_amount_1: u256_to_big_decimal(&(params.sell_amount + params.fee_amount)), - buy_amount: u256_to_big_decimal(¶ms.buy_amount), + sell_token: ByteArray(*params.sell_token.0), + buy_token: ByteArray(*params.buy_token.0), + sell_amount_0: u256_to_big_decimal(¶ms.sell_amount.into_legacy()), + sell_amount_1: u256_to_big_decimal(&(params.sell_amount + params.fee_amount).into_legacy()), + buy_amount: u256_to_big_decimal(¶ms.buy_amount.into_legacy()), kind: order_kind_into(params.kind), expiration, quote_kind: quote_kind_from_signing_scheme(¶ms.signing_scheme), diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 383706df22..1fff06e755 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -13,11 +13,12 @@ use { price_estimation::{Estimate, QuoteVerificationMode, Verification}, trade_finding::external::dto, }, + alloy::primitives::Address, anyhow::{Context, Result}, chrono::{DateTime, Duration, Utc}, database::quotes::{Quote as QuoteRow, QuoteKind}, ethcontract::{H160, U256}, - ethrpc::alloy::conversions::IntoAlloy, + ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::TryFutureExt, gas_estimation::GasPriceEstimating, model::{ @@ -311,11 +312,11 @@ pub enum FindQuoteError { /// Fields for searching stored quotes. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct QuoteSearchParameters { - pub sell_token: H160, - pub buy_token: H160, - pub sell_amount: U256, - pub buy_amount: U256, - pub fee_amount: U256, + pub sell_token: Address, + pub buy_token: Address, + pub sell_amount: alloy::primitives::U256, + pub buy_amount: alloy::primitives::U256, + pub fee_amount: alloy::primitives::U256, pub kind: OrderKind, pub signing_scheme: QuoteSigningScheme, pub additional_gas: u64, @@ -327,16 +328,20 @@ impl QuoteSearchParameters { /// quote data. fn matches(&self, data: &QuoteData) -> bool { let amounts_match = match self.kind { - OrderKind::Buy => self.buy_amount == data.quoted_buy_amount, + OrderKind::Buy => self.buy_amount == data.quoted_buy_amount.into_alloy(), OrderKind::Sell => { - self.sell_amount == data.quoted_sell_amount - || self.sell_amount + self.fee_amount == data.quoted_sell_amount + self.sell_amount == data.quoted_sell_amount.into_alloy() + || self.sell_amount + self.fee_amount == data.quoted_sell_amount.into_alloy() } }; amounts_match && (self.sell_token, self.buy_token, self.kind) - == (data.sell_token, data.buy_token, data.kind) + == ( + data.sell_token.into_alloy(), + data.buy_token.into_alloy(), + data.kind, + ) } /// Returns additional gas costs incurred by the quote. @@ -669,7 +674,7 @@ impl OrderQuoting for OrderQuoter { .with_additional_cost(additional_cost); let quote = match scaled_sell_amount { - Some(sell_amount) => quote.with_scaled_sell_amount(sell_amount), + Some(sell_amount) => quote.with_scaled_sell_amount(sell_amount.into_legacy()), None => quote, }; @@ -861,7 +866,7 @@ mod tests { from: H160([3; 20]), ..Default::default() }, - sell_token: Address::new([1; 20]), + sell_token: Address::repeat_byte(1), buy_token: Address::new([2; 20]), in_amount: NonZeroU256::try_from(100).unwrap(), kind: OrderKind::Sell, @@ -1002,7 +1007,7 @@ mod tests { from: H160([3; 20]), ..Default::default() }, - sell_token: Address::new([1; 20]), + sell_token: Address::repeat_byte(1), buy_token: Address::new([2; 20]), in_amount: NonZeroU256::try_from(100).unwrap(), kind: OrderKind::Sell, @@ -1138,7 +1143,7 @@ mod tests { from: H160([3; 20]), ..Default::default() }, - sell_token: Address::new([1; 20]), + sell_token: Address::repeat_byte(1), buy_token: Address::new([2; 20]), in_amount: NonZeroU256::try_from(42).unwrap(), kind: OrderKind::Buy, @@ -1398,11 +1403,11 @@ mod tests { let now = Utc::now(); let quote_id = 42; let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 85.into(), - buy_amount: 40.into(), - fee_amount: 15.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(85), + buy_amount: alloy::primitives::U256::from(40), + fee_amount: alloy::primitives::U256::from(15), kind: OrderKind::Sell, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, @@ -1481,11 +1486,11 @@ mod tests { let now = Utc::now(); let quote_id = 42; let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 100.into(), - buy_amount: 40.into(), - fee_amount: 30.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(100), + buy_amount: alloy::primitives::U256::from(40), + fee_amount: alloy::primitives::U256::from(30), kind: OrderKind::Sell, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, @@ -1560,11 +1565,11 @@ mod tests { async fn finds_quote_by_parameters() { let now = Utc::now(); let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 110.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(110), + buy_amount: alloy::primitives::U256::from(42), + fee_amount: alloy::primitives::U256::from(30), kind: OrderKind::Buy, signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, @@ -1645,7 +1650,7 @@ mod tests { async fn find_invalid_quote_error() { let now = Utc::now(); let parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), + sell_token: Address::repeat_byte(1), ..Default::default() }; diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index 89c25eefa2..38e6b442f4 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -645,11 +645,11 @@ impl OrderValidating for OrderValidator { }; let quote_parameters = QuoteSearchParameters { - sell_token: data.sell_token.into_legacy(), - buy_token: data.buy_token.into_legacy(), - sell_amount: data.sell_amount.into_legacy(), - buy_amount: data.buy_amount.into_legacy(), - fee_amount: data.fee_amount.into_legacy(), + sell_token: data.sell_token, + buy_token: data.buy_token, + sell_amount: data.sell_amount, + buy_amount: data.buy_amount, + fee_amount: data.fee_amount, kind: data.kind, signing_scheme: convert_signing_scheme_into_quote_signing_scheme( order.signature.scheme(), @@ -903,12 +903,13 @@ async fn get_or_create_quote( Err(err) => { tracing::debug!(?err, "failed to find quote for order creation"); let parameters = QuoteParameters { - sell_token: quote_search_parameters.sell_token, - buy_token: quote_search_parameters.buy_token, + sell_token: quote_search_parameters.sell_token.into_legacy(), + buy_token: quote_search_parameters.buy_token.into_legacy(), side: match quote_search_parameters.kind { OrderKind::Buy => OrderQuoteSide::Buy { buy_amount_after_fee: quote_search_parameters .buy_amount + .into_legacy() .try_into() .map_err(|_| ValidationError::ZeroAmount)?, }, @@ -916,6 +917,7 @@ async fn get_or_create_quote( sell_amount: SellAmount::AfterFee { value: quote_search_parameters .sell_amount + .into_legacy() .try_into() .map_err(|_| ValidationError::ZeroAmount)?, }, @@ -2242,11 +2244,11 @@ mod tests { async fn get_quote_find_by_id() { let mut order_quoter = MockOrderQuoting::new(); let quote_search_parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 3.into(), - buy_amount: 4.into(), - fee_amount: 0.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(3), + buy_amount: alloy::primitives::U256::from(4), + fee_amount: alloy::primitives::U256::from(0), kind: OrderKind::Buy, signing_scheme: QuoteSigningScheme::Eip1271 { onchain_order: true, @@ -2300,9 +2302,9 @@ mod tests { .with(eq(None), always()) .returning(|_, _| Err(FindQuoteError::NotFound(None))); let quote_search_parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 3.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(3), kind: OrderKind::Sell, verification: verification.clone(), ..Default::default() @@ -2315,11 +2317,14 @@ mod tests { order_quoter .expect_calculate_quote() .with(eq(QuoteParameters { - sell_token: quote_search_parameters.sell_token, - buy_token: quote_search_parameters.buy_token, + sell_token: quote_search_parameters.sell_token.into_legacy(), + buy_token: quote_search_parameters.buy_token.into_legacy(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { - value: NonZeroU256::try_from(quote_search_parameters.sell_amount).unwrap(), + value: NonZeroU256::try_from( + quote_search_parameters.sell_amount.into_legacy(), + ) + .unwrap(), }, }, verification, @@ -2471,11 +2476,11 @@ mod tests { async fn validate_quote_find_by_id() { let mut order_quoter = MockOrderQuoting::new(); let quote_search_parameters = QuoteSearchParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - sell_amount: 3.into(), - buy_amount: 4.into(), - fee_amount: 0.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + sell_amount: alloy::primitives::U256::from(3), + buy_amount: alloy::primitives::U256::from(4), + fee_amount: alloy::primitives::U256::from(0), kind: OrderKind::Buy, signing_scheme: QuoteSigningScheme::Eip1271 { onchain_order: false, From a9b6dcbbcee4cf6acb33615c5b61f9fb194fdb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Tue, 25 Nov 2025 14:10:12 +0000 Subject: [PATCH 009/470] Migrate EthflowData into alloy (#3919) # Description Migrate EthflowData into alloy # Changes - [ ] Migrate EthflowData into alloy - [ ] Refactor where applicable ## How to test Existing tests --- crates/model/src/order.rs | 6 +++--- crates/orderbook/src/database/orders.rs | 3 +-- crates/shared/src/db_order_conversions.rs | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/crates/model/src/order.rs b/crates/model/src/order.rs index 6956711176..e9649ebd3b 100644 --- a/crates/model/src/order.rs +++ b/crates/model/src/order.rs @@ -9,7 +9,7 @@ use { quote::QuoteId, signature::{self, EcdsaSignature, EcdsaSigningScheme, Signature}, }, - alloy::primitives::{Address, U512}, + alloy::primitives::{Address, B256, U512}, anyhow::{Result, anyhow}, app_data::{AppDataHash, hash_full_app_data}, bigdecimal::BigDecimal, @@ -647,7 +647,7 @@ pub struct CancellationPayload { #[serde(rename_all = "camelCase")] pub struct EthflowData { pub user_valid_to: i64, - pub refund_tx_hash: Option, + pub refund_tx_hash: Option, } // We still want to have the `is_refunded` field in the JSON response to stay @@ -663,7 +663,7 @@ impl ::serde::Serialize for EthflowData { #[serde(rename_all = "camelCase")] struct Extended { user_valid_to: i64, - refund_tx_hash: Option, + refund_tx_hash: Option, is_refunded: bool, } diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index bbc424b2b6..669dca9643 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -12,7 +12,6 @@ use { order_events::{OrderEvent, OrderEventLabel, insert_order_event}, orders::{self, FullOrder, OrderKind as DbOrderKind}, }, - ethcontract::H256, ethrpc::alloy::conversions::IntoLegacy, futures::{FutureExt, StreamExt, stream::TryStreamExt}, model::{ @@ -538,7 +537,7 @@ fn full_order_with_quote_into_model_order( let ethflow_data = if let Some((refund_tx, user_valid_to)) = order.ethflow_data { Some(EthflowData { user_valid_to, - refund_tx_hash: refund_tx.map(|hash| H256(hash.0)), + refund_tx_hash: refund_tx.map(|hash| B256::new(hash.0)), }) } else { None diff --git a/crates/shared/src/db_order_conversions.rs b/crates/shared/src/db_order_conversions.rs index 87471cd992..7565a72536 100644 --- a/crates/shared/src/db_order_conversions.rs +++ b/crates/shared/src/db_order_conversions.rs @@ -1,5 +1,5 @@ use { - alloy::primitives::Address, + alloy::primitives::{Address, B256}, anyhow::{Context, Result}, app_data::AppDataHash, bigdecimal::BigDecimal, @@ -15,7 +15,7 @@ use { SigningScheme as DbSigningScheme, }, }, - ethcontract::{H160, H256}, + ethcontract::H160, ethrpc::alloy::conversions::IntoAlloy, model::{ interaction::InteractionData, @@ -56,7 +56,7 @@ pub fn full_order_into_model_order(order: database::orders::FullOrder) -> Result let ethflow_data = if let Some((refund_tx, user_valid_to)) = order.ethflow_data { Some(EthflowData { user_valid_to, - refund_tx_hash: refund_tx.map(|hash| H256::from(hash.0)), + refund_tx_hash: refund_tx.map(|hash| B256::from(hash.0)), }) } else { None From 088f737244c974eee2b254a5b449ec7dd2e11008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Tue, 25 Nov 2025 14:58:43 +0000 Subject: [PATCH 010/470] Migrate QuoteData to alloy (#3918) # Description Migrate QuoteData to alloy # Changes - [ ] Migrates the QuoteData struct to alloy - [ ] Refactors where applicable ## How to test Existing tests --- .../src/database/onchain_order_events/mod.rs | 15 +- crates/orderbook/src/orderbook.rs | 4 +- crates/orderbook/src/quoter.rs | 4 +- crates/shared/src/event_storing_helpers.rs | 10 +- crates/shared/src/order_quoting.rs | 186 +++++++++--------- 5 files changed, 109 insertions(+), 110 deletions(-) diff --git a/crates/autopilot/src/database/onchain_order_events/mod.rs b/crates/autopilot/src/database/onchain_order_events/mod.rs index 222a31a145..3e52675088 100644 --- a/crates/autopilot/src/database/onchain_order_events/mod.rs +++ b/crates/autopilot/src/database/onchain_order_events/mod.rs @@ -501,7 +501,7 @@ where sell_token_price: quote.data.fee_parameters.sell_token_price, sell_amount: u256_to_big_decimal("e.sell_amount), buy_amount: u256_to_big_decimal("e.buy_amount), - solver: ByteArray(quote.data.solver.0), + solver: ByteArray(*quote.data.solver.0), verified: quote.data.verified, metadata: quote.data.metadata.try_into()?, }), @@ -1212,13 +1212,10 @@ mod test { let quote = Quote { id: Some(0i64), data: QuoteData { - sell_token: sell_token.into_legacy(), - buy_token: buy_token.into_legacy(), - quoted_sell_amount: sell_amount - .checked_sub(U256::from(1)) - .unwrap() - .into_legacy(), - quoted_buy_amount: buy_amount.checked_sub(U256::from(1)).unwrap().into_legacy(), + sell_token, + buy_token, + quoted_sell_amount: sell_amount.checked_sub(U256::from(1)).unwrap(), + quoted_buy_amount: buy_amount.checked_sub(U256::from(1)).unwrap(), fee_parameters: FeeParameters { gas_amount: 2.0f64, gas_price: 3.0f64, @@ -1306,7 +1303,7 @@ mod test { sell_token_price: quote.data.fee_parameters.sell_token_price, sell_amount: u256_to_big_decimal("e.sell_amount), buy_amount: u256_to_big_decimal("e.buy_amount), - solver: ByteArray(quote.data.solver.0), + solver: ByteArray(*quote.data.solver.0), verified: quote.data.verified, metadata: quote.data.metadata.try_into().unwrap(), }; diff --git a/crates/orderbook/src/orderbook.rs b/crates/orderbook/src/orderbook.rs index 3677b18c4a..c080739f4a 100644 --- a/crates/orderbook/src/orderbook.rs +++ b/crates/orderbook/src/orderbook.rs @@ -13,7 +13,7 @@ use { bigdecimal::ToPrimitive, chrono::Utc, database::order_events::OrderEventLabel, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethrpc::alloy::conversions::IntoLegacy, model::{ DomainSeparator, order::{ @@ -223,7 +223,7 @@ impl From<&Quote> for QuoteMetadata { fn from(value: &Quote) -> Self { Self { id: value.id, - solver: value.data.solver.into_alloy(), + solver: value.data.solver, } } } diff --git a/crates/orderbook/src/quoter.rs b/crates/orderbook/src/quoter.rs index 391ca35af4..d09a939038 100644 --- a/crates/orderbook/src/quoter.rs +++ b/crates/orderbook/src/quoter.rs @@ -271,8 +271,8 @@ mod tests { data: QuoteData { sell_token: Default::default(), buy_token: Default::default(), - quoted_sell_amount: sell_amount.into_legacy(), - quoted_buy_amount: buy_amount.into_legacy(), + quoted_sell_amount: sell_amount, + quoted_buy_amount: buy_amount, fee_parameters: Default::default(), kind: model::order::OrderKind::Sell, expiration: chrono::Utc::now(), diff --git a/crates/shared/src/event_storing_helpers.rs b/crates/shared/src/event_storing_helpers.rs index 635b3eb29f..0734413029 100644 --- a/crates/shared/src/event_storing_helpers.rs +++ b/crates/shared/src/event_storing_helpers.rs @@ -16,17 +16,17 @@ use { pub fn create_quote_row(data: QuoteData) -> Result { Ok(DbQuote { id: Default::default(), - sell_token: ByteArray(data.sell_token.0), - buy_token: ByteArray(data.buy_token.0), - sell_amount: u256_to_big_decimal(&data.quoted_sell_amount), - buy_amount: u256_to_big_decimal(&data.quoted_buy_amount), + sell_token: ByteArray(*data.sell_token.0), + buy_token: ByteArray(*data.buy_token.0), + sell_amount: u256_to_big_decimal(&data.quoted_sell_amount.into_legacy()), + buy_amount: u256_to_big_decimal(&data.quoted_buy_amount.into_legacy()), gas_amount: data.fee_parameters.gas_amount, gas_price: data.fee_parameters.gas_price, sell_token_price: data.fee_parameters.sell_token_price, order_kind: order_kind_into(data.kind), expiration_timestamp: data.expiration, quote_kind: data.quote_kind, - solver: ByteArray(data.solver.0), + solver: ByteArray(*data.solver.0), verified: data.verified, metadata: data.metadata.try_into()?, }) diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 1fff06e755..45484d85c0 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -111,8 +111,8 @@ impl Quote { pub fn new(id: Option, data: QuoteData) -> Self { Self { id, - sell_amount: data.quoted_sell_amount, - buy_amount: data.quoted_buy_amount, + sell_amount: data.quoted_sell_amount.into_legacy(), + buy_amount: data.quoted_buy_amount.into_legacy(), fee_amount: data.fee_parameters.fee(), data, } @@ -145,10 +145,14 @@ impl Quote { self.sell_amount = sell_amount; // Use `full_mul: (U256, U256) -> U512` to avoid any overflow // errors computing the initial product. - self.buy_amount = (self.data.quoted_buy_amount.full_mul(sell_amount) - / self.data.quoted_sell_amount) - .try_into() - .unwrap_or(U256::MAX); + self.buy_amount = (self + .data + .quoted_buy_amount + .into_legacy() + .full_mul(sell_amount) + / self.data.quoted_sell_amount.into_legacy()) + .try_into() + .unwrap_or(U256::MAX); self } @@ -166,7 +170,7 @@ impl Quote { .context("sell token price is not a valid BigDecimal")?, sell_amount: self.sell_amount, buy_amount: self.buy_amount, - solver: self.data.solver, + solver: self.data.solver.into_legacy(), verified: self.data.verified, metadata: serde_json::to_value(&self.data.metadata)?, }) @@ -176,8 +180,8 @@ impl Quote { /// Detailed data for a computed order quote. #[derive(Clone, Debug, Default, PartialEq)] pub struct QuoteData { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, /// The sell amount used when computing the exchange rate for this quote. /// /// For buy orders, this will be the expected sell amount for some fixed @@ -185,7 +189,7 @@ pub struct QuoteData { /// will be the total `sell_amount + fee_amount`. For sell orders of the /// `SellAmount::AfterFee` variant, this will be the fixed sell amount of /// the order used for price estimates. - pub quoted_sell_amount: U256, + pub quoted_sell_amount: alloy::primitives::U256, /// The buy amount used when computing the exchange rate for this quote. /// /// For buy orders, this will be the fixed buy amount. For sell order of the @@ -193,7 +197,7 @@ pub struct QuoteData { /// `sell_amount + fee_amount` were traded. For sell orders of the /// `SellAmount::AfterFee` variant, this will be the expected sell amount if /// exactly `sell_amount` were traded. - pub quoted_buy_amount: U256, + pub quoted_buy_amount: alloy::primitives::U256, pub fee_parameters: FeeParameters, pub kind: OrderKind, pub expiration: DateTime, @@ -201,7 +205,7 @@ pub struct QuoteData { /// we need to store the quote kind to prevent missuse of quotes. pub quote_kind: QuoteKind, /// The address of the solver that provided the quote. - pub solver: H160, + pub solver: Address, /// Were we able to verify that this quote is accurate? pub verified: bool, /// Additional data associated with the quote. @@ -213,12 +217,14 @@ impl TryFrom for QuoteData { fn try_from(row: QuoteRow) -> Result { Ok(QuoteData { - sell_token: H160(row.sell_token.0), - buy_token: H160(row.buy_token.0), + sell_token: Address::from_slice(&row.sell_token.0), + buy_token: Address::from_slice(&row.buy_token.0), quoted_sell_amount: big_decimal_to_u256(&row.sell_amount) - .context("quoted sell amount is not a valid U256")?, + .context("quoted sell amount is not a valid U256")? + .into_alloy(), quoted_buy_amount: big_decimal_to_u256(&row.buy_amount) - .context("quoted buy amount is not a valid U256")?, + .context("quoted buy amount is not a valid U256")? + .into_alloy(), fee_parameters: FeeParameters { gas_amount: row.gas_amount, gas_price: row.gas_price, @@ -227,7 +233,7 @@ impl TryFrom for QuoteData { kind: order_kind_from(row.order_kind), expiration: row.expiration_timestamp, quote_kind: row.quote_kind, - solver: H160(row.solver.0), + solver: Address::from_slice(&row.solver.0), verified: row.verified, metadata: row.metadata.try_into()?, }) @@ -328,20 +334,16 @@ impl QuoteSearchParameters { /// quote data. fn matches(&self, data: &QuoteData) -> bool { let amounts_match = match self.kind { - OrderKind::Buy => self.buy_amount == data.quoted_buy_amount.into_alloy(), + OrderKind::Buy => self.buy_amount == data.quoted_buy_amount, OrderKind::Sell => { - self.sell_amount == data.quoted_sell_amount.into_alloy() - || self.sell_amount + self.fee_amount == data.quoted_sell_amount.into_alloy() + self.sell_amount == data.quoted_sell_amount + || self.sell_amount + self.fee_amount == data.quoted_sell_amount } }; amounts_match && (self.sell_token, self.buy_token, self.kind) - == ( - data.sell_token.into_alloy(), - data.buy_token.into_alloy(), - data.kind, - ) + == (data.sell_token, data.buy_token, data.kind) } /// Returns additional gas costs incurred by the quote. @@ -506,15 +508,15 @@ impl OrderQuoter { let quote_kind = quote_kind_from_signing_scheme(¶meters.signing_scheme); let quote = QuoteData { - sell_token: parameters.sell_token, - buy_token: parameters.buy_token, - quoted_sell_amount, - quoted_buy_amount, + sell_token: parameters.sell_token.into_alloy(), + buy_token: parameters.buy_token.into_alloy(), + quoted_sell_amount: quoted_sell_amount.into_alloy(), + quoted_buy_amount: quoted_buy_amount.into_alloy(), fee_parameters, kind: trade_query.kind, expiration, quote_kind, - solver: trade_estimate.solver, + solver: trade_estimate.solver.into_alloy(), verified: trade_estimate.verified, metadata: QuoteMetadataV1 { interactions: trade_estimate.execution.interactions, @@ -909,10 +911,10 @@ mod tests { storage .expect_save() .with(eq(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -921,7 +923,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -947,10 +949,10 @@ mod tests { Quote { id: Some(1337), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -959,7 +961,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1050,10 +1052,10 @@ mod tests { storage .expect_save() .with(eq(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1062,7 +1064,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1088,10 +1090,10 @@ mod tests { Quote { id: Some(1337), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1100,7 +1102,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1186,10 +1188,10 @@ mod tests { storage .expect_save() .with(eq(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1198,7 +1200,7 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1224,10 +1226,10 @@ mod tests { Quote { id: Some(1337), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1236,7 +1238,7 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(60i64), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1420,10 +1422,10 @@ mod tests { let mut storage = MockQuoteStoring::new(); storage.expect_get().with(eq(42)).returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1432,7 +1434,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1455,10 +1457,10 @@ mod tests { Quote { id: Some(42), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1467,7 +1469,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1503,10 +1505,10 @@ mod tests { let mut storage = MockQuoteStoring::new(); storage.expect_get().with(eq(42)).returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1515,7 +1517,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), })) @@ -1538,10 +1540,10 @@ mod tests { Quote { id: Some(42), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1550,7 +1552,7 @@ mod tests { kind: OrderKind::Sell, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1587,10 +1589,10 @@ mod tests { Ok(Some(( 42, QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1599,7 +1601,7 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1623,10 +1625,10 @@ mod tests { Quote { id: Some(42), data: QuoteData { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), - quoted_sell_amount: 100.into(), - quoted_buy_amount: 42.into(), + sell_token: Address::repeat_byte(1), + buy_token: Address::repeat_byte(2), + quoted_sell_amount: alloy::primitives::U256::from(100), + quoted_buy_amount: alloy::primitives::U256::from(42), fee_parameters: FeeParameters { gas_amount: 3., gas_price: 2., @@ -1635,7 +1637,7 @@ mod tests { kind: OrderKind::Buy, expiration: now + chrono::Duration::seconds(10), quote_kind: QuoteKind::Standard, - solver: H160([1; 20]), + solver: Address::repeat_byte(1), verified: false, metadata: Default::default(), }, @@ -1662,7 +1664,7 @@ mod tests { .in_sequence(&mut sequence) .returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([2; 20]), + sell_token: Address::repeat_byte(2), expiration: now, ..Default::default() })) @@ -1673,7 +1675,7 @@ mod tests { .in_sequence(&mut sequence) .returning(move |_| { Ok(Some(QuoteData { - sell_token: H160([1; 20]), + sell_token: Address::repeat_byte(1), expiration: now - chrono::Duration::seconds(1), ..Default::default() })) From 1ad74319905937fb4e67b29090bfbef90dec1848 Mon Sep 17 00:00:00 2001 From: ilya Date: Wed, 26 Nov 2025 11:29:30 +0000 Subject: [PATCH 011/470] Use `FuturesUnordered` when fetching COW AMM balances (#3924) # Description Fetching COW AMM token balances takes a lot of time on base due to a high number of AMMs. In order to speed things up a bit, it is suggested to use `FuturesUnordered`, which is a better approach than `FuturesOrdered`, which is used by `futures_util::future::join_all` when the number of futures exceeds 30. ## How to test Staging --- crates/cow-amm/src/maintainers.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/cow-amm/src/maintainers.rs b/crates/cow-amm/src/maintainers.rs index b5cd5b6a23..fe39199a65 100644 --- a/crates/cow-amm/src/maintainers.rs +++ b/crates/cow-amm/src/maintainers.rs @@ -2,7 +2,10 @@ use { crate::{Amm, cache::Storage}, contracts::alloy::ERC20, ethrpc::Web3, - futures::future::{join_all, select_ok}, + futures::{ + future::{join_all, select_ok}, + stream::{FuturesUnordered, StreamExt}, + }, shared::maintenance::Maintaining, std::sync::Arc, tokio::sync::RwLock, @@ -55,13 +58,20 @@ impl Maintaining for EmptyPoolRemoval { amms_to_check.extend(storage.cow_amms().await); } } - let futures = amms_to_check.iter().map(|amm| async { - self.has_zero_balance(amm.clone()) - .await - .then_some(*amm.address()) - }); - let empty_amms: Vec<_> = join_all(futures).await.into_iter().flatten().collect(); + let empty_amms: Vec<_> = amms_to_check + .iter() + .map(|amm| { + let amm = amm.clone(); + async move { + let address = *amm.address(); + self.has_zero_balance(amm).await.then_some(address) + } + }) + .collect::>() + .filter_map(std::future::ready) + .collect() + .await; if !empty_amms.is_empty() { tracing::debug!(amms = ?empty_amms, "removing AMMs with zero token balance"); let lock = self.storage.read().await; From 0c78a1c1211290f70bac039225edcf2b413ce851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Wed, 26 Nov 2025 11:58:25 +0000 Subject: [PATCH 012/470] [TRIVIAL] Migrate DTOs and validation to alloy types (#3920) ## Description This PR continues the migration from the `ethcontract` library to the `alloy` library by updating DTOs, database layer, and validation logic to use alloy primitive types. This is part of a larger effort to modernize the codebase's Ethereum interaction layer. The changes replace `primitive_types::{H160, U256}` with their alloy equivalents (`alloy::primitives::{Address, U256}`) across DTOs, API models, and validation traits, adding necessary type conversions where needed. ## Changes - [ ] Migrate `solver_competition` model types from H160/U256 to Address/alloy::U256 - [ ] Update autopilot run loop to use `IntoAlloy` conversions for solver settlement data - [ ] Migrate orderbook DTO types (Order, Quote, ExecutedAmounts, Auction) to alloy primitives - [ ] Update `LimitOrderCounting` trait to use `Address` instead of `H160` - [ ] Update database layer to use alloy-specific conversion functions - [ ] Add `.into_alloy()` conversions in order validation logic - [ ] Update test fixtures to use alloy constructors (`Address::repeat_byte`, `U256::from`) ## How to test Existing tests --------- Co-authored-by: Claude --- crates/autopilot/src/run_loop.rs | 15 +++++++----- crates/model/src/solver_competition.rs | 32 ++++++++++++------------- crates/orderbook/src/database/orders.rs | 9 ++++--- crates/orderbook/src/dto/auction.rs | 7 +++--- crates/orderbook/src/dto/mod.rs | 10 ++++---- crates/orderbook/src/dto/order.rs | 28 +++++++++++----------- crates/shared/src/order_validation.rs | 8 +++---- 7 files changed, 56 insertions(+), 53 deletions(-) diff --git a/crates/autopilot/src/run_loop.rs b/crates/autopilot/src/run_loop.rs index 24c196eaf6..5cfaa28a0b 100644 --- a/crates/autopilot/src/run_loop.rs +++ b/crates/autopilot/src/run_loop.rs @@ -29,7 +29,10 @@ use { ::observe::metrics, anyhow::{Context, Result}, database::order_events::OrderEventLabel, - ethrpc::{alloy::conversions::IntoLegacy, block_stream::BlockInfo}, + ethrpc::{ + alloy::conversions::{IntoAlloy, IntoLegacy}, + block_stream::BlockInfo, + }, futures::{FutureExt, TryFutureExt}, itertools::Itertools, model::solver_competition::{ @@ -468,7 +471,7 @@ impl RunLoop { .enumerated() .map(|(index, participant)| SolverSettlement { solver: participant.driver().name.clone(), - solver_address: participant.solution().solver().0, + solver_address: participant.solution().solver().0.into_alloy(), score: Some(Score::Solver(participant.solution().score().get().0)), ranking: index + 1, orders: participant @@ -477,15 +480,15 @@ impl RunLoop { .iter() .map(|(id, order)| Order::Colocated { id: (*id).into(), - sell_amount: order.executed_sell.into(), - buy_amount: order.executed_buy.into(), + sell_amount: order.executed_sell.0.into_alloy(), + buy_amount: order.executed_buy.0.into_alloy(), }) .collect(), clearing_prices: participant .solution() .prices() .iter() - .map(|(token, price)| (token.0, price.get().into())) + .map(|(token, price)| (token.0.into_alloy(), price.get().0.into_alloy())) .collect(), is_winner: participant.is_winner(), filtered_out: participant.filtered_out(), @@ -507,7 +510,7 @@ impl RunLoop { prices: auction .prices .iter() - .map(|(key, value)| ((*key).into(), value.get().into())) + .map(|(key, value)| (key.0.into_alloy(), value.get().0.into_alloy())) .collect(), }, solutions, diff --git a/crates/model/src/solver_competition.rs b/crates/model/src/solver_competition.rs index 6c5d80c6e8..56c101643f 100644 --- a/crates/model/src/solver_competition.rs +++ b/crates/model/src/solver_competition.rs @@ -1,8 +1,8 @@ use { crate::{AuctionId, order::OrderUid}, - alloy::primitives::B256, + alloy::primitives::{Address, B256}, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, + primitive_types::U256, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, @@ -36,7 +36,7 @@ pub struct SolverCompetitionAPI { pub struct CompetitionAuction { pub orders: Vec, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub prices: BTreeMap, + pub prices: BTreeMap, } #[serde_as] @@ -45,13 +45,13 @@ pub struct CompetitionAuction { pub struct SolverSettlement { pub solver: String, #[serde(default)] - pub solver_address: H160, + pub solver_address: Address, #[serde(flatten)] pub score: Option, #[serde(default)] pub ranking: usize, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub clearing_prices: BTreeMap, + pub clearing_prices: BTreeMap, pub orders: Vec, #[serde(default)] pub is_winner: bool, @@ -106,16 +106,16 @@ pub enum Order { id: OrderUid, /// The effective amount that left the user's wallet including all fees. #[serde_as(as = "HexOrDecimalU256")] - sell_amount: U256, + sell_amount: alloy::primitives::U256, /// The effective amount the user received after all fees. #[serde_as(as = "HexOrDecimalU256")] - buy_amount: U256, + buy_amount: alloy::primitives::U256, }, #[serde(rename_all = "camelCase")] Legacy { id: OrderUid, #[serde_as(as = "HexOrDecimalU256")] - executed_amount: U256, + executed_amount: alloy::primitives::U256, }, } @@ -189,28 +189,28 @@ mod tests { OrderUid([0x33; 56]), ], prices: btreemap! { - H160([0x11; 20]) => 1000.into(), - H160([0x22; 20]) => 2000.into(), - H160([0x33; 20]) => 3000.into(), + Address::repeat_byte(0x11) => alloy::primitives::U256::from(1000), + Address::repeat_byte(0x22) => alloy::primitives::U256::from(2000), + Address::repeat_byte(0x33) => alloy::primitives::U256::from(3000), }, }, solutions: vec![SolverSettlement { solver: "2".to_string(), - solver_address: H160([0x22; 20]), + solver_address: Address::repeat_byte(0x22), score: Some(Score::Solver(1.into())), ranking: 1, clearing_prices: btreemap! { - H160([0x22; 20]) => 8.into(), + Address::repeat_byte(0x22) => alloy::primitives::U256::from(8), }, orders: vec![ Order::Colocated { id: OrderUid([0x33; 56]), - sell_amount: 12.into(), - buy_amount: 13.into(), + sell_amount: alloy::primitives::U256::from(12), + buy_amount: alloy::primitives::U256::from(13), }, Order::Legacy { id: OrderUid([0x44; 56]), - executed_amount: 14.into(), + executed_amount: alloy::primitives::U256::from(14), }, ], is_winner: true, diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index 669dca9643..d6ba36ccb6 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -39,7 +39,6 @@ use { big_decimal_to_u256, u256_to_big_decimal, }, - primitive_types::{H160, U256}, shared::{ db_order_conversions::{ buy_token_destination_from, @@ -407,7 +406,7 @@ impl Postgres { } pub async fn token_metadata(&self, token: &Address) -> Result { - let (first_trade_block, native_price): (Option, Option) = tokio::try_join!( + let (first_trade_block, native_price): (Option, Option) = tokio::try_join!( self.execute_instrumented("token_first_trade_block", async { let mut ex = self.pool.acquire().await?; database::trades::token_first_trade_block(&mut ex, ByteArray(token.0.0)) @@ -425,7 +424,7 @@ impl Postgres { ) .await .map_err(anyhow::Error::from)? - .and_then(|price| big_decimal_to_u256(&price))) + .and_then(|price| number::conversions::alloy::big_decimal_to_u256(&price))) }) )?; @@ -454,7 +453,7 @@ impl Postgres { #[async_trait] impl LimitOrderCounting for Postgres { - async fn count(&self, owner: H160) -> Result { + async fn count(&self, owner: Address) -> Result { let _timer = super::Metrics::get() .database_queries .with_label_values(&["count_limit_orders_by_owner"]) @@ -464,7 +463,7 @@ impl LimitOrderCounting for Postgres { Ok(database::orders::user_orders_with_quote( &mut ex, now_in_epoch_seconds().into(), - &ByteArray(owner.0), + &ByteArray(owner.0.0), ) .await? .into_iter() diff --git a/crates/orderbook/src/dto/auction.rs b/crates/orderbook/src/dto/auction.rs index fe3d237fbf..54268c0ad9 100644 --- a/crates/orderbook/src/dto/auction.rs +++ b/crates/orderbook/src/dto/auction.rs @@ -1,13 +1,14 @@ use { super::order::Order, + alloy::primitives::{Address, U256}, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, }; /// Replicates [`crate::model::Auction`]. +// NOTE: as of 25/11/2025 this is only used for liveness checking. #[serde_as] #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -15,9 +16,9 @@ pub struct Auction { pub block: u64, pub orders: Vec, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub prices: BTreeMap, + pub prices: BTreeMap, #[serde(default)] - pub surplus_capturing_jit_order_owners: Vec, + pub surplus_capturing_jit_order_owners: Vec
, } pub type AuctionId = i64; diff --git a/crates/orderbook/src/dto/mod.rs b/crates/orderbook/src/dto/mod.rs index 1fd8284dbf..7d75fc8a9f 100644 --- a/crates/orderbook/src/dto/mod.rs +++ b/crates/orderbook/src/dto/mod.rs @@ -1,16 +1,16 @@ pub mod auction; pub mod order; -pub use { - auction::{Auction, AuctionId, AuctionWithId}, - order::Order, -}; use { + alloy::primitives::U256, number::serialization::HexOrDecimalU256, - primitive_types::U256, serde::Serialize, serde_with::serde_as, }; +pub use { + auction::{Auction, AuctionId, AuctionWithId}, + order::Order, +}; #[serde_as] #[derive(Serialize)] diff --git a/crates/orderbook/src/dto/order.rs b/crates/orderbook/src/dto/order.rs index 0e08967081..99b309a32f 100644 --- a/crates/orderbook/src/dto/order.rs +++ b/crates/orderbook/src/dto/order.rs @@ -1,4 +1,5 @@ use { + alloy::primitives::Address, app_data::AppDataHash, model::{ interaction::InteractionData, @@ -6,7 +7,6 @@ use { signature::Signature, }, number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, serde::{Deserialize, Serialize}, serde_with::serde_as, }; @@ -16,21 +16,21 @@ use { #[serde(rename_all = "camelCase")] pub struct Order { pub uid: OrderUid, - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, #[serde_as(as = "HexOrDecimalU256")] - pub sell_amount: U256, + pub sell_amount: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub buy_amount: U256, + pub buy_amount: alloy::primitives::U256, pub protocol_fees: Vec, pub created: u32, pub valid_to: u32, pub kind: OrderKind, - pub receiver: Option, - pub owner: H160, + pub receiver: Option
, + pub owner: Address, pub partially_fillable: bool, #[serde_as(as = "HexOrDecimalU256")] - pub executed: U256, + pub executed: alloy::primitives::U256, pub pre_interactions: Vec, pub post_interactions: Vec, pub sell_token_balance: SellTokenSource, @@ -48,12 +48,12 @@ pub struct Order { #[serde(rename_all = "camelCase")] pub struct Quote { #[serde_as(as = "HexOrDecimalU256")] - pub sell_amount: U256, + pub sell_amount: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub buy_amount: U256, + pub buy_amount: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub fee: U256, - pub solver: H160, + pub fee: alloy::primitives::U256, + pub solver: Address, } #[serde_as] @@ -78,9 +78,9 @@ pub enum FeePolicy { #[serde(rename_all = "camelCase")] pub struct ExecutedAmounts { #[serde_as(as = "HexOrDecimalU256")] - pub sell: U256, + pub sell: alloy::primitives::U256, #[serde_as(as = "HexOrDecimalU256")] - pub buy: U256, + pub buy: alloy::primitives::U256, } /// Indicates that a solver has provided a solution, with `executed_amounts` diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index 38e6b442f4..70bfa0ae74 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -212,7 +212,7 @@ impl From for ValidationError { #[cfg_attr(any(test, feature = "test-util"), mockall::automock)] #[async_trait] pub trait LimitOrderCounting: Send + Sync { - async fn count(&self, owner: H160) -> Result; + async fn count(&self, owner: Address) -> Result; } #[derive(Clone)] @@ -324,7 +324,7 @@ impl OrderValidator { } } - async fn check_max_limit_orders(&self, owner: H160) -> Result<(), ValidationError> { + async fn check_max_limit_orders(&self, owner: Address) -> Result<(), ValidationError> { let num_limit_orders = self .limit_order_counter .count(owner) @@ -726,7 +726,7 @@ impl OrderValidating for OrderValidator { }, data.kind, ) { - self.check_max_limit_orders(owner).await?; + self.check_max_limit_orders(owner.into_alloy()).await?; } (class, Some(quote)) } @@ -757,7 +757,7 @@ impl OrderValidating for OrderValidator { }, data.kind, ) { - self.check_max_limit_orders(owner).await?; + self.check_max_limit_orders(owner.into_alloy()).await?; } (OrderClass::Limit, None) } From dd6ec1396b5a78d3b404626617701e34fb091ec1 Mon Sep 17 00:00:00 2001 From: ilya Date: Wed, 26 Nov 2025 12:40:17 +0000 Subject: [PATCH 013/470] Do not preprocess COW AMMs when not configured (#3925) # Description When the driver's COW AMM config is empty, the corresponding task still tries to search for surplus capturing jit order owners among the AMMs and fires a redundant warning log in that case. When the driver doesn't expect any AMMs, this log doesn't make any sense. This PR fixes this. # Changes - [ ] Make the COW AMM cache optional based on the COW AMMs config. - [ ] When None, return fast with no AMMs for every auction with no redundant logs. ## How to test Logs on chains where COW AMMs are not configured. ## Related Issues Fixes #3890 --- crates/driver/src/domain/competition/pre_processing.rs | 10 +++++++--- crates/driver/src/domain/cow_amm.rs | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/crates/driver/src/domain/competition/pre_processing.rs b/crates/driver/src/domain/competition/pre_processing.rs index a49c5adfe9..15bb8d3e8a 100644 --- a/crates/driver/src/domain/competition/pre_processing.rs +++ b/crates/driver/src/domain/competition/pre_processing.rs @@ -60,7 +60,7 @@ pub struct Utilities { liquidity_fetcher: infra::liquidity::Fetcher, tokens: tokens::Fetcher, balance_fetcher: Arc, - cow_amm_cache: cow_amm::Cache, + cow_amm_cache: Option, } impl std::fmt::Debug for Utilities { @@ -390,12 +390,16 @@ impl Utilities { } async fn cow_amm_orders(self: Arc, auction: Arc) -> Arc> { + let Some(ref cow_amm_cache) = self.cow_amm_cache else { + // CoW AMMs are not configured, return empty vec + return Default::default(); + }; + let _timer = metrics::get().processing_stage_timer("cow_amm_orders"); let _timer2 = observe::metrics::metrics().on_auction_overhead_start("driver", "cow_amm_orders"); - let cow_amms = self - .cow_amm_cache + let cow_amms = cow_amm_cache .get_or_create_amms(&auction.surplus_capturing_jit_order_owners) .await; diff --git a/crates/driver/src/domain/cow_amm.rs b/crates/driver/src/domain/cow_amm.rs index c60dcaaa72..d384a30153 100644 --- a/crates/driver/src/domain/cow_amm.rs +++ b/crates/driver/src/domain/cow_amm.rs @@ -24,7 +24,11 @@ pub struct Cache { } impl Cache { - pub fn new(web3: DynProvider, factory_mapping: HashMap) -> Self { + pub fn new(web3: DynProvider, factory_mapping: HashMap) -> Option { + if factory_mapping.is_empty() { + return None; + } + let helper_by_factory = factory_mapping .into_iter() .map(|(factory, helper)| { @@ -34,11 +38,11 @@ impl Cache { ) }) .collect(); - Self { + Some(Self { inner: RwLock::new(HashMap::new()), web3: web3.clone(), helper_by_factory, - } + }) } /// Gets or creates AMM instances for the given surplus capturing JIT order From b91aa964da1dcf769a977b1893f29b24bd3ef949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Wed, 26 Nov 2025 12:42:05 +0000 Subject: [PATCH 014/470] [SIMPLE] Alloy migration for quotes, order validation, fee calculations (#3921) Non-trivial part: https://github.com/cowprotocol/services/pull/3921/files#diff-3f8b6079ce50ae3ab0fe449d91c7e68922cae4023902961c892b58f91ddc49b3L148-L155 The rest is trivial # Description This PR continues the migration from the `ethcontract` library to the `alloy` library by replacing `primitive_types` (H160, U256) with `alloy::primitives` (Address, U256) across quote handling, order validation, solver competitions, DTOs, and database operations. This migration modernizes the codebase to use alloy's type system, which provides better type safety and compatibility with the latest Ethereum tooling. # Changes - [ ] **Quote Handling** - Migrate `order_quoting` module to use alloy U256 and Address types, updating Quote and QuoteData structures - [ ] **Order Validation** - Update `order_validation` module to use alloy types for order validation logic - [ ] **Solver Competitions** - Replace primitive types in `solver_competition` model with alloy Address and U256 - [ ] **DTOs** - Migrate all DTOs (auction, order) to use alloy types for serialization - [ ] **Database Operations** - Update database order operations, token metadata handling, and limit order counting with alloy types - [ ] **Autopilot** - Convert onchain order events, quote domain models, and run loop to use alloy types - [ ] **Fee Calculations** - Update fee module to use alloy::primitives::U256 instead of ethcontract::U256 - [ ] **Event Storage** - Migrate quote row creation helpers to use alloy types - [ ] **Price Estimation** - Update trade verifier to work with alloy types - [ ] **Type Conversions** - Add `into_legacy()` and `into_alloy()` conversion helpers for backward compatibility where needed - [ ] **Tests** - Update e2e quote verification tests with alloy address conversions ## How to test Existing tests --------- Co-authored-by: Claude --- .../src/database/onchain_order_events/mod.rs | 26 +-- crates/autopilot/src/domain/quote/mod.rs | 7 +- crates/e2e/tests/e2e/quote_verification.rs | 4 +- crates/orderbook/src/database/orders.rs | 29 +-- crates/orderbook/src/orderbook.rs | 12 +- crates/orderbook/src/quoter.rs | 33 ++-- crates/shared/src/fee.rs | 4 +- crates/shared/src/order_quoting.rs | 168 +++++++++--------- crates/shared/src/order_validation.rs | 122 +++++++------ crates/shared/src/price_estimation/mod.rs | 4 +- .../price_estimation/trade_verifier/mod.rs | 22 +-- 11 files changed, 224 insertions(+), 207 deletions(-) diff --git a/crates/autopilot/src/database/onchain_order_events/mod.rs b/crates/autopilot/src/database/onchain_order_events/mod.rs index 3e52675088..cdaab8fed3 100644 --- a/crates/autopilot/src/database/onchain_order_events/mod.rs +++ b/crates/autopilot/src/database/onchain_order_events/mod.rs @@ -499,8 +499,10 @@ where gas_amount: quote.data.fee_parameters.gas_amount, gas_price: quote.data.fee_parameters.gas_price, sell_token_price: quote.data.fee_parameters.sell_token_price, - sell_amount: u256_to_big_decimal("e.sell_amount), - buy_amount: u256_to_big_decimal("e.buy_amount), + sell_amount: number::conversions::alloy::u256_to_big_decimal( + "e.sell_amount, + ), + buy_amount: number::conversions::alloy::u256_to_big_decimal("e.buy_amount), solver: ByteArray(*quote.data.solver.0), verified: quote.data.verified, metadata: quote.data.metadata.try_into()?, @@ -598,9 +600,9 @@ fn convert_onchain_order_placement( // executed fast (we don't want to reserve the user's ETH for too long) if quote.as_ref().is_ok_and(|quote| { !order_data.within_market(QuoteAmounts { - sell: quote.sell_amount, - buy: quote.buy_amount, - fee: quote.fee_amount, + sell: quote.sell_amount.into_legacy(), + buy: quote.buy_amount.into_legacy(), + fee: quote.fee_amount.into_legacy(), }) }) { tracing::debug!(%order_uid, ?owner, "order is outside market price"); @@ -1091,8 +1093,8 @@ mod test { }; let settlement_contract = H160::from([8u8; 20]); let quote = Quote { - sell_amount: sell_amount.into_legacy(), - buy_amount: (buy_amount / U256::from(2)).into_legacy(), + sell_amount, + buy_amount: buy_amount / U256::from(2), ..Default::default() }; let order_uid = OrderUid([9u8; 56]); @@ -1223,9 +1225,9 @@ mod test { }, ..Default::default() }, - sell_amount: sell_amount.into_legacy(), - buy_amount: buy_amount.into_legacy(), - fee_amount: fee_amount.into_legacy(), + sell_amount, + buy_amount, + fee_amount, }; let cloned_quote = quote.clone(); order_quoter @@ -1301,8 +1303,8 @@ mod test { gas_amount: quote.data.fee_parameters.gas_amount, gas_price: quote.data.fee_parameters.gas_price, sell_token_price: quote.data.fee_parameters.sell_token_price, - sell_amount: u256_to_big_decimal("e.sell_amount), - buy_amount: u256_to_big_decimal("e.buy_amount), + sell_amount: number::conversions::alloy::u256_to_big_decimal("e.sell_amount), + buy_amount: number::conversions::alloy::u256_to_big_decimal("e.buy_amount), solver: ByteArray(*quote.data.solver.0), verified: quote.data.verified, metadata: quote.data.metadata.try_into().unwrap(), diff --git a/crates/autopilot/src/domain/quote/mod.rs b/crates/autopilot/src/domain/quote/mod.rs index 41131c37ef..12efff2fa1 100644 --- a/crates/autopilot/src/domain/quote/mod.rs +++ b/crates/autopilot/src/domain/quote/mod.rs @@ -2,6 +2,7 @@ use { super::OrderUid, crate::{boundary::Amounts, domain::eth}, alloy::primitives::Address, + ethrpc::alloy::conversions::IntoAlloy, }; #[derive(Clone, Debug, PartialEq)] @@ -16,9 +17,9 @@ pub struct Quote { impl From<&Quote> for Amounts { fn from(quote: &Quote) -> Self { Self { - sell: quote.sell_amount.into(), - buy: quote.buy_amount.into(), - fee: quote.fee.into(), + sell: quote.sell_amount.0.into_alloy(), + buy: quote.buy_amount.0.into_alloy(), + fee: quote.fee.0.into_alloy(), } } } diff --git a/crates/e2e/tests/e2e/quote_verification.rs b/crates/e2e/tests/e2e/quote_verification.rs index a4f788d820..6f1f60a28b 100644 --- a/crates/e2e/tests/e2e/quote_verification.rs +++ b/crates/e2e/tests/e2e/quote_verification.rs @@ -175,9 +175,9 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { in_amount: NonZeroU256::new(12.into()).unwrap(), }, &Verification { - from: H160::from_str("0x73688c2b34bf6c09c125fed02fe92d17a94b897a").unwrap(), + from: H160::from_str("0x73688c2b34bf6c09c125fed02fe92d17a94b897a").unwrap().into_alloy(), receiver: H160::from_str("0x73688c2b34bf6c09c125fed02fe92d17a94b897a") - .unwrap(), + .unwrap().into_alloy(), pre_interactions: vec![], post_interactions: vec![], sell_token_source: SellTokenSource::Erc20, diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index d6ba36ccb6..df486cf540 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -12,7 +12,7 @@ use { order_events::{OrderEvent, OrderEventLabel, insert_order_event}, orders::{self, FullOrder, OrderKind as DbOrderKind}, }, - ethrpc::alloy::conversions::IntoLegacy, + ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::{FutureExt, StreamExt, stream::TryStreamExt}, model::{ order::{ @@ -470,13 +470,21 @@ impl LimitOrderCounting for Postgres { .filter(|order_with_quote| { is_order_outside_market_price( &Amounts { - sell: big_decimal_to_u256(&order_with_quote.order_sell_amount).unwrap(), - buy: big_decimal_to_u256(&order_with_quote.order_buy_amount).unwrap(), - fee: 0.into(), + sell: big_decimal_to_u256(&order_with_quote.order_sell_amount) + .unwrap() + .into_alloy(), + buy: big_decimal_to_u256(&order_with_quote.order_buy_amount) + .unwrap() + .into_alloy(), + fee: alloy::primitives::U256::from(0), }, &Amounts { - sell: big_decimal_to_u256(&order_with_quote.quote_sell_amount).unwrap(), - buy: big_decimal_to_u256(&order_with_quote.quote_buy_amount).unwrap(), + sell: big_decimal_to_u256(&order_with_quote.quote_sell_amount) + .unwrap() + .into_alloy(), + buy: big_decimal_to_u256(&order_with_quote.quote_buy_amount) + .unwrap() + .into_alloy(), fee: FeeParameters { gas_amount: order_with_quote.quote_gas_amount, gas_price: order_with_quote.quote_gas_price, @@ -657,7 +665,6 @@ mod tests { order::{Order, OrderData, OrderMetadata, OrderStatus, OrderUid}, signature::{Signature, SigningScheme}, }, - primitive_types::U256, shared::order_quoting::{Quote, QuoteData, QuoteMetadataV1}, std::sync::atomic::{AtomicI64, Ordering}, }; @@ -1123,8 +1130,8 @@ mod tests { let quote = Quote { id: Some(5), - sell_amount: U256::from(1), - buy_amount: U256::from(2), + sell_amount: alloy::primitives::U256::from(1), + buy_amount: alloy::primitives::U256::from(2), data: QuoteData { fee_parameters: FeeParameters { sell_token_price: 2.5, @@ -1173,8 +1180,8 @@ mod tests { let quote = Quote { id: Some(5), - sell_amount: U256::from(1), - buy_amount: U256::from(2), + sell_amount: alloy::primitives::U256::from(1), + buy_amount: alloy::primitives::U256::from(2), data: QuoteData { verified: true, metadata: QuoteMetadataV1 { diff --git a/crates/orderbook/src/orderbook.rs b/crates/orderbook/src/orderbook.rs index c080739f4a..0e20eed8cf 100644 --- a/crates/orderbook/src/orderbook.rs +++ b/crates/orderbook/src/orderbook.rs @@ -13,7 +13,7 @@ use { bigdecimal::ToPrimitive, chrono::Utc, database::order_events::OrderEventLabel, - ethrpc::alloy::conversions::IntoLegacy, + ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, model::{ DomainSeparator, order::{ @@ -78,13 +78,13 @@ impl Metrics { // Check if the order at the submission time was "in market" !is_order_outside_market_price( &Amounts { - sell: order.data.sell_amount.into_legacy(), - buy: order.data.buy_amount.into_legacy(), - fee: order.data.fee_amount.into_legacy(), + sell: order.data.sell_amount, + buy: order.data.buy_amount, + fee: order.data.fee_amount, }, &Amounts { - sell: quote.sell_amount, - buy: quote.buy_amount, + sell: quote.sell_amount.into_alloy(), + buy: quote.buy_amount.into_alloy(), fee: FeeParameters { // safe to unwrap as these values were converted from f64 previously gas_amount: quote.gas_amount.to_f64().unwrap(), diff --git a/crates/orderbook/src/quoter.rs b/crates/orderbook/src/quoter.rs index d09a939038..dc73b46b31 100644 --- a/crates/orderbook/src/quoter.rs +++ b/crates/orderbook/src/quoter.rs @@ -90,12 +90,12 @@ impl QuoteHandler { self.order_validator.partial_validate(order).await?; let params = QuoteParameters { - sell_token: request.sell_token, - buy_token: request.buy_token, + sell_token: request.sell_token.into_alloy(), + buy_token: request.buy_token.into_alloy(), side: request.side, verification: Verification { - from: request.from, - receiver: request.receiver.unwrap_or(request.from), + from: request.from.into_alloy(), + receiver: request.receiver.unwrap_or(request.from).into_alloy(), sell_token_source: request.sell_token_balance, buy_token_destination: request.buy_token_balance, pre_interactions: trade_finding::map_interactions(&app_data.interactions.pre), @@ -142,7 +142,7 @@ impl QuoteHandler { }, app_data => app_data.clone(), }, - fee_amount: quote.fee_amount, + fee_amount: quote.fee_amount.into_legacy(), kind: quote.data.kind, partially_fillable: false, sell_token_balance: request.sell_token_balance, @@ -173,8 +173,8 @@ fn get_adjusted_quote_data( .and_then(|config| config.factor) else { return Ok(AdjustedQuoteData { - sell_amount: quote.sell_amount.into_alloy(), - buy_amount: quote.buy_amount.into_alloy(), + sell_amount: quote.sell_amount, + buy_amount: quote.buy_amount, protocol_fee_bps: None, }); }; @@ -187,7 +187,6 @@ fn get_adjusted_quote_data( let protocol_fee = U256::uint_try_from( quote .buy_amount - .into_alloy() .widening_mul(U256::from(factor.to_bps())) .checked_div(U512::from(FeeFactor::MAX_BPS)) .ok_or_else(|| anyhow::anyhow!("volume fee calculation division by zero"))?, @@ -195,16 +194,16 @@ fn get_adjusted_quote_data( .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; // Reduce buy amount by protocol fee - let adjusted_buy = quote.buy_amount.into_alloy().saturating_sub(protocol_fee); + let adjusted_buy = quote.buy_amount.saturating_sub(protocol_fee); - (quote.sell_amount.into_alloy(), adjusted_buy) + (quote.sell_amount, adjusted_buy) } OrderQuoteSide::Buy { .. } => { // For BUY orders, fee is calculated on sell amount + network fee. // Network fee is already in sell token, so it is added to get the total volume. let total_sell_volume = quote.sell_amount.saturating_add(quote.fee_amount); let factor = U256::from(factor.to_bps()); - let volume_bps: Uint<512, 8> = total_sell_volume.into_alloy().widening_mul(factor); + let volume_bps: Uint<512, 8> = total_sell_volume.widening_mul(factor); let protocol_fee = U256::uint_try_from( volume_bps .checked_div(U512::from(FeeFactor::MAX_BPS)) @@ -213,9 +212,9 @@ fn get_adjusted_quote_data( .map_err(|_| anyhow::anyhow!("volume fee calculation overflow"))?; // Increase sell amount by protocol fee - let adjusted_sell = quote.sell_amount.into_alloy().saturating_add(protocol_fee); + let adjusted_sell = quote.sell_amount.saturating_add(protocol_fee); - (adjusted_sell, quote.buy_amount.into_alloy()) + (adjusted_sell, quote.buy_amount) } }; @@ -281,9 +280,9 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount: sell_amount.into_legacy(), - buy_amount: buy_amount.into_legacy(), - fee_amount: U256::ZERO.into_legacy(), + sell_amount, + buy_amount, + fee_amount: U256::ZERO, } } @@ -360,7 +359,7 @@ mod tests { // Buying 100 tokens, expecting to sell 100 tokens, with 5 token network fee let mut quote = create_test_quote(to_wei(100), to_wei(100)); - quote.fee_amount = to_wei(5).into_legacy(); // Network fee in sell token + quote.fee_amount = to_wei(5); // Network fee in sell token let side = OrderQuoteSide::Buy { buy_amount_after_fee: number::nonzero::U256::try_from(to_wei(100).into_legacy()) .unwrap(), diff --git a/crates/shared/src/fee.rs b/crates/shared/src/fee.rs index 4bea308ada..dfe7944c52 100644 --- a/crates/shared/src/fee.rs +++ b/crates/shared/src/fee.rs @@ -1,4 +1,4 @@ -use ethcontract::U256; +use alloy::primitives::U256; /// Everything required to compute the fee amount in sell token #[derive(Debug, Clone, Copy, PartialEq)] @@ -41,6 +41,6 @@ impl FeeParameters { // 1. For final amounts that end up close to 0 atoms we always take a fee so we // are not attackable through low decimal tokens. // 2. When validating fees this consistently picks the same amount. - U256::from_f64_lossy((fee_in_eth / self.sell_token_price).ceil()) + U256::from((fee_in_eth / self.sell_token_price).ceil()) } } diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 45484d85c0..1905eaa81e 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -13,7 +13,7 @@ use { price_estimation::{Estimate, QuoteVerificationMode, Verification}, trade_finding::external::dto, }, - alloy::primitives::Address, + alloy::primitives::{Address, U512, ruint::UintTryFrom}, anyhow::{Context, Result}, chrono::{DateTime, Duration, Utc}, database::quotes::{Quote as QuoteRow, QuoteKind}, @@ -36,8 +36,8 @@ use { /// Order parameters for quoting. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct QuoteParameters { - pub sell_token: H160, - pub buy_token: H160, + pub sell_token: Address, + pub buy_token: Address, pub side: OrderQuoteSide, pub verification: Verification, pub signing_scheme: QuoteSigningScheme, @@ -68,8 +68,8 @@ impl QuoteParameters { price_estimation::Query { verification: self.verification.clone(), - sell_token: self.sell_token.into_alloy(), - buy_token: self.buy_token.into_alloy(), + sell_token: self.sell_token, + buy_token: self.buy_token, in_amount, kind, block_dependent: true, @@ -94,16 +94,16 @@ pub struct Quote { /// Note that this is different than the `QuoteData::quoted_sell_amount` for /// quotes computed with `SellAmount::BeforeFee` (specifically, it will be /// `quoted_sell_amount - fee_amount` in those cases). - pub sell_amount: U256, + pub sell_amount: alloy::primitives::U256, /// The final computed buy amount for the quote. /// /// Note that this is different than the `QuoteData::quoted_buy_amount` for /// quotes computed with `SellAmount::BeforeFee` (specifically, it will be /// scaled down to account for the computed `fee_amount`). - pub buy_amount: U256, + pub buy_amount: alloy::primitives::U256, /// The fee amount for any order created for this quote. The fee is /// denoted in the sell token. - pub fee_amount: U256, + pub fee_amount: alloy::primitives::U256, } impl Quote { @@ -111,8 +111,8 @@ impl Quote { pub fn new(id: Option, data: QuoteData) -> Self { Self { id, - sell_amount: data.quoted_sell_amount.into_legacy(), - buy_amount: data.quoted_buy_amount.into_legacy(), + sell_amount: data.quoted_sell_amount, + buy_amount: data.quoted_buy_amount, fee_amount: data.fee_parameters.fee(), data, } @@ -141,18 +141,18 @@ impl Quote { /// it assumes that the final buy amount will never overflow a `U256` and /// _will saturate_ to `U256::MAX` if this is used to scale up past the /// maximum value. - pub fn with_scaled_sell_amount(mut self, sell_amount: U256) -> Self { + pub fn with_scaled_sell_amount(mut self, sell_amount: alloy::primitives::U256) -> Self { self.sell_amount = sell_amount; // Use `full_mul: (U256, U256) -> U512` to avoid any overflow // errors computing the initial product. - self.buy_amount = (self - .data - .quoted_buy_amount - .into_legacy() - .full_mul(sell_amount) - / self.data.quoted_sell_amount.into_legacy()) - .try_into() - .unwrap_or(U256::MAX); + + self.buy_amount = alloy::primitives::U256::uint_try_from( + self.data + .quoted_buy_amount + .widening_mul::<_, _, 512, 8>(sell_amount) + / U512::from(self.data.quoted_sell_amount), + ) + .unwrap_or(alloy::primitives::U256::MAX); self } @@ -168,8 +168,8 @@ impl Quote { self.data.fee_parameters.sell_token_price, ) .context("sell token price is not a valid BigDecimal")?, - sell_amount: self.sell_amount, - buy_amount: self.buy_amount, + sell_amount: self.sell_amount.into_legacy(), + buy_amount: self.buy_amount.into_legacy(), solver: self.data.solver.into_legacy(), verified: self.data.verified, metadata: serde_json::to_value(&self.data.metadata)?, @@ -476,13 +476,13 @@ impl OrderQuoter { .estimate(trade_query.clone()) .map_err(|err| (EstimatorKind::Regular, err).into()), self.native_price_estimator - .estimate_native_price(parameters.sell_token.into_alloy(), trade_query.timeout) + .estimate_native_price(parameters.sell_token, trade_query.timeout) .map_err(|err| (EstimatorKind::NativeSell, err).into()), // We don't care about the native price of the buy_token for the quote but we need it // when we build the auction. To prevent creating orders which we can't settle later on // we make the native buy_token price a requirement here as well. self.native_price_estimator - .estimate_native_price(parameters.buy_token.into_alloy(), trade_query.timeout) + .estimate_native_price(parameters.buy_token, trade_query.timeout) .map_err(|err| (EstimatorKind::NativeBuy, err).into()), )?; @@ -508,8 +508,8 @@ impl OrderQuoter { let quote_kind = quote_kind_from_signing_scheme(¶meters.signing_scheme); let quote = QuoteData { - sell_token: parameters.sell_token.into_alloy(), - buy_token: parameters.buy_token.into_alloy(), + 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(), fee_parameters, @@ -547,7 +547,10 @@ impl OrderQuoter { } let balance = match self - .get_balance(¶meters.verification, parameters.sell_token) + .get_balance( + ¶meters.verification, + parameters.sell_token.into_legacy(), + ) .await { Ok(balance) => balance, @@ -568,7 +571,7 @@ impl OrderQuoter { async fn get_balance(&self, verification: &Verification, token: H160) -> Result { let query = Query { - owner: verification.from, + owner: verification.from.into_legacy(), token, source: verification.sell_token_source, interactions: verification @@ -608,12 +611,14 @@ impl OrderQuoting for OrderQuoter { }, } = ¶meters.side { - let sell_amount = - Into::::into(*sell_amount_before_fee).saturating_sub(quote.fee_amount); - if sell_amount == U256::zero() { + let sell_amount = sell_amount_before_fee + .get() + .into_alloy() + .saturating_sub(quote.fee_amount); + if sell_amount.is_zero() { // We want a sell_amount of at least 1! return Err(CalculateQuoteError::SellAmountDoesNotCoverFee { - fee_amount: quote.fee_amount, + fee_amount: quote.fee_amount.into_legacy(), }); } @@ -676,7 +681,7 @@ impl OrderQuoting for OrderQuoter { .with_additional_cost(additional_cost); let quote = match scaled_sell_amount { - Some(sell_amount) => quote.with_scaled_sell_amount(sell_amount.into_legacy()), + Some(sell_amount) => quote.with_scaled_sell_amount(sell_amount), None => quote, }; @@ -794,7 +799,6 @@ mod tests { alloy::primitives::Address, chrono::Utc, ethcontract::H160, - ethrpc::alloy::conversions::IntoLegacy, futures::FutureExt, gas_estimation::GasPrice1559, mockall::{Sequence, predicate::eq}, @@ -838,15 +842,15 @@ mod tests { async fn compute_sell_before_fee_quote() { let now = Utc::now(); let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(100).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, @@ -865,7 +869,7 @@ mod tests { .withf(|q| { **q == price_estimation::Query { verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, sell_token: Address::repeat_byte(1), @@ -894,14 +898,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); @@ -965,9 +969,9 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount: 70.into(), - buy_amount: 29.into(), - fee_amount: 30.into(), + sell_amount: alloy::primitives::U256::from(70), + buy_amount: alloy::primitives::U256::from(29), + fee_amount: alloy::primitives::U256::from(30), } ); } @@ -976,15 +980,15 @@ mod tests { async fn compute_sell_after_fee_quote() { let now = Utc::now(); let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(100).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip1271 { @@ -1006,7 +1010,7 @@ mod tests { .withf(|q| { **q == price_estimation::Query { verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, sell_token: Address::repeat_byte(1), @@ -1035,14 +1039,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); @@ -1106,9 +1110,9 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 60.into(), + sell_amount: alloy::primitives::U256::from(100), + buy_amount: alloy::primitives::U256::from(42), + fee_amount: alloy::primitives::U256::from(60), } ); } @@ -1117,13 +1121,13 @@ mod tests { async fn compute_buy_quote() { let now = Utc::now(); let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Buy { buy_amount_after_fee: NonZeroU256::try_from(42).unwrap(), }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, @@ -1142,7 +1146,7 @@ mod tests { .withf(|q| { **q == price_estimation::Query { verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, sell_token: Address::repeat_byte(1), @@ -1171,14 +1175,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(0.2) }.boxed()); @@ -1242,9 +1246,9 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_amount: alloy::primitives::U256::from(100), + buy_amount: alloy::primitives::U256::from(42), + fee_amount: alloy::primitives::U256::from(30), } ); } @@ -1252,15 +1256,15 @@ mod tests { #[tokio::test] async fn compute_sell_before_fee_quote_insufficient_amount_error() { let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(100).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, @@ -1292,14 +1296,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(1.) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Ok(1.) }.boxed()); @@ -1326,15 +1330,15 @@ mod tests { #[tokio::test] async fn require_native_price_for_buy_token() { let parameters = QuoteParameters { - sell_token: H160([1; 20]), - buy_token: H160([2; 20]), + sell_token: Address::from([1; 20]), + buy_token: Address::from([2; 20]), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(100_000).unwrap(), }, }, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, signing_scheme: QuoteSigningScheme::Eip712, @@ -1366,14 +1370,14 @@ mod tests { .expect_estimate_native_price() .withf({ let sell_token = parameters.sell_token; - move |q, _| q.into_legacy() == sell_token + move |q, _| *q == sell_token }) .returning(|_, _| async { Ok(1.) }.boxed()); native_price_estimator .expect_estimate_native_price() .withf({ let buy_token = parameters.buy_token; - move |q, _| q.into_legacy() == buy_token + move |q, _| *q == buy_token }) .returning(|_, _| async { Err(PriceEstimationError::NoLiquidity) }.boxed()); @@ -1414,7 +1418,7 @@ mod tests { signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, }; @@ -1473,12 +1477,12 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount: 85.into(), + sell_amount: alloy::primitives::U256::from(85), // Allows for "out-of-price" buy amounts. This means that order // be used for providing liquidity at a premium over current // market price. - buy_amount: 35.into(), - fee_amount: 30.into(), + buy_amount: alloy::primitives::U256::from(35), + fee_amount: alloy::primitives::U256::from(30), } ); } @@ -1497,7 +1501,7 @@ mod tests { signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, }; @@ -1556,9 +1560,9 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_amount: alloy::primitives::U256::from(100), + buy_amount: alloy::primitives::U256::from(42), + fee_amount: alloy::primitives::U256::from(30), } ); } @@ -1576,7 +1580,7 @@ mod tests { signing_scheme: QuoteSigningScheme::Eip712, additional_gas: 0, verification: Verification { - from: H160([3; 20]), + from: Address::from([3; 20]), ..Default::default() }, }; @@ -1641,9 +1645,9 @@ mod tests { verified: false, metadata: Default::default(), }, - sell_amount: 100.into(), - buy_amount: 42.into(), - fee_amount: 30.into(), + sell_amount: alloy::primitives::U256::from(100), + buy_amount: alloy::primitives::U256::from(42), + fee_amount: alloy::primitives::U256::from(30), } ); } diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index 70bfa0ae74..0b04f7bab8 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -636,8 +636,8 @@ impl OrderValidating for OrderValidator { .map_err(ValidationError::Partial)?; let verification = Verification { - from: owner, - receiver: order.receiver.unwrap_or(owner), + from: owner.into_alloy(), + receiver: order.receiver.unwrap_or(owner).into_alloy(), sell_token_source: order.sell_token_balance, buy_token_destination: order.buy_token_balance, pre_interactions: trade_finding::map_interactions(&app_data.interactions.pre), @@ -685,9 +685,9 @@ impl OrderValidating for OrderValidator { ); if is_order_outside_market_price( &Amounts { - sell: data.sell_amount.into_legacy(), - buy: data.buy_amount.into_legacy(), - fee: data.fee_amount.into_legacy(), + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, }, &Amounts { sell: quote.sell_amount, @@ -715,9 +715,9 @@ impl OrderValidating for OrderValidator { // If the order is not "In-Market", check for the limit orders if is_order_outside_market_price( &Amounts { - sell: data.sell_amount.into_legacy(), - buy: data.buy_amount.into_legacy(), - fee: data.fee_amount.into_legacy(), + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, }, &Amounts { sell: quote.sell_amount, @@ -746,9 +746,9 @@ impl OrderValidating for OrderValidator { // If the order is not "In-Market", check for the limit orders if is_order_outside_market_price( &Amounts { - sell: data.sell_amount.into_legacy(), - buy: data.buy_amount.into_legacy(), - fee: data.fee_amount.into_legacy(), + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, }, &Amounts { sell: quote.sell_amount, @@ -903,8 +903,8 @@ async fn get_or_create_quote( Err(err) => { tracing::debug!(?err, "failed to find quote for order creation"); let parameters = QuoteParameters { - sell_token: quote_search_parameters.sell_token.into_legacy(), - buy_token: quote_search_parameters.buy_token.into_legacy(), + sell_token: quote_search_parameters.sell_token, + buy_token: quote_search_parameters.buy_token, side: match quote_search_parameters.kind { OrderKind::Buy => OrderQuoteSide::Buy { buy_amount_after_fee: quote_search_parameters @@ -946,17 +946,17 @@ async fn get_or_create_quote( /// Amounts used for market price checker. #[derive(Debug)] pub struct Amounts { - pub sell: U256, - pub buy: U256, - pub fee: U256, + pub sell: alloy::primitives::U256, + pub buy: alloy::primitives::U256, + pub fee: alloy::primitives::U256, } impl From<&model::order::Order> for Amounts { fn from(order: &model::order::Order) -> Self { Self { - sell: order.data.sell_amount.into_legacy(), - buy: order.data.buy_amount.into_legacy(), - fee: order.data.fee_amount.into_legacy(), + sell: order.data.sell_amount, + buy: order.data.buy_amount, + fee: order.data.fee_amount, } } } @@ -969,14 +969,18 @@ pub fn is_order_outside_market_price( kind: model::order::OrderKind, ) -> bool { let check = move || match kind { - OrderKind::Buy => { - Some(order.sell.full_mul(quote.buy) < (quote.sell + quote.fee).full_mul(order.buy)) - } + OrderKind::Buy => Some( + order.sell.widening_mul::<256, 4, 512, 8>(quote.buy) + < (quote.sell + quote.fee).widening_mul::<256, 4, 512, 8>(order.buy), + ), OrderKind::Sell => { let quote_buy = quote .buy .checked_sub(quote.fee.checked_mul(quote.buy)?.checked_div(quote.sell)?)?; - Some(order.sell.full_mul(quote_buy) < quote.sell.full_mul(order.buy)) + Some( + order.sell.widening_mul::<256, 4, 512, 8>(quote_buy) + < quote.sell.widening_mul::<256, 4, 512, 8>(order.buy), + ) } }; @@ -1532,8 +1536,8 @@ mod tests { Ok(Quote { id: None, data: Default::default(), - sell_amount: U256::from(1), - buy_amount: U256::from(1), + sell_amount: alloy::primitives::U256::from(1), + buy_amount: alloy::primitives::U256::from(1), fee_amount: Default::default(), }) }); @@ -2256,12 +2260,12 @@ mod tests { }, additional_gas: 0, verification: Verification { - from: H160([0xf0; 20]), + from: Address::from([0xf0; 20]), ..Default::default() }, }; let quote_data = Quote { - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() }; let fee_amount = 0.into(); @@ -2283,7 +2287,7 @@ mod tests { assert_eq!( quote, Quote { - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() } ); @@ -2292,7 +2296,7 @@ mod tests { #[tokio::test] async fn get_quote_calculates_fresh_quote_when_not_found() { let verification = Verification { - from: H160([0xf0; 20]), + from: Address::from([0xf0; 20]), ..Default::default() }; @@ -2310,15 +2314,15 @@ mod tests { ..Default::default() }; let quote_data = Quote { - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() }; let fee_amount = 0.into(); order_quoter .expect_calculate_quote() .with(eq(QuoteParameters { - sell_token: quote_search_parameters.sell_token.into_legacy(), - buy_token: quote_search_parameters.buy_token.into_legacy(), + sell_token: quote_search_parameters.sell_token, + buy_token: quote_search_parameters.buy_token, side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from( @@ -2359,7 +2363,7 @@ mod tests { quote, Quote { id: Some(42), - fee_amount: 6.into(), + fee_amount: alloy::primitives::U256::from(6), ..Default::default() } ); @@ -2368,18 +2372,18 @@ mod tests { #[test] fn detects_market_orders_buy() { let quote = Quote { - sell_amount: 90.into(), - buy_amount: 100.into(), - fee_amount: 10.into(), + sell_amount: alloy::primitives::U256::from(90), + buy_amount: alloy::primitives::U256::from(100), + fee_amount: alloy::primitives::U256::from(10), ..Default::default() }; // at market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 100.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(100), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2391,9 +2395,9 @@ mod tests { // willing to buy less than market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 90.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(90), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2405,9 +2409,9 @@ mod tests { // wanting to buy more than market price assert!(is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 1000.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(1000), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2422,18 +2426,18 @@ mod tests { fn detects_market_orders_sell() { // 1 to 1 conversion let quote = Quote { - sell_amount: 100.into(), - buy_amount: 100.into(), - fee_amount: 10.into(), + sell_amount: alloy::primitives::U256::from(100), + buy_amount: alloy::primitives::U256::from(100), + fee_amount: alloy::primitives::U256::from(10), ..Default::default() }; // at market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 90.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(90), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2445,9 +2449,9 @@ mod tests { // willing to buy less than market price assert!(!is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 80.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(80), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2459,9 +2463,9 @@ mod tests { // wanting to buy more than market price assert!(is_order_outside_market_price( &Amounts { - sell: 100.into(), - buy: 1000.into(), - fee: 0.into(), + sell: alloy::primitives::U256::from(100), + buy: alloy::primitives::U256::from(1000), + fee: alloy::primitives::U256::from(0), }, &Amounts { sell: quote.sell_amount, @@ -2488,8 +2492,8 @@ mod tests { }, additional_gas: 0, verification: Verification { - from: H160([0xf0; 20]), - receiver: H160([0xf0; 20]), + from: Address::from([0xf0; 20]), + receiver: Address::from([0xf0; 20]), ..Default::default() }, }; diff --git a/crates/shared/src/price_estimation/mod.rs b/crates/shared/src/price_estimation/mod.rs index 862cb88735..3d2d624ba6 100644 --- a/crates/shared/src/price_estimation/mod.rs +++ b/crates/shared/src/price_estimation/mod.rs @@ -512,9 +512,9 @@ pub struct Query { #[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize)] pub struct Verification { /// This address needs to have the `sell_token`. - pub from: H160, + pub from: Address, /// This address will receive the `buy_token`. - pub receiver: H160, + pub receiver: Address, /// These interactions will be executed before the trade. pub pre_interactions: Vec, /// These interactions will be executed after the trade. diff --git a/crates/shared/src/price_estimation/trade_verifier/mod.rs b/crates/shared/src/price_estimation/trade_verifier/mod.rs index 6702bc5108..91073f1e97 100644 --- a/crates/shared/src/price_estimation/trade_verifier/mod.rs +++ b/crates/shared/src/price_estimation/trade_verifier/mod.rs @@ -168,7 +168,7 @@ impl TradeVerifier { let swap_simulation = solver.swap( *self.settlement.address(), tokens.iter().cloned().map(IntoAlloy::into_alloy).collect(), - verification.receiver.into_alloy(), + verification.receiver, settle_call.into(), ) // Initiate tx as solver so gas doesn't get deducted from user's ETH. @@ -242,7 +242,7 @@ impl TradeVerifier { // It looks like the contract lost a lot of sell tokens but only because it was // the trader and had to pay for the trade. Adjust tokens lost downward. - if verification.from == self.settlement.address().into_legacy() { + if verification.from == *self.settlement.address() { summary .tokens_lost .entry(query.sell_token) @@ -251,7 +251,7 @@ impl TradeVerifier { // 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 // upward. - if verification.receiver == self.settlement.address().into_legacy() { + if verification.receiver == *self.settlement.address() { summary .tokens_lost .entry(query.buy_token) @@ -319,7 +319,7 @@ impl TradeVerifier { overrides.insert(token, solver_balance_override); if verification.from.is_zero() { - verification.from = H160::random(); + verification.from = H160::random().into_alloy(); tracing::debug!( trader = ?verification.from, "use random trader address with fake balances" @@ -335,7 +335,7 @@ impl TradeVerifier { // Set up mocked trader. overrides.insert( - verification.from, + verification.from.into_legacy(), StateOverride { code: Some(Trader::Trader::DEPLOYED_BYTECODE.clone().into_legacy()), ..Default::default() @@ -346,7 +346,7 @@ impl TradeVerifier { // to proxy into it during the simulation. let trader_impl = self .code_fetcher - .code(verification.from) + .code(verification.from.into_legacy()) .await .context("failed to fetch trader code")?; if !trader_impl.0.is_empty() { @@ -577,7 +577,7 @@ fn encode_settlement( }; let solver_address = trade.solver(); let setup_call = Solver::Solver::ensureTradePreconditionsCall { - trader: verification.from.into_alloy(), + trader: verification.from, settlementContract: settlement.into_alloy(), sellToken: query.sell_token.into_alloy(), sellAmount: sell_amount.into_alloy(), @@ -632,7 +632,7 @@ fn encode_fake_trade( sell_amount: sell_amount.into_alloy(), buy_token: query.buy_token.into_alloy(), buy_amount: buy_amount.into_alloy(), - receiver: Some(verification.receiver.into_alloy()), + receiver: Some(verification.receiver), valid_to: u32::MAX, app_data: Default::default(), fee_amount: alloy::primitives::U256::ZERO, @@ -646,7 +646,7 @@ fn encode_fake_trade( let encoded_trade = encode_trade( &fake_order, &fake_signature, - verification.from, + verification.from.into_legacy(), // the tokens set length is small so the linear search is acceptable tokens .iter() @@ -751,7 +751,7 @@ fn add_balance_queries( let (token, owner) = match query.kind { // track how much `buy_token` the `receiver` actually got OrderKind::Sell => { - let receiver = match verification.receiver == H160::zero() { + let receiver = match verification.receiver.is_zero() { // Settlement contract sends fund to owner if receiver is the 0 address. true => verification.from, false => verification.receiver, @@ -764,7 +764,7 @@ fn add_balance_queries( }; let query_balance_call = Solver::Solver::storeBalanceCall { token: token.into_alloy(), - owner: owner.into_alloy(), + owner, countGas: true, } .abi_encode(); From 5923b4753420f4b0ba8bba010325a99a7df63caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Wed, 26 Nov 2025 15:07:09 +0000 Subject: [PATCH 015/470] [TRIVIAL] Migrate OrderQuoteRequest to use alloy Address types (#3922) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Migrates `OrderQuoteRequest` struct from using ethcontract's `H160` to alloy's `Address` type for address fields (`from`, `sell_token`, `buy_token`, `receiver`). This is part of the ongoing ethcontract → alloy library migration. # Changes - [x] Update `OrderQuoteRequest` struct in `model/src/quote.rs` to use `alloy::primitives::Address` instead of `H160` - [x] Update `orderbook/src/api/post_quote.rs` tests to use alloy `Address` constructors - [x] Update `orderbook/src/quoter.rs` to handle alloy Address types - [x] Add `.into_legacy()` conversions in `shared/src/order_quoting.rs` when converting `OrderQuoteRequest` to `PreOrderData` (which still uses H160) - [x] Fix all e2e tests (14 files) to properly convert between H160 and alloy Address: - Use `.into_alloy()` when converting H160 → Address for OrderQuoteRequest - Use `.into_legacy()` when converting Address → H160 for legacy functions - Dereference address references where needed (`*token.address()`) ## How to test Existing tests --------- Co-authored-by: Claude --- crates/e2e/tests/e2e/app_data.rs | 4 +- crates/e2e/tests/e2e/banned_users.rs | 11 ++- crates/e2e/tests/e2e/cow_amm.rs | 10 +-- crates/e2e/tests/e2e/eth_integration.rs | 6 +- crates/e2e/tests/e2e/ethflow.rs | 69 ++++++++++++------- crates/e2e/tests/e2e/hooks.rs | 6 +- crates/e2e/tests/e2e/limit_orders.rs | 10 +-- crates/e2e/tests/e2e/order_cancellation.rs | 11 ++- .../e2e/tests/e2e/place_order_with_quote.rs | 6 +- crates/e2e/tests/e2e/protocol_fee.rs | 4 +- crates/e2e/tests/e2e/quote_verification.rs | 59 ++++++++-------- crates/e2e/tests/e2e/quoting.rs | 30 ++++---- crates/e2e/tests/e2e/refunder.rs | 17 ++--- crates/e2e/tests/e2e/wrapper.rs | 4 +- crates/model/src/quote.rs | 13 ++-- crates/orderbook/src/api/post_quote.rs | 33 ++++----- crates/orderbook/src/quoter.rs | 18 ++--- crates/shared/src/order_quoting.rs | 8 +-- 18 files changed, 167 insertions(+), 152 deletions(-) diff --git a/crates/e2e/tests/e2e/app_data.rs b/crates/e2e/tests/e2e/app_data.rs index 499380b97d..6f7cec3148 100644 --- a/crates/e2e/tests/e2e/app_data.rs +++ b/crates/e2e/tests/e2e/app_data.rs @@ -114,8 +114,8 @@ async fn app_data(web3: Web3) { }); services .submit_quote(&OrderQuoteRequest { - sell_token: order3.sell_token, - buy_token: order3.buy_token, + sell_token: order3.sell_token.into_alloy(), + buy_token: order3.buy_token.into_alloy(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: order3.sell_amount.try_into().unwrap(), diff --git a/crates/e2e/tests/e2e/banned_users.rs b/crates/e2e/tests/e2e/banned_users.rs index abd741e855..8b4e80351c 100644 --- a/crates/e2e/tests/e2e/banned_users.rs +++ b/crates/e2e/tests/e2e/banned_users.rs @@ -12,10 +12,7 @@ use { to_wei, to_wei_with_exp, }, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::{Web3, alloy::conversions::IntoAlloy}, model::quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount}, reqwest::StatusCode, }; @@ -96,14 +93,14 @@ async fn forked_mainnet_onchain_banned_user_test(web3: Web3) { let result = services .submit_quote(&OrderQuoteRequest { - sell_token: token_dai.address().into_legacy(), - buy_token: token_usdt.address().into_legacy(), + sell_token: *token_dai.address(), + buy_token: *token_usdt.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei_with_exp(1000, 18).try_into().unwrap(), }, }, - from: BANNED_USER.into_legacy(), + from: BANNED_USER, ..Default::default() }) .await; diff --git a/crates/e2e/tests/e2e/cow_amm.rs b/crates/e2e/tests/e2e/cow_amm.rs index 259f742867..459c6a91b0 100644 --- a/crates/e2e/tests/e2e/cow_amm.rs +++ b/crates/e2e/tests/e2e/cow_amm.rs @@ -621,8 +621,8 @@ factory = "0xf76c421bAb7df8548604E60deCCcE50477C10462" // may time out) let _ = services .submit_quote(&OrderQuoteRequest { - sell_token: usdc.address().into_legacy(), - buy_token: usdt.address().into_legacy(), + sell_token: *usdc.address(), + buy_token: *usdt.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei_with_exp(1000, 6).try_into().unwrap(), @@ -1008,9 +1008,9 @@ async fn cow_amm_opposite_direction(web3: Web3) { mock_solver.configure_solution(Some(mocked_quote_solution)); let quote_request = OrderQuoteRequest { - from: bob.address(), - sell_token: dai.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + from: bob.address().into_alloy(), + sell_token: *dai.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(executed_amount).unwrap(), diff --git a/crates/e2e/tests/e2e/eth_integration.rs b/crates/e2e/tests/e2e/eth_integration.rs index d84854417b..b9e97b2ee6 100644 --- a/crates/e2e/tests/e2e/eth_integration.rs +++ b/crates/e2e/tests/e2e/eth_integration.rs @@ -62,7 +62,7 @@ async fn eth_integration(web3: Web3) { let request = OrderQuoteRequest { sell_token, buy_token, - from: Address::default(), + from: Address::default().into_alloy(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(to_wei(43)).unwrap(), @@ -73,11 +73,11 @@ async fn eth_integration(web3: Web3) { services.submit_quote(&request).await } }; - quote(token.address().into_legacy(), BUY_ETH_ADDRESS) + quote(*token.address(), BUY_ETH_ADDRESS.into_alloy()) .await .unwrap(); // Eth is only supported as the buy token - let (status, body) = quote(BUY_ETH_ADDRESS, token.address().into_legacy()) + let (status, body) = quote(BUY_ETH_ADDRESS.into_alloy(), *token.address()) .await .unwrap_err(); assert_eq!(status, 400, "{body}"); diff --git a/crates/e2e/tests/e2e/ethflow.rs b/crates/e2e/tests/e2e/ethflow.rs index 2d3be7829c..5b961461c4 100644 --- a/crates/e2e/tests/e2e/ethflow.rs +++ b/crates/e2e/tests/e2e/ethflow.rs @@ -102,9 +102,9 @@ async fn eth_flow_tx(web3: Web3) { .await; // Get a quote from the services - let buy_token = dai.address().into_legacy(); - let receiver = H160([0x42; 20]); - let sell_amount = to_wei(1); + let buy_token = *dai.address(); + let receiver = Address::repeat_byte(0x42); + let sell_amount = eth(1); let intent = EthFlowTradeIntent { sell_amount, buy_token, @@ -157,7 +157,10 @@ async fn eth_flow_tx(web3: Web3) { app_data: OrderCreationAppData::Hash { hash: app_data::AppDataHash(const_hex::decode(&hash[2..]).unwrap().try_into().unwrap()), }, - ..intent.to_quote_request(trader.account().address(), &onchain.contracts().weth) + ..intent.to_quote_request( + trader.account().address().into_alloy(), + &onchain.contracts().weth, + ) }; let quote: OrderQuoteResponse = test_submit_quote(&services, "e_request).await; @@ -182,7 +185,7 @@ async fn eth_flow_tx(web3: Web3) { test_order_availability_in_api( &services, ðflow_order, - &trader.address(), + &trader.address().into_alloy(), onchain.contracts(), ethflow_contract, ) @@ -299,7 +302,7 @@ async fn eth_flow_without_quote(web3: Web3) { test_order_availability_in_api( &services, ðflow_order, - &trader.address(), + &trader.address().into_alloy(), onchain.contracts(), ethflow_contract, ) @@ -330,11 +333,14 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { &test_submit_quote( &services, &(EthFlowTradeIntent { - sell_amount: 42.into(), - buy_token: dai.address().into_legacy(), - receiver: H160([42; 20]), + sell_amount: alloy::primitives::U256::from(42), + buy_token: *dai.address(), + receiver: Address::repeat_byte(42), }) - .to_quote_request(dummy_trader.account().address(), &onchain.contracts().weth), + .to_quote_request( + dummy_trader.account().address().into_alloy(), + &onchain.contracts().weth, + ), ) .await, valid_to, @@ -356,7 +362,7 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { // Create the actual order that should be picked up by the services and matched. let buy_token = dai.address().into_legacy(); - let receiver = H160([0x42; 20]); + let receiver = Address::repeat_byte(0x42); let sell_amount = to_wei(1); let valid_to = chrono::offset::Utc::now().timestamp() as u32 + timestamp_of_current_block_in_seconds(&web3.alloy) @@ -367,11 +373,14 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { &test_submit_quote( &services, &(EthFlowTradeIntent { - sell_amount, - buy_token, + sell_amount: sell_amount.into_alloy(), + buy_token: buy_token.into_alloy(), receiver, }) - .to_quote_request(trader.account().address(), &onchain.contracts().weth), + .to_quote_request( + trader.account().address().into_alloy(), + &onchain.contracts().weth, + ), ) .await, valid_to, @@ -451,7 +460,7 @@ async fn submit_order( async fn test_order_availability_in_api( services: &Services<'_>, order: &ExtendedEthFlowOrder, - owner: &H160, + owner: &Address, contracts: &Contracts, ethflow_contract: &CoWSwapEthFlow::Instance, ) { @@ -460,16 +469,26 @@ async fn test_order_availability_in_api( let is_available = || async { services.get_order(&uid).await.is_ok() }; wait_for_condition(TIMEOUT, is_available).await.unwrap(); - test_orders_query(services, order, owner, contracts, ethflow_contract).await; + test_orders_query( + services, + order, + &owner.into_legacy(), + contracts, + ethflow_contract, + ) + .await; // Api returns eth flow orders for both eth-flow contract address and actual // owner - for address in [owner, ðflow_contract.address().into_legacy()] { + for address in [ + &owner.into_legacy(), + ðflow_contract.address().into_legacy(), + ] { test_account_query( address, services.client(), order, - owner, + &owner.into_legacy(), contracts, ethflow_contract, ) @@ -821,18 +840,18 @@ impl From for EthFlowOrderOnchainS } pub struct EthFlowTradeIntent { - pub sell_amount: U256, - pub buy_token: H160, - pub receiver: H160, + pub sell_amount: alloy::primitives::U256, + pub buy_token: Address, + pub receiver: Address, } impl EthFlowTradeIntent { // How a user trade intent is converted into a quote request by the frontend - pub fn to_quote_request(&self, from: H160, weth: &WETH9::Instance) -> OrderQuoteRequest { + pub fn to_quote_request(&self, from: Address, weth: &WETH9::Instance) -> OrderQuoteRequest { OrderQuoteRequest { from, // Even if the user sells ETH, we request a quote for WETH - sell_token: weth.address().into_legacy(), + sell_token: *weth.address(), buy_token: self.buy_token, receiver: Some(self.receiver), validity: Validity::For(3600), @@ -843,7 +862,7 @@ impl EthFlowTradeIntent { }, side: OrderQuoteSide::Sell { sell_amount: model::quote::SellAmount::AfterFee { - value: NonZeroU256::try_from(self.sell_amount).unwrap(), + value: NonZeroU256::try_from(self.sell_amount.into_legacy()).unwrap(), }, }, buy_token_balance: BuyTokenDestination::Erc20, @@ -898,7 +917,7 @@ async fn eth_flow_zero_buy_amount(web3: Web3) { test_order_availability_in_api( &services, ðflow_order, - &trader.address(), + &trader.address().into_alloy(), onchain.contracts(), ethflow_contract, ) diff --git a/crates/e2e/tests/e2e/hooks.rs b/crates/e2e/tests/e2e/hooks.rs index d0006408c7..29a406ac74 100644 --- a/crates/e2e/tests/e2e/hooks.rs +++ b/crates/e2e/tests/e2e/hooks.rs @@ -647,9 +647,9 @@ async fn quote_verification(web3: Web3) { let quote = services .submit_quote(&OrderQuoteRequest { - from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(to_wei(5)).unwrap(), diff --git a/crates/e2e/tests/e2e/limit_orders.rs b/crates/e2e/tests/e2e/limit_orders.rs index 05156a58c6..7dfe8716cd 100644 --- a/crates/e2e/tests/e2e/limit_orders.rs +++ b/crates/e2e/tests/e2e/limit_orders.rs @@ -734,9 +734,9 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { .await; let quote_request = OrderQuoteRequest { - from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(to_wei(5)).unwrap(), @@ -894,8 +894,8 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { // may time out) let _ = services .submit_quote(&OrderQuoteRequest { - sell_token: token_usdc.address().into_legacy(), - buy_token: token_usdt.address().into_legacy(), + sell_token: *token_usdc.address(), + buy_token: *token_usdt.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei_with_exp(1000, 6).try_into().unwrap(), diff --git a/crates/e2e/tests/e2e/order_cancellation.rs b/crates/e2e/tests/e2e/order_cancellation.rs index c73e76a815..9b00fb1e43 100644 --- a/crates/e2e/tests/e2e/order_cancellation.rs +++ b/crates/e2e/tests/e2e/order_cancellation.rs @@ -1,10 +1,7 @@ use { database::order_events::OrderEventLabel, e2e::setup::{eth, *}, - ethrpc::alloy::{ - CallBuilderExt, - conversions::{IntoAlloy, IntoLegacy}, - }, + ethrpc::alloy::{CallBuilderExt, conversions::IntoAlloy}, model::{ order::{ CancellationPayload, @@ -92,9 +89,9 @@ async fn order_cancellation(web3: Web3) { let trader = &trader; let request = OrderQuoteRequest { - from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(to_wei(1)).unwrap(), diff --git a/crates/e2e/tests/e2e/place_order_with_quote.rs b/crates/e2e/tests/e2e/place_order_with_quote.rs index ab8ad8ade6..423fdb4e5d 100644 --- a/crates/e2e/tests/e2e/place_order_with_quote.rs +++ b/crates/e2e/tests/e2e/place_order_with_quote.rs @@ -63,9 +63,9 @@ async fn place_order_with_quote(web3: Web3) { tracing::info!("Quoting"); let quote_sell_amount = to_wei(1); let quote_request = OrderQuoteRequest { - from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(quote_sell_amount).unwrap(), diff --git a/crates/e2e/tests/e2e/protocol_fee.rs b/crates/e2e/tests/e2e/protocol_fee.rs index 6a3e5b5005..2139f5bc85 100644 --- a/crates/e2e/tests/e2e/protocol_fee.rs +++ b/crates/e2e/tests/e2e/protocol_fee.rs @@ -606,8 +606,8 @@ async fn get_quote( }, }; let quote_request = OrderQuoteRequest { - sell_token, - buy_token, + sell_token: sell_token.into_alloy(), + buy_token: buy_token.into_alloy(), side, validity: Validity::To(valid_to), ..Default::default() diff --git a/crates/e2e/tests/e2e/quote_verification.rs b/crates/e2e/tests/e2e/quote_verification.rs index 6f1f60a28b..b1e2585f35 100644 --- a/crates/e2e/tests/e2e/quote_verification.rs +++ b/crates/e2e/tests/e2e/quote_verification.rs @@ -18,7 +18,6 @@ use { number::nonzero::U256 as NonZeroU256, serde_json::json, shared::{ - addr, price_estimation::{ Estimate, Verification, @@ -109,9 +108,9 @@ async fn standard_verified_quote(web3: Web3) { // quote where the trader has sufficient balance and an approval set. let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: onchain.contracts().weth.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *token.address(), + buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(1).try_into().unwrap(), @@ -270,9 +269,9 @@ async fn verified_quote_eth_balance(web3: Web3) { ); let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(1).try_into().unwrap(), @@ -311,8 +310,8 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { services.start_protocol(solver.clone()).await; let request = OrderQuoteRequest { - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(3).try_into().unwrap(), @@ -324,7 +323,7 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where settlement contract is trader and implicit receiver let response = services .submit_quote(&OrderQuoteRequest { - from: onchain.contracts().gp_settlement.address().into_legacy(), + from: *onchain.contracts().gp_settlement.address(), receiver: None, ..request.clone() }) @@ -335,8 +334,8 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where settlement contract is trader and explicit receiver let response = services .submit_quote(&OrderQuoteRequest { - from: onchain.contracts().gp_settlement.address().into_legacy(), - receiver: Some(onchain.contracts().gp_settlement.address().into_legacy()), + from: *onchain.contracts().gp_settlement.address(), + receiver: Some(*onchain.contracts().gp_settlement.address()), ..request.clone() }) .await @@ -346,8 +345,8 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where settlement contract is trader and not the receiver let response = services .submit_quote(&OrderQuoteRequest { - from: onchain.contracts().gp_settlement.address().into_legacy(), - receiver: Some(trader.address()), + from: *onchain.contracts().gp_settlement.address(), + receiver: Some(trader.address().into_alloy()), ..request.clone() }) .await @@ -357,8 +356,8 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where a random trader sends funds to the settlement contract let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address(), - receiver: Some(onchain.contracts().gp_settlement.address().into_legacy()), + from: trader.address().into_alloy(), + receiver: Some(*onchain.contracts().gp_settlement.address()), ..request.clone() }) .await @@ -422,9 +421,9 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { ); let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address(), - sell_token: token.address().into_legacy(), - buy_token: weth.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *token.address(), + buy_token: *weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(1).try_into().unwrap(), @@ -465,9 +464,9 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { ); let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(1).try_into().unwrap(), @@ -483,9 +482,9 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // which is used when no wallet is connected in the frontend let response = services .submit_quote(&OrderQuoteRequest { - from: H160::zero(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: H160::zero().into_alloy(), + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(1).try_into().unwrap(), @@ -501,9 +500,9 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // if the user provided pre-interactions. This works now. let response = services .submit_quote(&OrderQuoteRequest { - from: H160::zero(), - sell_token: weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: H160::zero().into_alloy(), + sell_token: *weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(1).try_into().unwrap(), @@ -539,8 +538,8 @@ async fn usdt_quote_verification(web3: Web3) { let [solver] = onchain.make_solvers_forked(to_wei(1)).await; - let usdc = addr!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); - let usdt = addr!("dac17f958d2ee523a2206206994597c13d831ec7"); + let usdc = address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); + let usdt = address!("dac17f958d2ee523a2206206994597c13d831ec7"); // Place Orders let services = Services::new(&onchain).await; diff --git a/crates/e2e/tests/e2e/quoting.rs b/crates/e2e/tests/e2e/quoting.rs index 0711effbfe..e81176f27c 100644 --- a/crates/e2e/tests/e2e/quoting.rs +++ b/crates/e2e/tests/e2e/quoting.rs @@ -91,9 +91,9 @@ async fn test(web3: Web3) { tracing::info!("Quoting order"); let request = OrderQuoteRequest { - from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(to_wei(1)).unwrap(), @@ -229,9 +229,9 @@ async fn uses_stale_liquidity(web3: Web3) { services.start_protocol(solver).await; let quote = OrderQuoteRequest { - from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::new(to_wei(1)).unwrap(), @@ -330,9 +330,9 @@ async fn quote_timeout(web3: Web3) { })); let quote_request = |timeout| OrderQuoteRequest { - from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: sell_token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *sell_token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(to_wei(1)).unwrap(), @@ -462,9 +462,9 @@ async fn volume_fee(web3: Web3) { tracing::info!("Testing SELL quote with volume fee"); let sell_request = OrderQuoteRequest { - from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: NonZeroU256::try_from(to_wei(1)).unwrap(), @@ -481,9 +481,9 @@ async fn volume_fee(web3: Web3) { tracing::info!("Testing BUY quote with volume fee"); let buy_request = OrderQuoteRequest { - from: trader.address(), - sell_token: onchain.contracts().weth.address().into_legacy(), - buy_token: token.address().into_legacy(), + from: trader.address().into_alloy(), + sell_token: *onchain.contracts().weth.address(), + buy_token: *token.address(), side: OrderQuoteSide::Buy { buy_amount_after_fee: NonZeroU256::try_from(to_wei(1)).unwrap(), }, diff --git a/crates/e2e/tests/e2e/refunder.rs b/crates/e2e/tests/e2e/refunder.rs index badd6f96d2..29d6346baf 100644 --- a/crates/e2e/tests/e2e/refunder.rs +++ b/crates/e2e/tests/e2e/refunder.rs @@ -1,11 +1,12 @@ use { crate::ethflow::{EthFlowOrderOnchainStatus, ExtendedEthFlowOrder}, + ::alloy::primitives::Address, chrono::{TimeZone, Utc}, e2e::{nodes::local_node::TestNodeApi, setup::*}, - ethcontract::{H160, U256}, + ethcontract::U256, ethrpc::{ Web3, - alloy::conversions::{IntoAlloy, IntoLegacy, TryIntoAlloyAsync}, + alloy::conversions::{IntoAlloy, TryIntoAlloyAsync}, block_stream::timestamp_of_current_block_in_seconds, }, model::quote::{OrderQuoteRequest, OrderQuoteSide, QuoteSigningScheme, Validity}, @@ -33,14 +34,14 @@ async fn refunder_tx(web3: Web3) { services.start_protocol(solver).await; // Get quote id for order placement - let buy_token = token.address().into_legacy(); - let receiver = Some(H160([42; 20])); + let buy_token = *token.address(); + let receiver = Some(Address::repeat_byte(42)); let sell_amount = U256::from("3000000000000000"); let ethflow_contract = onchain.contracts().ethflows.first().unwrap(); let quote = OrderQuoteRequest { - from: ethflow_contract.address().into_legacy(), - sell_token: onchain.contracts().weth.address().into_legacy(), + from: *ethflow_contract.address(), + sell_token: *onchain.contracts().weth.address(), buy_token, receiver, validity: Validity::For(3600), @@ -71,8 +72,8 @@ async fn refunder_tx(web3: Web3) { let ethflow_contract_2 = onchain.contracts().ethflows.get(1).unwrap(); let quote = OrderQuoteRequest { - from: ethflow_contract_2.address().into_legacy(), - sell_token: onchain.contracts().weth.address().into_legacy(), + from: *ethflow_contract_2.address(), + sell_token: *onchain.contracts().weth.address(), buy_token, receiver, validity: Validity::For(3600), diff --git a/crates/e2e/tests/e2e/wrapper.rs b/crates/e2e/tests/e2e/wrapper.rs index 2d7c2b800a..55b07a95bc 100644 --- a/crates/e2e/tests/e2e/wrapper.rs +++ b/crates/e2e/tests/e2e/wrapper.rs @@ -136,8 +136,8 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { // Warm up co-located driver by quoting the order let _ = services .submit_quote(&OrderQuoteRequest { - sell_token: token_weth.address().into_legacy(), - buy_token: token_usdc.address().into_legacy(), + sell_token: *token_weth.address(), + buy_token: *token_usdc.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { value: to_wei(1).try_into().unwrap(), diff --git a/crates/model/src/quote.rs b/crates/model/src/quote.rs index 8e10f563c7..171fbd9da5 100644 --- a/crates/model/src/quote.rs +++ b/crates/model/src/quote.rs @@ -4,6 +4,7 @@ use { signature::SigningScheme, time, }, + alloy::primitives::Address, anyhow::bail, app_data::AppDataHash, chrono::{DateTime, Utc}, @@ -120,11 +121,11 @@ impl TryFrom for QuoteSigningScheme { #[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct OrderQuoteRequest { - pub from: H160, - pub sell_token: H160, - pub buy_token: H160, + pub from: Address, + pub sell_token: Address, + pub buy_token: Address, #[serde(skip_serializing_if = "Option::is_none")] - pub receiver: Option, + pub receiver: Option
, #[serde(flatten)] pub side: OrderQuoteSide, #[serde(flatten)] @@ -466,8 +467,8 @@ mod tests { }), ]; let expected_standard_response = OrderQuoteRequest { - 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() }; let modify_signing_scheme = |signing_scheme: QuoteSigningScheme| { diff --git a/crates/orderbook/src/api/post_quote.rs b/crates/orderbook/src/api/post_quote.rs index 9d087ef787..46d18a06cd 100644 --- a/crates/orderbook/src/api/post_quote.rs +++ b/crates/orderbook/src/api/post_quote.rs @@ -88,6 +88,7 @@ mod tests { use { super::*, crate::api::response_body, + alloy::primitives::Address, anyhow::anyhow, app_data::AppDataHash, chrono::{TimeZone, Utc}, @@ -130,9 +131,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), receiver: None, side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { @@ -169,9 +170,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), receiver: None, side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { @@ -203,10 +204,10 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), - receiver: Some(H160([0x04; 20])), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), + receiver: Some(Address::repeat_byte(0x04)), side: OrderQuoteSide::Buy { buy_amount_after_fee: NonZeroU256::try_from(1337).unwrap(), }, @@ -229,9 +230,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(1337).unwrap() @@ -255,9 +256,9 @@ mod tests { })) .unwrap(), OrderQuoteRequest { - from: H160([0x01; 20]), - sell_token: H160([0x02; 20]), - buy_token: H160([0x03; 20]), + from: Address::repeat_byte(0x01), + sell_token: Address::repeat_byte(0x02), + buy_token: Address::repeat_byte(0x03), side: OrderQuoteSide::Sell { sell_amount: SellAmount::AfterFee { value: NonZeroU256::try_from(1337).unwrap() diff --git a/crates/orderbook/src/quoter.rs b/crates/orderbook/src/quoter.rs index dc73b46b31..dec7eb7769 100644 --- a/crates/orderbook/src/quoter.rs +++ b/crates/orderbook/src/quoter.rs @@ -5,7 +5,7 @@ use { }, alloy::primitives::{U256, U512, Uint, ruint::UintTryFrom}, chrono::{TimeZone, Utc}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethrpc::alloy::conversions::IntoLegacy, model::{ order::OrderCreationAppData, quote::{OrderQuote, OrderQuoteRequest, OrderQuoteResponse, OrderQuoteSide, PriceQuality}, @@ -90,12 +90,12 @@ impl QuoteHandler { self.order_validator.partial_validate(order).await?; let params = QuoteParameters { - sell_token: request.sell_token.into_alloy(), - buy_token: request.buy_token.into_alloy(), + sell_token: request.sell_token, + buy_token: request.buy_token, side: request.side, verification: Verification { - from: request.from.into_alloy(), - receiver: request.receiver.unwrap_or(request.from).into_alloy(), + from: request.from, + receiver: request.receiver.unwrap_or(request.from), sell_token_source: request.sell_token_balance, buy_token_destination: request.buy_token_balance, pre_interactions: trade_finding::map_interactions(&app_data.interactions.pre), @@ -129,9 +129,9 @@ impl QuoteHandler { .map_err(|err| OrderQuoteError::CalculateQuote(err.into()))?; let response = OrderQuoteResponse { quote: OrderQuote { - sell_token: request.sell_token, - buy_token: request.buy_token, - receiver: request.receiver, + sell_token: request.sell_token.into_legacy(), + buy_token: request.buy_token.into_legacy(), + receiver: request.receiver.map(IntoLegacy::into_legacy), sell_amount: adjusted_quote.sell_amount.into_legacy(), buy_amount: adjusted_quote.buy_amount.into_legacy(), valid_to, @@ -149,7 +149,7 @@ impl QuoteHandler { buy_token_balance: request.buy_token_balance, signing_scheme: request.signing_scheme.into(), }, - from: request.from, + from: request.from.into_legacy(), expiration: quote.data.expiration, id: quote.id, verified: quote.data.verified, diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 1905eaa81e..9d7bd35de6 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -694,10 +694,10 @@ impl From<&OrderQuoteRequest> for PreOrderData { fn from(quote_request: &OrderQuoteRequest) -> Self { let owner = quote_request.from; Self { - owner, - sell_token: quote_request.sell_token, - buy_token: quote_request.buy_token, - receiver: quote_request.receiver.unwrap_or(owner), + 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(), valid_to: quote_request.validity.actual_valid_to(), partially_fillable: false, buy_token_balance: quote_request.buy_token_balance, From bcb5e34c08edbca04c5468390705a7a82ecdffa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Wed, 26 Nov 2025 16:06:04 +0000 Subject: [PATCH 016/470] Implement build.rs bindings generation (#3827) # Description Implements bindings generation in `build.rs`, adding this allows 1. Generated code to be inspected manually and "cmd-click"ed into 2. Faster incremental compilation since the code can be cached unlike macros # Changes - [ ] New contracts-generate crate to simplify build.rs code - [ ] Generate bindings in contracts build.rs - [ ] Migrate everything without changing any module paths - [ ] Moved away from the Provider re-export (`contracts::alloy::Provider` -> `alloy::providers::DynProvider`) - [ ] Removes the ethcontract re-export from the contracts crate - [ ] Removes now unused code (some inconsistent tests and dummy legacy things) ## How to test Run existing tests & compile --- Cargo.lock | 150 ++- Cargo.toml | 7 + .../src/boundary/events/settlement.rs | 2 +- .../ethflow_events/event_retriever.rs | 2 +- .../onchain_order_events/event_retriever.rs | 2 +- .../src/database/onchain_order_events/mod.rs | 2 +- .../src/infra/blockchain/contracts.rs | 1 - crates/autopilot/src/run.rs | 2 +- crates/contracts/.gitignore | 2 + crates/contracts/Cargo.toml | 13 +- crates/contracts/build.rs | 1186 +++++++++++++++++ crates/contracts/src/alloy.rs | 988 -------------- crates/contracts/src/lib.rs | 83 +- crates/contracts/src/macros.rs | 6 - crates/contracts/src/web3.rs | 44 - .../driver/src/boundary/liquidity/zeroex.rs | 1 - crates/e2e/src/setup/deploy.rs | 1 - .../e2e/src/setup/onchain_components/safe.rs | 6 +- crates/e2e/tests/e2e/liquidity.rs | 2 +- .../e2e/liquidity_source_notification.rs | 2 +- crates/orderbook/src/run.rs | 1 - crates/shared/src/bad_token/trace_call.rs | 2 +- crates/shared/src/event_handling.rs | 4 +- .../sources/balancer_v2/pool_fetching/mod.rs | 1 - .../src/boundary/liquidity/concentrated.rs | 10 +- .../src/boundary/liquidity/limit_order.rs | 4 +- crates/solvers/src/domain/solver.rs | 1 - 27 files changed, 1326 insertions(+), 1199 deletions(-) create mode 100644 crates/contracts/.gitignore create mode 100644 crates/contracts/build.rs delete mode 100644 crates/contracts/src/alloy.rs delete mode 100644 crates/contracts/src/macros.rs delete mode 100644 crates/contracts/src/web3.rs diff --git a/Cargo.lock b/Cargo.lock index 23628c0732..8069c1f926 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,7 +453,7 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -641,7 +641,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -658,7 +658,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", "syn-solidity", "tiny-keccak", ] @@ -677,7 +677,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.104", + "syn 2.0.108", "syn-solidity", ] @@ -784,7 +784,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -964,7 +964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -1002,7 +1002,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -1120,7 +1120,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -1131,7 +1131,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -1179,7 +1179,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -1861,7 +1861,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", "syn_derive", ] @@ -2047,7 +2047,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -2203,13 +2203,21 @@ name = "contracts" version = "0.1.0" dependencies = [ "alloy", + "alloy-sol-macro-expander", + "alloy-sol-macro-input", "anyhow", "ethcontract", "ethcontract-generate", "paste", + "prettyplease", + "proc-macro2", + "quote", + "serde", "serde_json", + "syn 2.0.108", "tracing", "tracing-subscriber", + "walkdir", ] [[package]] @@ -2459,7 +2467,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -2474,7 +2482,7 @@ dependencies = [ "quote", "serde", "strsim", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -2485,7 +2493,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core 0.20.9", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -2496,7 +2504,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -2628,7 +2636,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", "unicode-xid", ] @@ -2640,7 +2648,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", "unicode-xid", ] @@ -2817,7 +2825,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -2875,7 +2883,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -2986,7 +2994,7 @@ dependencies = [ "ethcontract-generate", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -3000,7 +3008,7 @@ dependencies = [ "ethcontract-common", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", "url", ] @@ -3290,7 +3298,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -4217,7 +4225,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -4359,7 +4367,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -4589,7 +4597,7 @@ checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -4694,7 +4702,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -4986,7 +4994,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -5090,6 +5098,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.108", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -5154,14 +5172,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -5253,7 +5271,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -5266,7 +5284,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -5328,9 +5346,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -5938,6 +5956,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.23" @@ -6109,7 +6136,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -6181,7 +6208,7 @@ dependencies = [ "darling 0.20.9", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -6746,7 +6773,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -6768,9 +6795,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -6786,7 +6813,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -6798,7 +6825,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -6904,7 +6931,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -6915,7 +6942,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -7032,7 +7059,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -7294,7 +7321,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -7567,6 +7594,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -7644,7 +7681,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", "wasm-bindgen-shared", ] @@ -7678,7 +7715,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7798,6 +7835,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -7844,7 +7890,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -7855,7 +7901,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -8139,7 +8185,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] [[package]] @@ -8159,5 +8205,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.108", ] diff --git a/Cargo.toml b/Cargo.toml index 9da5d9bfaf..1c3fd432ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,6 +99,13 @@ tower-http = "0.4" tracing-opentelemetry = "0.31" tracing-serde = "0.2" vergen = "8" +walkdir = "2.5.0" +quote = "1.0.41" +syn = "2.0.108" +prettyplease = "0.2.37" +proc-macro2 = "1.0.103" +alloy-sol-macro-input = "1.4.1" +alloy-sol-macro-expander = "1.4.1" [workspace.lints] clippy.cast_possible_wrap = "deny" diff --git a/crates/autopilot/src/boundary/events/settlement.rs b/crates/autopilot/src/boundary/events/settlement.rs index 1520b67b21..e58ea68ce9 100644 --- a/crates/autopilot/src/boundary/events/settlement.rs +++ b/crates/autopilot/src/boundary/events/settlement.rs @@ -28,7 +28,7 @@ impl AlloyEventRetrieving for GPv2SettlementContract { Filter::new().address(self.address) } - fn provider(&self) -> &contracts::alloy::Provider { + fn provider(&self) -> &alloy::providers::DynProvider { &self.provider } } diff --git a/crates/autopilot/src/database/ethflow_events/event_retriever.rs b/crates/autopilot/src/database/ethflow_events/event_retriever.rs index f4bcd5e4df..aa7ae2e83a 100644 --- a/crates/autopilot/src/database/ethflow_events/event_retriever.rs +++ b/crates/autopilot/src/database/ethflow_events/event_retriever.rs @@ -29,7 +29,7 @@ impl EthFlowRefundRetriever { impl AlloyEventRetrieving for EthFlowRefundRetriever { type Event = CoWSwapEthFlow::CoWSwapEthFlowEvents; - fn provider(&self) -> &contracts::alloy::Provider { + fn provider(&self) -> &alloy::providers::DynProvider { &self.web3.alloy } diff --git a/crates/autopilot/src/database/onchain_order_events/event_retriever.rs b/crates/autopilot/src/database/onchain_order_events/event_retriever.rs index ed99df97bf..bde093e170 100644 --- a/crates/autopilot/src/database/onchain_order_events/event_retriever.rs +++ b/crates/autopilot/src/database/onchain_order_events/event_retriever.rs @@ -42,7 +42,7 @@ impl AlloyEventRetrieving for CoWSwapOnchainOrdersContract { ])) } - fn provider(&self) -> &contracts::alloy::Provider { + fn provider(&self) -> &alloy::providers::DynProvider { &self.web3.alloy } } diff --git a/crates/autopilot/src/database/onchain_order_events/mod.rs b/crates/autopilot/src/database/onchain_order_events/mod.rs index cdaab8fed3..b460768d80 100644 --- a/crates/autopilot/src/database/onchain_order_events/mod.rs +++ b/crates/autopilot/src/database/onchain_order_events/mod.rs @@ -786,7 +786,7 @@ mod test { super::*, crate::database::Config, alloy::primitives::U256, - contracts::alloy::{CoWSwapOnchainOrders, InstanceExt}, + contracts::alloy::CoWSwapOnchainOrders, database::{byte_array::ByteArray, onchain_broadcasted_orders::OnchainOrderPlacement}, ethcontract::H160, ethrpc::Web3, diff --git a/crates/autopilot/src/infra/blockchain/contracts.rs b/crates/autopilot/src/infra/blockchain/contracts.rs index bae638ad3f..11dd601f51 100644 --- a/crates/autopilot/src/infra/blockchain/contracts.rs +++ b/crates/autopilot/src/infra/blockchain/contracts.rs @@ -6,7 +6,6 @@ use { GPv2AllowListAuthentication, GPv2Settlement, HooksTrampoline, - InstanceExt, WETH9, support::Balances, }, diff --git a/crates/autopilot/src/run.rs b/crates/autopilot/src/run.rs index e59bd23a98..f27d667bc1 100644 --- a/crates/autopilot/src/run.rs +++ b/crates/autopilot/src/run.rs @@ -27,7 +27,7 @@ use { alloy::eips::BlockNumberOrTag, chain::Chain, clap::Parser, - contracts::alloy::{BalancerV2Vault, GPv2Settlement, IUniswapV3Factory, InstanceExt, WETH9}, + contracts::alloy::{BalancerV2Vault, GPv2Settlement, IUniswapV3Factory, WETH9}, ethcontract::H160, ethrpc::{ Web3, diff --git a/crates/contracts/.gitignore b/crates/contracts/.gitignore new file mode 100644 index 0000000000..1884d50914 --- /dev/null +++ b/crates/contracts/.gitignore @@ -0,0 +1,2 @@ +# Generated by build.rs, will contain the contract bindings +src/alloy diff --git a/crates/contracts/Cargo.toml b/crates/contracts/Cargo.toml index dbd069dbe8..04ad803035 100644 --- a/crates/contracts/Cargo.toml +++ b/crates/contracts/Cargo.toml @@ -22,8 +22,9 @@ bin = [ [dependencies] alloy = { workspace = true, features = ["sol-types", "json", "contract", "json-abi"] } -paste = { workspace = true } ethcontract = { workspace = true } +paste = { workspace = true } +serde = { workspace = true } serde_json = { workspace = true } # [bin-dependencies] @@ -33,8 +34,14 @@ tracing = { workspace = true, optional = true } tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"], optional = true } [build-dependencies] -ethcontract = { workspace = true } -ethcontract-generate = { workspace = true } +anyhow = { workspace = true } +alloy-sol-macro-expander = {workspace = true} +alloy-sol-macro-input = {workspace = true, features = ["json"]} +prettyplease = {workspace = true} +proc-macro2 = {workspace = true} +quote = {workspace = true} +syn = {workspace = true} +walkdir = {workspace = true} [lints] workspace = true diff --git a/crates/contracts/build.rs b/crates/contracts/build.rs new file mode 100644 index 0000000000..29bdab7bef --- /dev/null +++ b/crates/contracts/build.rs @@ -0,0 +1,1186 @@ +use { + alloy_sol_macro_expander::expand::expand, + alloy_sol_macro_input::{SolInput, SolInputKind}, + anyhow::{Context, Result}, + networks::*, + proc_macro2::{Span, TokenStream}, + quote::{ToTokens, format_ident}, + std::{ + collections::HashMap, + fmt::Write, + path::{Path, PathBuf}, + }, +}; + +mod networks { + pub const MAINNET: u64 = 1; + pub const GNOSIS: u64 = 100; + pub const SEPOLIA: u64 = 11155111; + pub const ARBITRUM_ONE: u64 = 42161; + pub const BASE: u64 = 8453; + pub const POLYGON: u64 = 137; + pub const AVALANCHE: u64 = 43114; + pub const BNB: u64 = 56; + pub const OPTIMISM: u64 = 10; + pub const LENS: u64 = 232; + pub const LINEA: u64 = 59144; + pub const PLASMA: u64 = 9745; +} + +/// Declare a network tuple with an optional block number. +/// +/// Example, without blocks: +/// ```no_run +/// # #[macro_use] extern crate contracts_generate; +/// # use contracts_generate::networks::{MAINNET, SEPOLIA}; +/// # fn main() { +/// # let _: [(_, (_, Option)); _] = +/// networks! { +/// MAINNET => "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", +/// SEPOLIA => "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", +/// }; +/// # } +/// ``` +/// +/// Example, with blocks: +/// ```no_run +/// # #[macro_use] extern crate contracts_generate; +/// # use contracts_generate::networks::{MAINNET, SEPOLIA}; +/// # fn main() { +/// # let _: [(_, (_, Option)); _] = +/// networks! { +/// MAINNET => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 12593265), +/// SEPOLIA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 4717488), +/// }; +/// # } +/// ``` +#[macro_export] +macro_rules! networks { + // Entry point: accepts a list of entries and delegates to internal rules + [$( + $id:expr => $value:tt + ),* $(,)?] => { + [$( + networks!(@entry $id => $value) + ),*] + }; + + // Internal rule: handle entry with address and block (parenthesized) + (@entry $id:expr => ($addr:expr, $block:expr)) => { + ($id, ($addr, Some($block))) + }; + + // Internal rule: handle entry with just address + (@entry $id:expr => $value:expr) => { + ($id, ($value, None)) + }; +} + +fn main() { + // NOTE: This is a workaround for `rerun-if-changed` directives for + // non-existent files cause the crate's build unit to get flagged for a + // rebuild if any files in the workspace change. + // + // See: + // - https://github.com/rust-lang/cargo/issues/6003 + // - https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=artifacts/"); + + // Path to the directory containing the vendored contract artifacts. + let vendored_bindings = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("alloy"); + + Module::default() + // 0x + .add_contract(Contract::new("IZeroex").with_networks(networks![ + MAINNET => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + SEPOLIA => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + ARBITRUM_ONE => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + BASE => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + AVALANCHE => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + BNB => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + OPTIMISM => "0xdef1abe32c034e558cdd535791643c58a13acc10", + POLYGON => "0xdef1c0ded9bec7f1a1670819833240f027b25eff", + // Not available on Lens + ])) + // Misc + .add_contract(Contract::new("ERC20")) + .add_contract(Contract::new("ERC20Mintable")) + // GnosisSafe + .add_contract(Contract::new("GnosisSafe")) + .add_contract(Contract::new("GnosisSafeCompatibilityFallbackHandler")) + .add_contract(Contract::new("GnosisSafeProxy")) + .add_contract(Contract::new("GnosisSafeProxyFactory")) + // Balancer V2 + .add_contract(Contract::new("BalancerV2Authorizer")) + .add_contract(Contract::new("BalancerV2BasePool")) + .add_contract(Contract::new("BalancerV2BasePoolFactory")) + .add_contract(Contract::new("BalancerV2WeightedPool")) + .add_contract(Contract::new("BalancerV2StablePool")) + .add_contract(Contract::new("BalancerV2ComposableStablePool")) + .add_contract(Contract::new("BalancerV2LiquidityBootstrappingPool")) + // + .add_contract( + Contract::new("BalancerV2WeightedPoolFactory").with_networks(networks![ + // + MAINNET => ("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9", 12272147), + // Not available on Sepolia (only version ≥ 4) + // + // Not available on Lens + ]), + ) + // + .add_contract( + Contract::new("BalancerV2WeightedPoolFactoryV3").with_networks(networks![ + // + MAINNET => ("0x5Dd94Da3644DDD055fcf6B3E1aa310Bb7801EB8b", 16520627), + // + GNOSIS => ("0xC128a9954e6c874eA3d62ce62B468bA073093F25", 26226256), + // + AVALANCHE => ("0x94f68b54191F62f781Fe8298A8A5Fa3ed772d227", 26389236), + // + OPTIMISM => ("0xA0DAbEBAAd1b243BBb243f933013d560819eB66f", 72832703), + // + POLYGON => ("0x82e4cFaef85b1B6299935340c964C942280327f4", 39036828), + // + BNB => ("0x6e4cF292C5349c79cCd66349c3Ed56357dD11B46", 25474982), + // Not available on Sepolia (only version ≥ 4) + // + // Not available on Lens + ]), + ) + .add_contract( + Contract::new("BalancerV2WeightedPoolFactoryV4").with_networks(networks![ + // + MAINNET => ("0x897888115Ada5773E02aA29F775430BFB5F34c51", 16878323), + // + GNOSIS => ("0x6CaD2ea22BFA7F4C14Aae92E47F510Cd5C509bc7", 27055829), + // + // + SEPOLIA => ("0x7920BFa1b2041911b354747CA7A6cDD2dfC50Cfd", 3424893), + // + ARBITRUM_ONE => ("0xc7E5ED1054A24Ef31D827E6F86caA58B3Bc168d7", 72222060), + // + BASE => ("0x4C32a8a8fDa4E24139B51b456B42290f51d6A1c4", 1204869), + // + AVALANCHE => ("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a", 27739006), + // + OPTIMISM => ("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a", 82737545), + // + POLYGON => ("0xFc8a407Bba312ac761D8BFe04CE1201904842B76", 40611103), + // + BNB => ("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a", 26665331), + // Not available on Base and Lens + // + ]), + ) + // + .add_contract( + Contract::new("BalancerV2WeightedPool2TokensFactory").with_networks(networks![ + // + MAINNET => ("0xa5bf2ddf098bb0ef6d120c98217dd6b141c74ee0", 12349891), + ARBITRUM_ONE => ("0xCF0a32Bbef8F064969F21f7e02328FB577382018", 222864), + // + OPTIMISM => ("0xdAE7e32ADc5d490a43cCba1f0c736033F2b4eFca", 7005512), + // + POLYGON => ("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9", 15832998), + // Not available on Sepolia, Base, Avalanche, BNB and Lens + // + // + ]), + ) + // + .add_contract( + Contract::new("BalancerV2StablePoolFactoryV2").with_networks(networks![ + // + MAINNET => ("0x8df6efec5547e31b0eb7d1291b511ff8a2bf987c", 14934936), + // + GNOSIS => ("0xf23b4DB826DbA14c0e857029dfF076b1c0264843", 25415344), + ARBITRUM_ONE => ("0xEF44D6786b2b4d544b7850Fe67CE6381626Bf2D6", 14244664), + // + OPTIMISM => ("0xeb151668006CD04DAdD098AFd0a82e78F77076c3", 11088891), + // + POLYGON => ("0xcA96C4f198d343E251b1a01F3EBA061ef3DA73C1", 29371951), + // Not available on Sepolia, Base, Avalanche, BNB and Lens + // + // + ]), + ) + // + .add_contract( + Contract::new("BalancerV2LiquidityBootstrappingPoolFactory").with_networks(networks![ + // + MAINNET => ("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE", 12871780), + ARBITRUM_ONE => ("0x142B9666a0a3A30477b052962ddA81547E7029ab", 222870), + // + POLYGON => ("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE", 17116402), + // Not available on Sepolia, Base, Avalanche, BNB, Optimism and Lens + // + // + ]), + ) + // + .add_contract( + Contract::new("BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory") + .with_networks(networks![ + // + MAINNET => ("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e", 13730248), + // + // + GNOSIS => ("0x85a80afee867aDf27B50BdB7b76DA70f1E853062", 25415236), + // + // + SEPOLIA => ("0x45fFd460cC6642B8D8Fb12373DFd77Ceb0f4932B", 25415236), + ARBITRUM_ONE => ("0x1802953277FD955f9a254B80Aa0582f193cF1d77", 4859669), + // + BASE => ("0x0c6052254551EAe3ECac77B01DFcf1025418828f", 1206531), + // + AVALANCHE => ("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e", 26386552), + // + BNB => ("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD", 22691243), + // + OPTIMISM => ("0xf302f9F50958c5593770FDf4d4812309fF77414f", 7005915), + // + POLYGON => ("0x41B953164995c11C81DA73D212ED8Af25741b7Ac", 22067480), + // Not available on Lens + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactory").with_networks(networks![ + // + MAINNET => ("0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F", 15485885), + ARBITRUM_ONE => ("0xaEb406b0E430BF5Ea2Dc0B9Fe62E4E53f74B3a33", 23227044), + // + BNB => ("0xf302f9F50958c5593770FDf4d4812309fF77414f", 22691193), + // + OPTIMISM => ("0xf145caFB67081895EE80eB7c04A30Cf87f07b745", 22182522), + // + POLYGON => ("0x136FD06Fa01eCF624C7F2B3CB15742c1339dC2c4", 32774224), + // Not available on Sepolia, Gnosis Chain, Base, Avalanche and Lens + // + // + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV3").with_networks(networks![ + // + MAINNET => ("0xdba127fBc23fb20F5929C546af220A991b5C6e01", 16580899), + // + GNOSIS => ("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD", 26365805), + ARBITRUM_ONE => ("0x1c99324EDC771c82A0DCCB780CC7DDA0045E50e7", 58948370), + // + BNB => ("0xacAaC3e6D6Df918Bf3c809DFC7d42de0e4a72d4C", 25475700), + // + OPTIMISM => ("0xe2E901AB09f37884BA31622dF3Ca7FC19AA443Be", 72832821), + // + POLYGON => ("0x7bc6C0E73EDAa66eF3F6E2f27b0EE8661834c6C9", 39037615), + // Not available on Sepolia (only version ≥ 4) and on Base (only version ≥ 5) + // + // + // Not available on Lens + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV4").with_networks(networks![ + // + MAINNET => ("0xfADa0f4547AB2de89D1304A668C39B3E09Aa7c76", 16878679), + // + GNOSIS => ("0xD87F44Df0159DC78029AB9CA7D7e57E7249F5ACD", 27056416), + // + // + SEPOLIA => ("0xA3fd20E29358c056B727657E83DFd139abBC9924", 3425277), + ARBITRUM_ONE => ("0x2498A2B0d6462d2260EAC50aE1C3e03F4829BA95", 72235860), + // + AVALANCHE => ("0x3B1eb8EB7b43882b385aB30533D9A2BeF9052a98", 29221425), + // + BNB => ("0x1802953277FD955f9a254B80Aa0582f193cF1d77", 26666380), + // + OPTIMISM => ("0x1802953277FD955f9a254B80Aa0582f193cF1d77", 82748180), + // + POLYGON => ("0x6Ab5549bBd766A43aFb687776ad8466F8b42f777", 40613553), + // Not available on Base and Lens + // + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV5").with_networks(networks![ + // + MAINNET => ("0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A", 17672478), + // + GNOSIS => ("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7", 28900564), + // + // + SEPOLIA => ("0xa523f47A933D5020b23629dDf689695AA94612Dc", 3872211), + ARBITRUM_ONE => ("0xA8920455934Da4D853faac1f94Fe7bEf72943eF1", 110212282), + // + BASE => ("0x8df317a729fcaA260306d7de28888932cb579b88", 1204710), + // + AVALANCHE => ("0xE42FFA682A26EF8F25891db4882932711D42e467", 32478827), + // + BNB => ("0x4fb47126Fa83A8734991E41B942Ac29A3266C968", 29877945), + // + OPTIMISM => ("0x043A2daD730d585C44FB79D2614F295D2d625412", 106752707), + // + POLYGON => ("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b", 44961548), + // Not available on Lens + ]), + ) + .add_contract( + Contract::new("BalancerV2ComposableStablePoolFactoryV6").with_networks(networks![ + // + MAINNET => ("0x5B42eC6D40f7B7965BE5308c70e2603c0281C1E9", 19314764), + // + GNOSIS => ("0x47B489bf5836f83ABD928C316F8e39bC0587B020", 32650879), + // + SEPOLIA => ("0x05503B3aDE04aCA81c8D6F88eCB73Ba156982D2B", 5369821), + // + ARBITRUM_ONE => ("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7", 184805448), + // + BASE => ("0x956CCab09898C0AF2aCa5e6C229c3aD4E93d9288", 11099703), + // + AVALANCHE => ("0xb9F8AB3ED3F3aCBa64Bc6cd2DcA74B7F38fD7B88", 42186350), + // + BNB => ("0x6B5dA774890Db7B7b96C6f44e6a4b0F657399E2e", 36485719), + // + OPTIMISM => ("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7", 116694338), + // + POLYGON => ("0xEAedc32a51c510d35ebC11088fD5fF2b47aACF2E", 53996258), + // Not available on Lens + ]), + ) + // Balancer addresses can be obtained from: + // + .add_contract(Contract::new("BalancerV2Vault").with_networks(networks![ + // + MAINNET => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 12272146), + // + GNOSIS => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 24821598), + // + SEPOLIA => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 3418831), + // + ARBITRUM_ONE => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 222832), + // + BASE => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 1196036), + // + AVALANCHE => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 26386141), + // + BNB => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 22691002), + // + OPTIMISM => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 7003431), + // + POLYGON => ("0xBA12222222228d8Ba445958a75a0704d566BF2C8", 15832990), + // Not available on Lens + ])) + .add_contract( + Contract::new("BalancerV3BatchRouter").with_networks(networks![ + // + MAINNET => ("0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", 21339510), + // + GNOSIS => ("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b", 37377506), + // + SEPOLIA => ("0xC85b652685567C1B074e8c0D4389f83a2E458b1C", 7219301), + // + ARBITRUM_ONE => ("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E", 297828544), + // + BASE => ("0x85a80afee867aDf27B50BdB7b76DA70f1E853062", 25347205), + // + AVALANCHE => ("0xc9b36096f5201ea332Db35d6D195774ea0D5988f", 59965747), + // + OPTIMISM => ("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E", 133969588), + // Not available on Lens, Polygon, BNB + ]), + ) + // UniV2 + .add_contract(Contract::new("BaoswapRouter").with_networks(networks![ + // https://gnosisscan.io/tx/0xdcbfa037f2c6c7456022df0632ec8d6a75d0f9a195238eec679d5d26895eb7b1 + GNOSIS => "0x6093AeBAC87d62b1A5a4cEec91204e35020E38bE", + ])) + .add_contract(Contract::new("HoneyswapRouter").with_networks(networks![ + GNOSIS => "0x1C232F01118CB8B424793ae03F870aa7D0ac7f77", + ])) + .add_contract(Contract::new("PancakeRouter").with_networks(networks![ + // + MAINNET => "0xEfF92A263d31888d860bD50809A8D171709b7b1c", + // + ARBITRUM_ONE => "0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb", + // + BASE => "0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb", + // + BNB => "0x10ED43C718714eb63d5aA57B78B54704E256024E", + ])) + // + .add_contract(Contract::new("SushiSwapRouter").with_networks(networks![ + // + MAINNET => "0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f", + // + GNOSIS => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + // + ARBITRUM_ONE => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + // + BASE => "0x6bded42c6da8fbf0d2ba55b2fa120c5e0c8d7891", + // + AVALANCHE => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + // + BNB => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + // + OPTIMISM => "0x2abf469074dc0b54d793850807e6eb5faf2625b1", + // + POLYGON => "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", + // Not available on Lens + ])) + // + .add_contract(Contract::new("SwaprRouter").with_networks(networks![ + // + MAINNET => "0xb9960d9bca016e9748be75dd52f02188b9d0829f", + // + GNOSIS => "0xE43e60736b1cb4a75ad25240E2f9a62Bff65c0C0", + // + ARBITRUM_ONE => "0x530476d5583724A89c8841eB6Da76E7Af4C0F17E", + // Not available on Base and Lens + ])) + .add_contract(Contract::new("ISwaprPair")) + .add_contract( + Contract::new("TestnetUniswapV2Router02").with_networks(networks![ + // + SEPOLIA => "0x86dcd3293C53Cf8EFd7303B57beb2a3F671dDE98", + ]), + ) + // + .add_contract(Contract::new("UniswapV2Factory").with_networks(networks![ + // + MAINNET => "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f", + // + GNOSIS => "0xA818b4F111Ccac7AA31D0BCc0806d64F2E0737D7", + // + ARBITRUM_ONE => "0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9", + // + BASE => "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", + // + SEPOLIA => "0xF62c03E08ada871A0bEb309762E260a7a6a880E6", + // + AVALANCHE => "0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C", + // + BNB => "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6", + // + OPTIMISM => "0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf", + // + POLYGON => "0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C", + // Not available on Lens + ])) + // + .add_contract(Contract::new("UniswapV2Router02").with_networks(networks![ + // + MAINNET => "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", + // + GNOSIS => "0x1C232F01118CB8B424793ae03F870aa7D0ac7f77", + // + ARBITRUM_ONE => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + // + BASE => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + // + SEPOLIA => "0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3", + // + AVALANCHE => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + // + BNB => "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24", + // + OPTIMISM => "0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2", + // + POLYGON => "0xedf6066a2b290C185783862C7F4776A2C8077AD1", + // Not available on Lens + ])) + .add_contract(Contract::new("IUniswapLikeRouter")) + .add_contract(Contract::new("IUniswapLikePair")) + .add_contract(Contract::new("UniswapV3Pool")) + // + .add_contract(Contract::new("UniswapV3QuoterV2").with_networks(networks![ + MAINNET => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + ARBITRUM_ONE => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + BASE => "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a", + AVALANCHE => "0xbe0F5544EC67e9B3b2D979aaA43f18Fd87E6257F", + BNB => "0x78D78E420Da98ad378D7799bE8f4AF69033EB077", + OPTIMISM => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + POLYGON => "0x61fFE014bA17989E743c5F6cB21bF9697530B21e", + LENS => "0x1eEA2B790Dc527c5a4cd3d4f3ae8A2DDB65B2af1", + LINEA => "0x42bE4D6527829FeFA1493e1fb9F3676d2425C3C1", + // Not listed on Gnosis and Sepolia chains + ])) + // + .add_contract( + Contract::new("UniswapV3SwapRouterV2").with_networks(networks![ + ARBITRUM_ONE => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + MAINNET => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + POLYGON => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + OPTIMISM => "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", + BASE => "0x2626664c2603336E57B271c5C0b26F421741e481", + AVALANCHE => "0xbb00FF08d01D300023C629E8fFfFcb65A5a578cE", + BNB => "0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2", + LENS => "0x6ddD32cd941041D8b61df213B9f515A7D288Dc13", + LINEA => "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a", + // Not available on Gnosis Chain + ]), + ) + // + .add_contract(Contract::new("IUniswapV3Factory").with_networks(networks![ + MAINNET => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + SEPOLIA => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + ARBITRUM_ONE => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + BASE => "0x33128a8fC17869897dcE68Ed026d694621f6FDfD", + AVALANCHE => "0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD", + BNB => "0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7", + OPTIMISM => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + POLYGON => "0x1F98431c8aD98523631AE4a59f267346ea31F984", + // not official + LENS => "0xc3A5b857Ba82a2586A45a8B59ECc3AA50Bc3D0e3", + LINEA => "0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9", + // Not available on Gnosis Chain + ])) + // + .add_contract(Contract::new("HooksTrampoline").with_networks(networks![ + MAINNET => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + // Gnosis is using the old instance of the hook trampoline since it's hardcoded in gnosis pay rebalance integration. + GNOSIS => "0x01DcB88678aedD0C4cC9552B20F4718550250574", + SEPOLIA => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + ARBITRUM_ONE => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + BASE => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + AVALANCHE => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + BNB => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + OPTIMISM => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + POLYGON => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + LENS => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + LINEA => "0x60bf78233f48ec42ee3f101b9a05ec7878728006", + PLASMA => "0x60Bf78233f48eC42eE3F101b9a05eC7878728006", + ])) + .add_contract(Contract::new("CoWSwapEthFlow").with_networks(networks![ + // + MAINNET => ("0x40a50cf069e992aa4536211b23f286ef88752187", 16169866), + // + GNOSIS => ("0x40a50cf069e992aa4536211b23f286ef88752187", 25414331), + // + // + SEPOLIA => ("0x0b7795E18767259CC253a2dF471db34c72B49516", 4718739), + // + ARBITRUM_ONE => ("0x6DFE75B5ddce1ADE279D4fa6BD6AeF3cBb6f49dB", 204747458), + // + BASE => ("0x3C3eA1829891BC9bEC3d06A81d5d169e52a415e3", 21490258), + // + AVALANCHE => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 60496408), + // + BNB => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 48411237), + // + OPTIMISM => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 134607215), + // + POLYGON => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 71296258), + // + LENS => ("0xFb337f8a725A142f65fb9ff4902d41cc901de222", 3007173), + // + LINEA => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 24522097), + // + PLASMA => ("0x04501b9b1d52e67f6862d157e00d13419d2d6e95", 3521855), + ])) + .add_contract(Contract::new("CoWSwapOnchainOrders")) + .add_contract(Contract::new("ERC1271SignatureValidator")) + // Used in the gnosis/solvers repo for the balancer solver + .add_contract(Contract::new("BalancerQueries").with_networks(networks![ + // + MAINNET => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 15188261), + // + ARBITRUM_ONE => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 18238624), + // + OPTIMISM => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 15288107), + // + BASE => ("0x300Ab2038EAc391f26D9F895dc61F8F66a548833", 1205869), + // + GNOSIS => ("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e", 24821845), + // + POLYGON => ("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5", 30988035), + // + AVALANCHE => ("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD", 26387068), + // Not available on Lens + ])) + // + .add_contract( + Contract::new("LiquoriceSettlement").with_networks(networks![ + MAINNET => "0x0448633eb8B0A42EfED924C42069E0DcF08fb552", + ARBITRUM_ONE => "0x0448633eb8B0A42EfED924C42069E0DcF08fb552", + ]), + ) + .add_contract(Contract::new("FlashLoanRouter").with_networks(networks![ + MAINNET => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + GNOSIS => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + SEPOLIA => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + ARBITRUM_ONE => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + BASE => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + POLYGON => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + AVALANCHE => "0x9da8b48441583a2b93e2ef8213aad0ec0b392c69", + ])) + .add_contract(Contract::new("ICowWrapper")) + .add_contract(Contract::new("ChainalysisOracle").with_networks(networks![ + MAINNET => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + ARBITRUM_ONE => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + BASE => "0x3A91A31cB3dC49b4db9Ce721F50a9D076c8D739B", + AVALANCHE => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + BNB => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + OPTIMISM => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + POLYGON => "0x40C57923924B5c5c5455c48D93317139ADDaC8fb", + ])) + // Only used in + .add_contract(Contract::new("Permit2").with_networks(networks![ + // + MAINNET => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 15986406), + // + GNOSIS => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 27338672), + // + SEPOLIA => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 2356287), + // + ARBITRUM_ONE => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 38692735), + // + BASE => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 1425180), + // + AVALANCHE => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 28844415), + // + BNB => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 25343783), + // + OPTIMISM => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 38854427), + // + POLYGON => ("0x000000000022D473030F116dDEE9F6B43aC78BA3", 35701901), + ])) + .add_contract( + Contract::new("GPv2AllowListAuthentication").with_networks(networks![ + // + MAINNET => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 12593263), + // + GNOSIS => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 16465099), + // + SEPOLIA => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 4717469), + // + ARBITRUM_ONE => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 204702129), + // + BASE => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 21407137), + // + AVALANCHE => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 59891351), + // + BNB => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 48173639), + // + OPTIMISM => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 134254466), + // + POLYGON => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 45854728), + // + LENS => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 2612937), + // + LINEA => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 24333100), + // + PLASMA => ("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE", 3439709), + ]), + ) + .add_contract(Contract::new("GPv2Settlement").with_networks(networks![ + // + MAINNET => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 12593265), + // + GNOSIS => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 16465100), + // + SEPOLIA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 4717488), + // + ARBITRUM_ONE => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 204704802), + // + BASE => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 21407238), + // + AVALANCHE => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 59891356), + // + BNB => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 48173641), + // + OPTIMISM => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 134254624), + // + POLYGON => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 45859743), + // + LENS => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 2621745), + // + LINEA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 24333100), + // + PLASMA => ("0x9008D19f58AAbD9eD0D60971565AA8510560ab41", 3439711), + ])) + // Note: the WETH address must be consistent with the one used by the ETH-flow + // contract + .add_contract(Contract::new("WETH9").with_networks(networks![ + MAINNET => "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + GNOSIS => "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", + SEPOLIA => "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + ARBITRUM_ONE => "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + BASE => "0x4200000000000000000000000000000000000006", + AVALANCHE => "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", + BNB => "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + OPTIMISM => "0x4200000000000000000000000000000000000006", + POLYGON => "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", + LENS => "0x6bDc36E20D267Ff0dd6097799f82e78907105e2F", + LINEA => "0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f", + PLASMA => "0x6100E367285b01F48D07953803A2d8dCA5D19873", + ])) + .add_submodule( + Submodule::new("cow_amm") + .add_contract(Contract::new("CowAmm")) + .add_contract(Contract::new("CowAmmConstantProductFactory").with_networks( + networks![ + // + MAINNET => ("0x40664207e3375FB4b733d4743CE9b159331fd034", 19861952), + // + GNOSIS => ("0xdb1cba3a87f2db53b6e1e6af48e28ed877592ec0", 33874317), + // + SEPOLIA => ("0xb808e8183e3a72d196457d127c7fd4befa0d7fd3", 5874562), + ], + )) + .add_contract(Contract::new("CowAmmLegacyHelper").with_networks(networks![ + // + MAINNET => ("0x3705ceee5eaa561e3157cf92641ce28c45a3999c", 20332745), + // + GNOSIS => ("0xd9ec06b001957498ab1bc716145515d1d0e30ffb", 35026999), + ])) + .add_contract(Contract::new("CowAmmUniswapV2PriceOracle")) + .add_contract(Contract::new("CowAmmFactoryGetter")), + ) + .add_submodule( + Submodule::new("test") // Test Contract for using up a specified amount of gas. + .add_contract(Contract::new("GasHog")) + // Test Contract for incrementing arbitrary counters. + .add_contract(Contract::new("Counter")) + // Token with support for `permit` (for pre-interaction tests) + .add_contract(Contract::new("CowProtocolToken").with_networks(networks![ + MAINNET => "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB", + GNOSIS => "0x177127622c4A00F3d409B75571e12cB3c8973d3c", + SEPOLIA => "0x0625aFB445C3B6B7B929342a04A22599fd5dBB59", + ARBITRUM_ONE => "0xcb8b5CD20BdCaea9a010aC1F8d835824F5C87A04", + BASE => "0xc694a91e6b071bF030A18BD3053A7fE09B6DaE69", + ])), + ) + .add_submodule( + Submodule::new("support") // support module + // Support contracts used for trade and token simulations. + .add_contract(Contract::new("AnyoneAuthenticator")) + .add_contract(Contract::new("Solver")) + .add_contract(Contract::new("Spardose")) + .add_contract(Contract::new("Trader")) + // Support contract used for solver fee simulations in the gnosis/solvers repo. + .add_contract(Contract::new("Swapper")) + .add_contract(Contract::new("Signatures").with_networks(networks![ + MAINNET => "0x8262d639c38470F38d2eff15926F7071c28057Af", + ARBITRUM_ONE => "0x8262d639c38470F38d2eff15926F7071c28057Af", + BASE => "0x8262d639c38470F38d2eff15926F7071c28057Af", + AVALANCHE => "0x8262d639c38470F38d2eff15926F7071c28057Af", + BNB => "0x8262d639c38470F38d2eff15926F7071c28057Af", + OPTIMISM => "0x8262d639c38470F38d2eff15926F7071c28057Af", + POLYGON => "0x8262d639c38470F38d2eff15926F7071c28057Af", + LENS => "0x8262d639c38470F38d2eff15926F7071c28057Af", + GNOSIS => "0x8262d639c38470F38d2eff15926F7071c28057Af", + SEPOLIA => "0x8262d639c38470F38d2eff15926F7071c28057Af", + // built with evm=London, because deployment reverts on Linea otherwise + LINEA => "0xf6E57e72F7dB3D9A51a8B4c149C00475b94A37e4", + PLASMA => "0x8262d639c38470F38d2eff15926F7071c28057Af", + ])) + // Support contracts used for various order simulations. + .add_contract(Contract::new("Balances").with_networks(networks![ + MAINNET => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + ARBITRUM_ONE => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + BASE => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + AVALANCHE => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + BNB => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + OPTIMISM => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + POLYGON => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + LENS => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + GNOSIS => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + SEPOLIA => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + PLASMA => "0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b", + // built with evm=London, because deployment reverts on Linea otherwise + LINEA => "0x361350f708f7c0c63c8a505226592c3e5d1faa29", + ])), + ) + .write_formatted(Path::new("artifacts"), true, vendored_bindings) + .unwrap(); +} + +// Codegen implementation starts here + +const MOD_HEADER: &str = r#"#![allow(unused_imports, unused_attributes, clippy::all, rustdoc::all, non_snake_case)] + //! This module contains the sol! generated bindings for solidity contracts. + //! This is autogenerated code. + //! Do not manually edit these files. + //! These files may be overwritten by the codegen system at any time. + "#; + +#[derive(Default)] +pub struct Module { + pub contracts: Vec, + submodules: Vec, +} + +impl Module { + pub fn add_contract(mut self, contract: Contract) -> Self { + self.contracts.push(contract); + self + } + + pub fn add_submodule(mut self, module: Submodule) -> Self { + self.submodules.push(module); + self + } + + pub fn write_formatted( + self, + bindings_folder: P1, + all_derives: bool, + output_folder: P2, + ) -> anyhow::Result<()> + where + P1: AsRef, + P2: AsRef, + { + std::fs::create_dir_all(&output_folder)?; + + let mut mod_file = String::from(MOD_HEADER); + for submodule in self.submodules { + write_mod_name(&mut mod_file, &submodule.name)?; + submodule.write_formatted(bindings_folder.as_ref(), all_derives, &output_folder)?; + } + + for contract in self.contracts { + let name = contract.name.clone(); + contract.write_formatted(bindings_folder.as_ref(), all_derives, &output_folder)?; + write_mod_name(&mut mod_file, &name)?; + } + + let file: syn::File = syn::parse_file(&mod_file)?; + let formatted = prettyplease::unparse(&file); + std::fs::write(output_folder.as_ref().join("mod.rs"), formatted)?; + + Ok(()) + } +} + +pub struct Submodule { + pub name: String, + pub contracts: Vec, + submodules: Vec, +} + +impl Submodule { + pub fn new(name: S) -> Self { + Self { + name: name.to_string(), + contracts: vec![], + submodules: vec![], + } + } + + pub fn add_contract(mut self, contract: Contract) -> Self { + self.contracts.push(contract); + self + } + + pub fn add_submodule(mut self, module: Submodule) -> Self { + self.submodules.push(module); + self + } + + pub fn write_formatted( + self, + bindings_folder: P1, + all_derives: bool, + output_folder: P2, + ) -> anyhow::Result<()> + where + P1: AsRef, + P2: AsRef, + { + let output_folder = output_folder.as_ref().join(self.name); + std::fs::create_dir_all(&output_folder)?; + + let mut mod_file = String::from(MOD_HEADER); + for submodule in self.submodules { + write_mod_name(&mut mod_file, &submodule.name)?; + submodule.write_formatted(bindings_folder.as_ref(), all_derives, &output_folder)?; + } + + for contract in self.contracts { + let name = contract.name.clone(); + contract.write_formatted(bindings_folder.as_ref(), all_derives, &output_folder)?; + write_mod_name(&mut mod_file, &name)?; + } + + let file: syn::File = syn::parse_file(&mod_file)?; + let formatted = prettyplease::unparse(&file); + std::fs::write(output_folder.join("mod.rs"), formatted)?; + + Ok(()) + } +} + +pub struct Contract { + pub name: String, + networks: HashMap)>, +} + +impl Contract { + pub fn new>(name: S) -> Self { + Self { + name: name.as_ref().to_string(), + networks: HashMap::new(), + } + } + + pub fn with_networks(mut self, networks: I) -> Self + where + S: AsRef, + I: IntoIterator))>, + { + for (id, (address, block_number)) in networks.into_iter() { + self.networks + .insert(id, (address.as_ref().to_string(), block_number)); + } + self + } + + fn bindings_path(&self, bindings_folder: &Path) -> PathBuf { + bindings_folder.join(&self.name).with_extension("json") + } + + pub fn generate>( + self, + bindings_folder: P, + all_derives: bool, + ) -> anyhow::Result { + let bindings_path = self.bindings_path(bindings_folder.as_ref()); + let mut macrogen = SolMacroGen::new(bindings_path, self.name.clone()); + generate_binding(&mut macrogen, all_derives)?; + let mut expansion = macrogen + .expansion + .expect("if the expansion failed, it should have errored earlier"); + + let module_name_ident = format_ident!("{}", self.name); + let instance_name_ident = format_ident!("{}Instance", self.name); + let instance = quote::quote! { + pub type Instance = #module_name_ident :: #instance_name_ident<::alloy::providers::DynProvider>; + }; + expansion.extend(instance); + + let no_networks = self.networks.is_empty(); + let networks = self.networks.into_iter().map(NetworkArm::from); + let deployment_info = if no_networks { + proc_macro2::TokenStream::new() + } else { + quote::quote! { + use { + std::{ + sync::LazyLock, + collections::HashMap + }, + anyhow::{Result, Context}, + alloy::{ + providers::{Provider, DynProvider}, + primitives::{address, Address}, + }, + }; + + pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { + match chain_id { + #( #networks ,)* + _ => None + } + } + + /// Returns the contract's deployment address (if one exists) for the given chain. + pub const fn deployment_address(chain_id: &u64) -> Option<::alloy::primitives::Address> { + match deployment_info(*chain_id) { + Some((address, _)) => Some(address), + None => None, + } + } + + /// Returns the contract's deployment block (if one exists) for the given chain. + pub const fn deployment_block(chain_id: &u64) -> Option { + match deployment_info(*chain_id) { + Some((_, block)) => block, + None => None, + } + } + + impl Instance { + pub fn deployed(provider: &DynProvider) -> impl Future> + Send { + async move { + let chain_id = provider + .get_chain_id() + .await + .context("could not fetch current chain id")?; + + let (address, _deployed_block) = deployment_info(chain_id) + .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; + + Ok(Instance::new( + address, + provider.clone(), + )) + } + } + } + } + }; + expansion.extend(deployment_info); + + Ok(expansion) + } + + pub fn write_formatted( + self, + bindings_folder: P1, + all_derives: bool, + output_folder: P2, + ) -> anyhow::Result<()> + where + P1: AsRef, + P2: AsRef, + { + let name = self.name.clone(); + let token_stream = self.generate(bindings_folder, all_derives)?; + let mut buffer = String::new(); + write!(buffer, "{}", token_stream)?; + let file: syn::File = syn::parse_file(&buffer)?; + let formatted = prettyplease::unparse(&file); + std::fs::write( + output_folder.as_ref().join(name).with_extension("rs"), + formatted, + )?; + Ok(()) + } +} + +fn generate_binding(instance: &mut SolMacroGen, all_derives: bool) -> anyhow::Result<()> { + let input = instance + .get_sol_input() + .map_err(|err| anyhow::anyhow!("{:?}", err))? + .normalize_json() + .map_err(|err| anyhow::anyhow!("{:?}", err))?; + let SolInput { + attrs: _, + path: _, + kind, + } = input; + + let tokens = match kind { + SolInputKind::Sol(mut file) => { + let sol_attr: syn::Attribute = if all_derives { + syn::parse_quote! { + #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract = + alloy::contract, all_derives = true, extra_derives(serde::Serialize, + serde::Deserialize))] } + } else { + syn::parse_quote! { + #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract = + alloy::contract)] } + }; + file.attrs.push(sol_attr); + expand(file)? + } + _ => unreachable!(), + }; + + instance.expansion = Some(tokens); + Ok(()) +} + +fn write_mod_name(contents: &mut String, name: &str) -> anyhow::Result<()> { + if syn::parse_str::(&format!("pub mod {name};")).is_ok() { + write!(contents, "pub mod {name};")?; + } else { + write!(contents, "pub mod r#{name};")?; + } + Ok(()) +} + +/// Wrapper to avoid destructuring the vector of tuples into three iterators. +/// +/// The following code: +/// ```ignore +/// // We need to "destructure" the iterator into several due to +/// let chain_ids = self.networks.iter().map(|n| n.0); +/// let addresses = self.networks.iter().map(|n| n.1.0.clone()); +/// let blocks = self.networks.iter().map(|n| match n.1.1 { +/// Some(block) => quote::quote! {Some (#block)}, +/// None => quote::quote! {None}, +/// }); +/// // ... +/// quote::quote! { +/// pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { +/// match chain_id { +/// #(#chain_id => Some((::alloy::primitives::address!(#address), #block_number)),)* +/// _ => None +/// } +/// } +/// } +/// ``` +/// +/// Becomes: +/// ```ignore +/// let networks = self.networks.into_iter().map(NetworkArm::from); +/// // ... +/// quote::quote! { +/// pub const fn deployment_info(chain_id: u64) -> Option<(Address, Option)> { +/// match chain_id { +/// #( #networks ,)* +/// _ => None +/// } +/// } +/// } +/// ``` +struct NetworkArm(u64, (String, Option)); + +impl ToTokens for NetworkArm { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let chain_id = self.0; + let address = &self.1.0; + let block_number = match self.1.1 { + Some(block) => quote::quote! {Some (#block)}, + None => quote::quote! {None}, + }; + tokens.extend(quote::quote! { + #chain_id => Some((::alloy::primitives::address!(#address), #block_number)) + }); + } +} + +impl From<(u64, (String, Option))> for NetworkArm { + fn from((chain_id, info): (u64, (String, Option))) -> Self { + Self(chain_id, info) + } +} + +/// SolMacroGen implementation vendored from +/// +/// to avoid depending on forge-sol-macro-gen. +pub struct SolMacroGen { + pub path: PathBuf, + pub name: String, + pub expansion: Option, +} + +impl SolMacroGen { + pub fn new(path: PathBuf, name: String) -> Self { + Self { + path, + name, + expansion: None, + } + } + + pub fn get_sol_input(&self) -> Result { + let path = self.path.to_string_lossy().into_owned(); + let name = proc_macro2::Ident::new(&self.name, Span::call_site()); + let tokens = quote::quote! { + #[sol(ignore_unlinked)] + #name, + #path + }; + + let sol_input: SolInput = syn::parse2(tokens).context("failed to parse input")?; + + Ok(sol_input) + } +} diff --git a/crates/contracts/src/alloy.rs b/crates/contracts/src/alloy.rs deleted file mode 100644 index 2729993c66..0000000000 --- a/crates/contracts/src/alloy.rs +++ /dev/null @@ -1,988 +0,0 @@ -pub mod networks { - pub const MAINNET: u64 = 1; - pub const GNOSIS: u64 = 100; - pub const SEPOLIA: u64 = 11155111; - pub const ARBITRUM_ONE: u64 = 42161; - pub const BASE: u64 = 8453; - pub const POLYGON: u64 = 137; - pub const AVALANCHE: u64 = 43114; - pub const BNB: u64 = 56; - pub const OPTIMISM: u64 = 10; - pub const LENS: u64 = 232; - pub const LINEA: u64 = 59144; - pub const PLASMA: u64 = 9745; -} - -crate::bindings!( - ChainalysisOracle, - crate::deployments! { - MAINNET => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - ARBITRUM_ONE => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - BASE => address!("0x3A91A31cB3dC49b4db9Ce721F50a9D076c8D739B"), - AVALANCHE => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - BNB => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - OPTIMISM => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - POLYGON => address!("0x40C57923924B5c5c5455c48D93317139ADDaC8fb"), - } -); - -crate::bindings!( - IZeroex, - crate::deployments! { - MAINNET => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - SEPOLIA => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - ARBITRUM_ONE => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - BASE => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - AVALANCHE => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - BNB => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - OPTIMISM => address!("0xdef1abe32c034e558cdd535791643c58a13acc10"), - POLYGON => address!("0xdef1c0ded9bec7f1a1670819833240f027b25eff"), - // Not available on Lens - } -); - -crate::bindings!(ERC20Mintable); - -crate::bindings!(GnosisSafe); -crate::bindings!(GnosisSafeCompatibilityFallbackHandler); -crate::bindings!(GnosisSafeProxy); -crate::bindings!(GnosisSafeProxyFactory); - -crate::bindings!(BalancerV2Authorizer); -crate::bindings!(BalancerV2BasePool); -crate::bindings!(BalancerV2BasePoolFactory); -crate::bindings!(BalancerV2WeightedPool); -crate::bindings!(BalancerV2StablePool); -crate::bindings!(BalancerV2ComposableStablePool); -crate::bindings!(BalancerV2LiquidityBootstrappingPool); -crate::bindings!( - BalancerV2WeightedPoolFactory, - // - crate::deployments! { - // - MAINNET => (address!("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9"), 12272147) - // Not available on Sepolia (only version ≥ 4) - // - // Not available on Lens - } -); -crate::bindings!( - BalancerV2WeightedPoolFactoryV3, - // - crate::deployments! { - // - MAINNET => (address!("0x5Dd94Da3644DDD055fcf6B3E1aa310Bb7801EB8b"), 16520627), - // - GNOSIS => (address!("0xC128a9954e6c874eA3d62ce62B468bA073093F25"), 26226256), - // - AVALANCHE => (address!("0x94f68b54191F62f781Fe8298A8A5Fa3ed772d227"), 26389236), - // - OPTIMISM => (address!("0xA0DAbEBAAd1b243BBb243f933013d560819eB66f"), 72832703), - // - POLYGON => (address!("0x82e4cFaef85b1B6299935340c964C942280327f4"), 39036828), - // - BNB => (address!("0x6e4cF292C5349c79cCd66349c3Ed56357dD11B46"), 25474982), - // Not available on Sepolia (only version ≥ 4) - // - // Not available on Lens - } -); -crate::bindings!( - BalancerV2WeightedPoolFactoryV4, - crate::deployments! { - // - MAINNET => (address!("0x897888115Ada5773E02aA29F775430BFB5F34c51"), 16878323), - // - GNOSIS => (address!("0x6CaD2ea22BFA7F4C14Aae92E47F510Cd5C509bc7"), 27055829), - // - // - SEPOLIA => (address!("0x7920BFa1b2041911b354747CA7A6cDD2dfC50Cfd"), 3424893), - // - ARBITRUM_ONE => (address!("0xc7E5ED1054A24Ef31D827E6F86caA58B3Bc168d7"), 72222060), - // - BASE => (address!("0x4C32a8a8fDa4E24139B51b456B42290f51d6A1c4"), 1204869), - // - AVALANCHE => (address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), 27739006), - // - OPTIMISM => (address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), 82737545), - // - POLYGON => (address!("0xFc8a407Bba312ac761D8BFe04CE1201904842B76"), 40611103), - // - BNB => (address!("0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a"), 26665331), - // Not available on Base and Lens - // - } -); -crate::bindings!( - BalancerV2WeightedPool2TokensFactory, - // - crate::deployments! { - // - MAINNET => (address!("0xa5bf2ddf098bb0ef6d120c98217dd6b141c74ee0"), 12349891), - ARBITRUM_ONE => (address!("0xCF0a32Bbef8F064969F21f7e02328FB577382018"), 222864), - // - OPTIMISM => (address!("0xdAE7e32ADc5d490a43cCba1f0c736033F2b4eFca"), 7005512), - // - POLYGON => (address!("0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9"), 15832998), - // Not available on Sepolia, Base, Avalanche, BNB and Lens - // - // - } -); -crate::bindings!( - BalancerV2StablePoolFactoryV2, - // - crate::deployments! { - // - MAINNET => (address!("0x8df6efec5547e31b0eb7d1291b511ff8a2bf987c"), 14934936), - // - GNOSIS => (address!("0xf23b4DB826DbA14c0e857029dfF076b1c0264843"), 25415344), - ARBITRUM_ONE => (address!("0xEF44D6786b2b4d544b7850Fe67CE6381626Bf2D6"), 14244664), - // - OPTIMISM => (address!("0xeb151668006CD04DAdD098AFd0a82e78F77076c3"), 11088891), - // - POLYGON => (address!("0xcA96C4f198d343E251b1a01F3EBA061ef3DA73C1"), 29371951), - // Not available on Sepolia, Base, Avalanche, BNB and Lens - // - // - } -); -crate::bindings!( - BalancerV2LiquidityBootstrappingPoolFactory, - // - crate::deployments! { - // - MAINNET => (address!("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE"), 12871780), - ARBITRUM_ONE => (address!("0x142B9666a0a3A30477b052962ddA81547E7029ab"), 222870), - // - POLYGON => (address!("0x751A0bC0e3f75b38e01Cf25bFCE7fF36DE1C87DE"), 17116402), - // Not available on Sepolia, Base, Avalanche, BNB, Optimism and Lens - // - // - } -); -crate::bindings!( - BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory, - // - crate::deployments! { - // - MAINNET => (address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), 13730248), - // - // - GNOSIS => (address!("0x85a80afee867aDf27B50BdB7b76DA70f1E853062"), 25415236), - // - // - SEPOLIA => (address!("0x45fFd460cC6642B8D8Fb12373DFd77Ceb0f4932B"), 25415236), - ARBITRUM_ONE => (address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), 4859669), - // - BASE => (address!("0x0c6052254551EAe3ECac77B01DFcf1025418828f"), 1206531), - // - AVALANCHE => (address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), 26386552), - // - BNB => (address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), 22691243), - // - OPTIMISM => (address!("0xf302f9F50958c5593770FDf4d4812309fF77414f"), 7005915), - // - POLYGON => (address!("0x41B953164995c11C81DA73D212ED8Af25741b7Ac"), 22067480), - // Not available on Lens - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactory, - crate::deployments! { - // - MAINNET => (address!("0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F"), 15485885), - ARBITRUM_ONE => (address!("0xaEb406b0E430BF5Ea2Dc0B9Fe62E4E53f74B3a33"), 23227044), - // - BNB => (address!("0xf302f9F50958c5593770FDf4d4812309fF77414f"), 22691193), - // - OPTIMISM => (address!("0xf145caFB67081895EE80eB7c04A30Cf87f07b745"), 22182522), - // - POLYGON => (address!("0x136FD06Fa01eCF624C7F2B3CB15742c1339dC2c4"), 32774224), - // Not available on Sepolia, Gnosis Chain, Base, Avalanche and Lens - // - // - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV3, - crate::deployments! { - // - MAINNET => (address!("0xdba127fBc23fb20F5929C546af220A991b5C6e01"), 16580899), - // - GNOSIS => (address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), 26365805), - ARBITRUM_ONE => (address!("0x1c99324EDC771c82A0DCCB780CC7DDA0045E50e7"), 58948370), - // - BNB => (address!("0xacAaC3e6D6Df918Bf3c809DFC7d42de0e4a72d4C"), 25475700), - // - OPTIMISM => (address!("0xe2E901AB09f37884BA31622dF3Ca7FC19AA443Be"), 72832821), - // - POLYGON => (address!("0x7bc6C0E73EDAa66eF3F6E2f27b0EE8661834c6C9"), 39037615), - // Not available on Sepolia (only version ≥ 4) and on Base (only version ≥ 5) - // - // - // Not available on Lens - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV4, - crate::deployments! { - // - MAINNET => (address!("0xfADa0f4547AB2de89D1304A668C39B3E09Aa7c76"), 16878679), - // - GNOSIS => (address!("0xD87F44Df0159DC78029AB9CA7D7e57E7249F5ACD"), 27056416), - // - // - SEPOLIA => (address!("0xA3fd20E29358c056B727657E83DFd139abBC9924"), 3425277), - ARBITRUM_ONE => (address!("0x2498A2B0d6462d2260EAC50aE1C3e03F4829BA95"), 72235860), - // - AVALANCHE => (address!("0x3B1eb8EB7b43882b385aB30533D9A2BeF9052a98"), 29221425), - // - BNB => (address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), 26666380), - // - OPTIMISM => (address!("0x1802953277FD955f9a254B80Aa0582f193cF1d77"), 82748180), - // - POLYGON => (address!("0x6Ab5549bBd766A43aFb687776ad8466F8b42f777"), 40613553), - // Not available on Base and Lens - // - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV5, - crate::deployments! { - // - MAINNET => (address!("0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A"), 17672478), - // - GNOSIS => (address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), 28900564), - // - // - SEPOLIA => (address!("0xa523f47A933D5020b23629dDf689695AA94612Dc"), 3872211), - ARBITRUM_ONE => (address!("0xA8920455934Da4D853faac1f94Fe7bEf72943eF1"), 110212282), - // - BASE => (address!("0x8df317a729fcaA260306d7de28888932cb579b88"), 1204710), - // - AVALANCHE => (address!("0xE42FFA682A26EF8F25891db4882932711D42e467"), 32478827), - // - BNB => (address!("0x4fb47126Fa83A8734991E41B942Ac29A3266C968"), 29877945), - // - OPTIMISM => (address!("0x043A2daD730d585C44FB79D2614F295D2d625412"), 106752707), - // - POLYGON => (address!("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b"), 44961548), - // Not available on Lens - } -); -crate::bindings!( - BalancerV2ComposableStablePoolFactoryV6, - crate::deployments! { - // - MAINNET => (address!("0x5B42eC6D40f7B7965BE5308c70e2603c0281C1E9"), 19314764), - // - GNOSIS => (address!("0x47B489bf5836f83ABD928C316F8e39bC0587B020"), 32650879), - // - SEPOLIA => (address!("0x05503B3aDE04aCA81c8D6F88eCB73Ba156982D2B"), 5369821), - // - ARBITRUM_ONE => (address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), 184805448), - // - BASE => (address!("0x956CCab09898C0AF2aCa5e6C229c3aD4E93d9288"), 11099703), - // - AVALANCHE => (address!("0xb9F8AB3ED3F3aCBa64Bc6cd2DcA74B7F38fD7B88"), 42186350), - // - BNB => (address!("0x6B5dA774890Db7B7b96C6f44e6a4b0F657399E2e"), 36485719), - // - OPTIMISM => (address!("0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7"), 116694338), - // - POLYGON => (address!("0xEAedc32a51c510d35ebC11088fD5fF2b47aACF2E"), 53996258), - // Not available on Lens - } -); -crate::bindings!( - // Balancer addresses can be obtained from: - // - BalancerV2Vault, - crate::deployments! { - // - MAINNET => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 12272146), - // - GNOSIS => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 24821598), - // - SEPOLIA => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 3418831), - // - ARBITRUM_ONE => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 222832), - // - BASE => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 1196036), - // - AVALANCHE => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 26386141), - // - BNB => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 22691002), - // - OPTIMISM => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 7003431), - // - POLYGON => (address!("0xBA12222222228d8Ba445958a75a0704d566BF2C8"), 15832990), - // Not available on Lens - } -); -crate::bindings!( - BalancerV3BatchRouter, - crate::deployments! { - // - MAINNET => (address!("0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1"), 21339510), - // - GNOSIS => (address!("0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b"), 37377506), - // - SEPOLIA => (address!("0xC85b652685567C1B074e8c0D4389f83a2E458b1C"), 7219301), - // - ARBITRUM_ONE => (address!("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E"), 297828544), - // - BASE => (address!("0x85a80afee867aDf27B50BdB7b76DA70f1E853062"), 25347205), - // - AVALANCHE => (address!("0xc9b36096f5201ea332Db35d6D195774ea0D5988f"), 59965747), - // - OPTIMISM => (address!("0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E"), 133969588), - // Not available on Lens, Polygon, BNB - } -); - -// UniV2 -crate::bindings!( - BaoswapRouter, - crate::deployments! { - // https://gnosisscan.io/tx/0xdcbfa037f2c6c7456022df0632ec8d6a75d0f9a195238eec679d5d26895eb7b1 - GNOSIS => (address!("0x6093AeBAC87d62b1A5a4cEec91204e35020E38bE")) - } -); -crate::bindings!( - HoneyswapRouter, - crate::deployments! { - GNOSIS => (address!("0x1C232F01118CB8B424793ae03F870aa7D0ac7f77")) - } -); -crate::bindings!( - PancakeRouter, - crate::deployments! { - // - MAINNET => (address!("0xEfF92A263d31888d860bD50809A8D171709b7b1c")), - // - ARBITRUM_ONE => (address!("0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb")), - // - BASE => (address!("0x8cFe327CEc66d1C090Dd72bd0FF11d690C33a2Eb")), - // - BNB => (address!("0x10ED43C718714eb63d5aA57B78B54704E256024E")) - } -); -crate::bindings!( - SushiSwapRouter, - // - crate::deployments! { - // - MAINNET => (address!("0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f")), - // - GNOSIS => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - ARBITRUM_ONE => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - BASE => (address!("0x6bded42c6da8fbf0d2ba55b2fa120c5e0c8d7891")), - // - AVALANCHE => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - BNB => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // - OPTIMISM => (address!("0x2abf469074dc0b54d793850807e6eb5faf2625b1")), - // - POLYGON => (address!("0x1b02da8cb0d097eb8d57a175b88c7d8b47997506")), - // Not available on Lens - } -); -crate::bindings!( - SwaprRouter, - // - crate::deployments! { - // - MAINNET => address!("0xb9960d9bca016e9748be75dd52f02188b9d0829f"), - // - GNOSIS => address!("0xE43e60736b1cb4a75ad25240E2f9a62Bff65c0C0"), - // - ARBITRUM_ONE => address!("0x530476d5583724A89c8841eB6Da76E7Af4C0F17E"), - // Not available on Base and Lens - } -); -crate::bindings!(ISwaprPair); -crate::bindings!( - TestnetUniswapV2Router02, - crate::deployments! { - // - SEPOLIA => address!("0x86dcd3293C53Cf8EFd7303B57beb2a3F671dDE98"), - } -); -crate::bindings!( - UniswapV2Factory, - // - crate::deployments! { - // - MAINNET => address!("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), - // - GNOSIS => address!("0xA818b4F111Ccac7AA31D0BCc0806d64F2E0737D7"), - // - ARBITRUM_ONE => address!("0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9"), - // - BASE => address!("0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"), - // - SEPOLIA => address!("0xF62c03E08ada871A0bEb309762E260a7a6a880E6"), - // - AVALANCHE => address!("0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C"), - // - BNB => address!("0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"), - // - OPTIMISM => address!("0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf"), - // - POLYGON => address!("0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C"), - // Not available on Lens - } -); -crate::bindings!( - UniswapV2Router02, - // - crate::deployments! { - // - MAINNET => address!("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"), - // - GNOSIS => address!("0x1C232F01118CB8B424793ae03F870aa7D0ac7f77"), - // - ARBITRUM_ONE => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - BASE => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - SEPOLIA => address!("0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3"), - // - AVALANCHE => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - BNB => address!("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24"), - // - OPTIMISM => address!("0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2"), - // - POLYGON => address!("0xedf6066a2b290C185783862C7F4776A2C8077AD1"), - // Not available on Lens - } -); -crate::bindings!(IUniswapLikeRouter); -crate::bindings!(IUniswapLikePair); -crate::bindings!(UniswapV3Pool); -crate::bindings!( - UniswapV3QuoterV2, - crate::deployments! { - // - MAINNET => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - ARBITRUM_ONE => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - BASE => address!("0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a"), - AVALANCHE => address!("0xbe0F5544EC67e9B3b2D979aaA43f18Fd87E6257F"), - BNB => address!("0x78D78E420Da98ad378D7799bE8f4AF69033EB077"), - OPTIMISM => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - POLYGON => address!("0x61fFE014bA17989E743c5F6cB21bF9697530B21e"), - LENS => address!("0x1eEA2B790Dc527c5a4cd3d4f3ae8A2DDB65B2af1"), - LINEA => address!("0x42bE4D6527829FeFA1493e1fb9F3676d2425C3C1"), - // Not listed on Gnosis and Sepolia chains - } -); -crate::bindings!( - UniswapV3SwapRouterV2, - crate::deployments! { - // - ARBITRUM_ONE => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - MAINNET => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - POLYGON => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - OPTIMISM => address!("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"), - BASE => address!("0x2626664c2603336E57B271c5C0b26F421741e481"), - AVALANCHE => address!("0xbb00FF08d01D300023C629E8fFfFcb65A5a578cE"), - BNB => address!("0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2"), - LENS => address!("0x6ddD32cd941041D8b61df213B9f515A7D288Dc13"), - LINEA => address!("0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a"), - // Not available on Gnosis Chain - } -); -crate::bindings!( - IUniswapV3Factory, - crate::deployments! { - // - MAINNET => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - SEPOLIA => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - ARBITRUM_ONE => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - BASE => address!( "0x33128a8fC17869897dcE68Ed026d694621f6FDfD"), - AVALANCHE => address!( "0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD"), - BNB => address!( "0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7"), - OPTIMISM => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - POLYGON => address!( "0x1F98431c8aD98523631AE4a59f267346ea31F984"), - // not official - LENS => address!( "0xc3A5b857Ba82a2586A45a8B59ECc3AA50Bc3D0e3"), - LINEA => address!("0x31FAfd4889FA1269F7a13A66eE0fB458f27D72A9"), - // Not available on Gnosis Chain - } -); - -crate::bindings!( - HooksTrampoline, - // - crate::deployments! { - MAINNET => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - // Gnosis is using the old instance of the hook trampoline since it's hardcoded in gnosis pay rebalance integration. - GNOSIS => address!("0x01DcB88678aedD0C4cC9552B20F4718550250574"), - SEPOLIA => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - ARBITRUM_ONE => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - BASE => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - AVALANCHE => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - BNB => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - OPTIMISM => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - POLYGON => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - LENS => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - LINEA => address!("0x60bf78233f48ec42ee3f101b9a05ec7878728006"), - PLASMA => address!("0x60Bf78233f48eC42eE3F101b9a05eC7878728006"), - } -); - -crate::bindings!( - CoWSwapEthFlow, - crate::deployments! { - // - MAINNET => (address!("0x40a50cf069e992aa4536211b23f286ef88752187"), 16169866), - // - GNOSIS => (address!("0x40a50cf069e992aa4536211b23f286ef88752187"), 25414331), - // - // - SEPOLIA => (address!("0x0b7795E18767259CC253a2dF471db34c72B49516"), 4718739), - // - ARBITRUM_ONE => (address!("0x6DFE75B5ddce1ADE279D4fa6BD6AeF3cBb6f49dB"), 204747458), - // - BASE => (address!("0x3C3eA1829891BC9bEC3d06A81d5d169e52a415e3"), 21490258), - // - AVALANCHE => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 60496408), - // - BNB => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 48411237), - // - OPTIMISM => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 134607215), - // - POLYGON => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 71296258), - // - LENS => (address!("0xFb337f8a725A142f65fb9ff4902d41cc901de222"), 3007173), - // - LINEA => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 24522097), - // - PLASMA => (address!("0x04501b9b1d52e67f6862d157e00d13419d2d6e95"), 3521855), - } -); -crate::bindings!(CoWSwapOnchainOrders); -crate::bindings!(ERC1271SignatureValidator); - -// Used in the gnosis/solvers repo for the balancer solver -crate::bindings!( - BalancerQueries, - crate::deployments! { - // - MAINNET => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 15188261), - // - ARBITRUM_ONE => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 18238624), - // - OPTIMISM => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 15288107), - // - BASE => (address!("0x300Ab2038EAc391f26D9F895dc61F8F66a548833"), 1205869), - // - GNOSIS => (address!("0x0F3e0c4218b7b0108a3643cFe9D3ec0d4F57c54e"), 24821845), - // - POLYGON => (address!("0xE39B5e3B6D74016b2F6A9673D7d7493B6DF549d5"), 30988035), - // - AVALANCHE => (address!("0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD"), 26387068), - // Not available on Lens - } -); - -crate::bindings!( - LiquoriceSettlement, - crate::deployments! { - // - MAINNET => address!("0x0448633eb8B0A42EfED924C42069E0DcF08fb552"), - ARBITRUM_ONE => address!("0x0448633eb8B0A42EfED924C42069E0DcF08fb552"), - } -); - -crate::bindings!( - FlashLoanRouter, - crate::deployments! { - MAINNET => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - GNOSIS => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - SEPOLIA => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - ARBITRUM_ONE => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - BASE => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - POLYGON => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - AVALANCHE => address!("0x9da8b48441583a2b93e2ef8213aad0ec0b392c69"), - } -); - -crate::bindings!(ICowWrapper); - -// Only used in -crate::bindings!( - Permit2, - crate::deployments! { - // - MAINNET => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 15986406), - // - GNOSIS => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 27338672), - // - SEPOLIA => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 2356287), - // - ARBITRUM_ONE => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 38692735), - // - BASE => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 1425180), - // - AVALANCHE => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 28844415), - // - BNB => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 25343783), - // - OPTIMISM => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 38854427), - // - POLYGON => (address!("0x000000000022D473030F116dDEE9F6B43aC78BA3"), 35701901), - } -); - -crate::bindings!( - GPv2AllowListAuthentication, - crate::deployments! { - // - MAINNET => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 12593263), - // - GNOSIS => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 16465099), - // - SEPOLIA => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 4717469), - // - ARBITRUM_ONE => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 204702129), - // - BASE => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 21407137), - // - AVALANCHE => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 59891351), - // - BNB => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 48173639), - // - OPTIMISM => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 134254466), - // - POLYGON => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 45854728), - // - LENS => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 2612937), - // - LINEA => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 24333100), - // - PLASMA => (address!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE"), 3439709), - } -); - -crate::bindings!( - GPv2Settlement, - crate::deployments! { - // - MAINNET => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 12593265), - // - GNOSIS => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 16465100), - // - SEPOLIA => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 4717488), - // - ARBITRUM_ONE => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 204704802), - // - BASE => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 21407238), - // - AVALANCHE => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 59891356), - // - BNB => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 48173641), - // - OPTIMISM => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 134254624), - // - POLYGON => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 45859743), - // - LENS => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 2621745), - // - LINEA => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 24333100), - // - PLASMA => (address!("0x9008D19f58AAbD9eD0D60971565AA8510560ab41"), 3439711), - } -); - -crate::bindings!( - WETH9, - crate::deployments! { - // Note: the WETH address must be consistent with the one used by the ETH-flow - // contract - MAINNET => address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), - GNOSIS => address!("0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"), - SEPOLIA => address!("0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"), - ARBITRUM_ONE => address!("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), - BASE => address!("0x4200000000000000000000000000000000000006"), - AVALANCHE => address!("0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"), - BNB => address!("0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"), - OPTIMISM => address!("0x4200000000000000000000000000000000000006"), - POLYGON => address!("0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"), - LENS => address!("0x6bDc36E20D267Ff0dd6097799f82e78907105e2F"), - LINEA => address!("0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f"), - PLASMA => address!("0x6100E367285b01F48D07953803A2d8dCA5D19873"), - } -); - -crate::bindings!(ERC20); - -pub mod cow_amm { - crate::bindings!(CowAmm); - crate::bindings!( - CowAmmConstantProductFactory, - crate::deployments! { - // - MAINNET => (address!("0x40664207e3375FB4b733d4743CE9b159331fd034"), 19861952), - // - GNOSIS => (address!("0xdb1cba3a87f2db53b6e1e6af48e28ed877592ec0"), 33874317), - // - SEPOLIA => (address!("0xb808e8183e3a72d196457d127c7fd4befa0d7fd3"), 5874562), - } - ); - crate::bindings!( - CowAmmLegacyHelper, - crate::deployments! { - // - MAINNET => (address!("0x3705ceee5eaa561e3157cf92641ce28c45a3999c"), 20332745), - // - GNOSIS => (address!("0xd9ec06b001957498ab1bc716145515d1d0e30ffb"), 35026999), - } - ); - crate::bindings!(CowAmmUniswapV2PriceOracle); - crate::bindings!(CowAmmFactoryGetter); -} - -pub mod support { - // Support contracts used for trade and token simulations. - crate::bindings!(AnyoneAuthenticator); - crate::bindings!(Solver); - crate::bindings!(Spardose); - crate::bindings!(Trader); - // Support contract used for solver fee simulations in the gnosis/solvers repo. - crate::bindings!(Swapper); - crate::bindings!( - Signatures, - crate::deployments! { - MAINNET => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - ARBITRUM_ONE => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - BASE => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - AVALANCHE => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - BNB => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - OPTIMISM => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - POLYGON => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - LENS => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - GNOSIS => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - SEPOLIA => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - // built with evm=London, because deployment reverts on Linea otherwise - LINEA => address!("0xf6E57e72F7dB3D9A51a8B4c149C00475b94A37e4"), - PLASMA => address!("0x8262d639c38470F38d2eff15926F7071c28057Af"), - } - ); - // Support contracts used for various order simulations. - crate::bindings!( - Balances, - crate::deployments! { - MAINNET => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - ARBITRUM_ONE => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - BASE => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - AVALANCHE => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - BNB => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - OPTIMISM => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - POLYGON => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - LENS => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - GNOSIS => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - SEPOLIA => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - PLASMA => address!("0x3e8C6De9510e7ECad902D005DE3Ab52f35cF4f1b"), - // built with evm=London, because deployment reverts on Linea otherwise - LINEA => address!("0x361350f708f7c0c63c8a505226592c3e5d1faa29"), - } - ); -} - -pub mod test { - // Test Contract for using up a specified amount of gas. - crate::bindings!(GasHog); - // Test Contract for incrementing arbitrary counters. - crate::bindings!(Counter); - // Token with support for `permit` (for pre-interaction tests) - crate::bindings!( - CowProtocolToken, - crate::deployments! { - MAINNET => address!("0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB"), - GNOSIS => address!("0x177127622c4A00F3d409B75571e12cB3c8973d3c"), - SEPOLIA => address!("0x0625aFB445C3B6B7B929342a04A22599fd5dBB59"), - ARBITRUM_ONE => address!("0xcb8b5CD20BdCaea9a010aC1F8d835824F5C87A04"), - BASE => address!("0xc694a91e6b071bF030A18BD3053A7fE09B6DaE69"), - } - ); -} - -pub use alloy::providers::DynProvider as Provider; - -/// Extension trait to attach some useful functions to the contract instance. -pub trait InstanceExt: Sized { - /// Crates a contract instance at the expected address for the current - /// network. - fn deployed( - provider: &Provider, - ) -> impl std::future::Future> + Send; -} - -/// Build a `HashMap)>` from entries like: -/// `CHAIN_ID => address!("0x…")` // block = None -/// `CHAIN_ID => (address!("0x…"), 12_345_678)` // block = Some(…) -#[macro_export] -macro_rules! deployments { - (@acc $m:ident; ) => {}; - - // Tuple form with trailing comma: CHAIN => (addr, block), - (@acc $m:ident; $chain:expr => ( $addr:expr, $block:expr ), $($rest:tt)* ) => { - $m.insert($chain, ($addr, Some($block))); - $crate::deployments!(@acc $m; $($rest)*); - }; - - // Address-only form with trailing comma: CHAIN => addr, - (@acc $m:ident; $chain:expr => $addr:expr, $($rest:tt)* ) => { - $m.insert($chain, ($addr, None::)); - $crate::deployments!(@acc $m; $($rest)*); - }; - - // Tuple form without trailing comma (last entry). - (@acc $m:ident; $chain:expr => ( $addr:expr, $block:expr ) ) => { - $m.insert($chain, ($addr, Some($block))); - }; - - // Address-only form without trailing comma (last entry). - (@acc $m:ident; $chain:expr => $addr:expr ) => { - $m.insert($chain, ($addr, None::)); - }; - - ( $($rest:tt)* ) => {{ - let mut m = ::std::collections::HashMap::new(); - $crate::deployments!(@acc m; $($rest)*); - m - }}; -} - -#[macro_export] -macro_rules! bindings { - ($contract:ident $(, $deployment_info:expr)?) => { - paste::paste! { - // Generate the main bindings in a private module. That allows - // us to re-export all items in our own module while also adding - // some items ourselves. - #[expect(non_snake_case)] - mod [<$contract Private>] { - alloy::sol!( - #[allow(missing_docs, clippy::too_many_arguments)] - #[sol(rpc, all_derives)] - $contract, - concat!("./artifacts/", stringify!($contract), ".json"), - ); - } - - #[expect(non_snake_case)] - pub mod $contract { - use alloy::providers::DynProvider; - - pub use super::[<$contract Private>]::*; - pub type Instance = $contract::[<$contract Instance>]; - - $( - use { - std::sync::LazyLock, - anyhow::Result, - std::collections::HashMap, - alloy::{ - providers::Provider, - primitives::{address, Address}, - }, - anyhow::Context, - $crate::alloy::networks::*, - }; - - static DEPLOYMENT_INFO: LazyLock)>> = LazyLock::new(|| { - $deployment_info - }); - - /// Returns the contract's deployment block (if one exists) for the given chain. - pub fn deployment_block(chain_id: &u64) -> Option { - DEPLOYMENT_INFO.get(chain_id).map(|(_, block)| *block).flatten() - } - - /// Returns the contract's deployment address (if one exists) for the given chain. - pub fn deployment_address(chain_id: &u64) -> Option { - DEPLOYMENT_INFO.get(chain_id).map(|(addr, _)| *addr) - } - - impl $crate::alloy::InstanceExt for Instance { - fn deployed(provider: &DynProvider) -> impl Future> + Send { - async move { - let chain_id = provider - .get_chain_id() - .await - .context("could not fetch current chain id")?; - - let (address, _deployed_block) = *DEPLOYMENT_INFO - .get(&chain_id) - .with_context(|| format!("no deployment info for chain {chain_id:?}"))?; - - Ok(Instance::new( - address, - provider.clone(), - )) - } - } - } - )* - } - } - }; -} - -#[cfg(test)] -mod tests { - use super::networks::*; - use super::*; - - #[test] - fn test_has_address() { - assert!(BaoswapRouter::deployment_address(&GNOSIS).is_some()); - assert!(HoneyswapRouter::deployment_address(&GNOSIS).is_some()); - - for chain_id in &[MAINNET, ARBITRUM_ONE, BASE, BNB] { - assert!(PancakeRouter::deployment_address(chain_id).is_some()); - } - - for chain_id in &[ - MAINNET, - GNOSIS, - ARBITRUM_ONE, - BASE, - AVALANCHE, - BNB, - OPTIMISM, - POLYGON, - ] { - assert!(SushiSwapRouter::deployment_address(chain_id).is_some()); - } - - for chain_id in &[MAINNET, GNOSIS, ARBITRUM_ONE] { - assert!(SwaprRouter::deployment_address(chain_id).is_some()); - } - - assert!(TestnetUniswapV2Router02::deployment_address(&SEPOLIA).is_some()); - - for chain_id in &[ - MAINNET, - GNOSIS, - ARBITRUM_ONE, - BASE, - SEPOLIA, - AVALANCHE, - BNB, - OPTIMISM, - POLYGON, - ] { - assert!(UniswapV2Factory::deployment_address(chain_id).is_some()); - assert!(UniswapV2Router02::deployment_address(chain_id).is_some()); - } - } -} diff --git a/crates/contracts/src/lib.rs b/crates/contracts/src/lib.rs index b39baad16f..1384ddc024 100644 --- a/crates/contracts/src/lib.rs +++ b/crates/contracts/src/lib.rs @@ -1,88 +1,11 @@ #![allow(clippy::let_unit_value)] -pub use ethcontract; +// This module get's auto-generated by the contracts build.rs +#[rustfmt::skip] pub mod alloy; -pub mod errors; -use { - anyhow::{Result, anyhow, bail}, - ethcontract::{ - Contract, - common::{DeploymentInformation, contract::Network}, - }, -}; - -pub fn deployment(contract: &Contract, chain_id: u64) -> Result<&Network> { - contract - .networks - .get(&chain_id.to_string()) - // Note that we are conflating network IDs with chain IDs. In general - // they cannot be considered the same, but for the networks that we - // support (xDAI, Görli and Mainnet) they are. - .ok_or_else(|| anyhow!("missing {} deployment for {}", contract.name, chain_id)) -} - -pub fn deployment_block(contract: &Contract, chain_id: u64) -> Result { - let deployment_info = deployment(contract, chain_id)? - .deployment_information - .ok_or_else(|| anyhow!("missing deployment information for {}", contract.name))?; - match deployment_info { - DeploymentInformation::BlockNumber(block) => Ok(block), - DeploymentInformation::TransactionHash(tx) => { - bail!("missing deployment block number for {}", tx) - } - } -} - -#[macro_use] -mod macros; +pub mod errors; #[cfg(feature = "bin")] pub mod paths; pub mod vault; -pub mod web3; - -#[cfg(test)] -mod tests { - use { - super::*, - crate::alloy::networks::{ARBITRUM_ONE, GNOSIS, MAINNET, SEPOLIA}, - }; - - #[test] - fn deployment_addresses() { - for network in &[MAINNET, GNOSIS, SEPOLIA, ARBITRUM_ONE] { - assert!( - alloy::BalancerV2NoProtocolFeeLiquidityBootstrappingPoolFactory::deployment_address(network).is_some() - ) - } - for network in &[MAINNET, ARBITRUM_ONE] { - assert!( - alloy::BalancerV2WeightedPool2TokensFactory::deployment_address(network).is_some() - ); - assert!( - alloy::BalancerV2LiquidityBootstrappingPoolFactory::deployment_address(network) - .is_some() - ); - } - - assert!(alloy::BalancerV2WeightedPoolFactory::deployment_address(&MAINNET).is_some()); - - for network in &[MAINNET, GNOSIS, ARBITRUM_ONE] { - assert!(alloy::BalancerV2StablePoolFactoryV2::deployment_address(network).is_some()); - } - } - - #[test] - fn deployment_information() { - assert!(alloy::BalancerV2WeightedPoolFactory::deployment_address(&MAINNET).is_some()); - for network in &[MAINNET, ARBITRUM_ONE] { - assert!( - alloy::BalancerV2WeightedPool2TokensFactory::deployment_address(network).is_some() - ); - } - for network in &[MAINNET, GNOSIS, ARBITRUM_ONE] { - assert!(alloy::BalancerV2StablePoolFactoryV2::deployment_address(network).is_some()); - } - } -} diff --git a/crates/contracts/src/macros.rs b/crates/contracts/src/macros.rs deleted file mode 100644 index 1fcf2ec4cf..0000000000 --- a/crates/contracts/src/macros.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[macro_export] -macro_rules! dummy_contract { - ($contract:ty, $addr:expr_2021) => { - <$contract>::at(&$crate::web3::dummy(), $addr.into()) - }; -} diff --git a/crates/contracts/src/web3.rs b/crates/contracts/src/web3.rs deleted file mode 100644 index e73ab5ed69..0000000000 --- a/crates/contracts/src/web3.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! This module provides a "dummy" implementation of a [`web3::Transport`]. The -//! reason is that [`ethcontract`] generated bindings require a `web3` instance -//! in order to construct contract instances. This is annoying when trying to -//! use the generated bindings for just encoding contract function calls, where -//! connection to a node is not needed at all. - -use ethcontract::{ - futures, - json::Value, - jsonrpc::Call as RpcCall, - web3::{self, BatchTransport, RequestId, Transport, Web3}, -}; - -/// A dummy [`web3::Transport`] implementation that always panics. -#[derive(Clone, Debug)] -pub struct DummyTransport; - -impl Transport for DummyTransport { - type Out = futures::future::Pending>; - - fn prepare(&self, _method: &str, _params: Vec) -> (web3::RequestId, RpcCall) { - unimplemented!() - } - - fn send(&self, _id: web3::RequestId, _request: RpcCall) -> Self::Out { - unimplemented!() - } -} - -impl BatchTransport for DummyTransport { - type Batch = futures::future::Pending>>>; - - fn send_batch(&self, _requests: T) -> Self::Batch - where - T: IntoIterator, - { - unimplemented!() - } -} - -/// Creates a [`web3::Web3`] instance with a [`DummyTransport`]. -pub fn dummy() -> Web3 { - Web3::new(DummyTransport) -} diff --git a/crates/driver/src/boundary/liquidity/zeroex.rs b/crates/driver/src/boundary/liquidity/zeroex.rs index fdd128885d..0376d4a60f 100644 --- a/crates/driver/src/boundary/liquidity/zeroex.rs +++ b/crates/driver/src/boundary/liquidity/zeroex.rs @@ -7,7 +7,6 @@ use { infra::{self, Ethereum}, }, anyhow::anyhow, - contracts::alloy::InstanceExt, ethrpc::block_stream::CurrentBlockWatcher, shared::{ http_client::HttpClientFactory, diff --git a/crates/e2e/src/setup/deploy.rs b/crates/e2e/src/setup/deploy.rs index c5765e2e7c..85cb82dfb7 100644 --- a/crates/e2e/src/setup/deploy.rs +++ b/crates/e2e/src/setup/deploy.rs @@ -7,7 +7,6 @@ use { GPv2AllowListAuthentication, GPv2Settlement, HooksTrampoline, - InstanceExt, UniswapV2Factory, UniswapV2Router02, WETH9, diff --git a/crates/e2e/src/setup/onchain_components/safe.rs b/crates/e2e/src/setup/onchain_components/safe.rs index fd92cc71a9..5ac9f76343 100644 --- a/crates/e2e/src/setup/onchain_components/safe.rs +++ b/crates/e2e/src/setup/onchain_components/safe.rs @@ -182,8 +182,10 @@ impl Safe { to: alloy::primitives::Address, data: Vec, nonce: alloy::primitives::U256, - ) -> alloy::contract::CallBuilder<&contracts::alloy::Provider, PhantomData> - { + ) -> alloy::contract::CallBuilder< + &alloy::providers::DynProvider, + PhantomData, + > { let signature = self.sign({ // `SafeTx` struct hash computation ported from the Safe Solidity code: // diff --git a/crates/e2e/tests/e2e/liquidity.rs b/crates/e2e/tests/e2e/liquidity.rs index 1598e095f4..31942b586d 100644 --- a/crates/e2e/tests/e2e/liquidity.rs +++ b/crates/e2e/tests/e2e/liquidity.rs @@ -4,7 +4,7 @@ use { providers::ext::{AnvilApi, ImpersonateConfig}, }, chrono::{NaiveDateTime, Utc}, - contracts::alloy::{ERC20, IZeroex, InstanceExt}, + contracts::alloy::{ERC20, IZeroex}, driver::domain::eth::H160, e2e::{ api::zeroex::{Eip712TypedZeroExOrder, ZeroExApi}, diff --git a/crates/e2e/tests/e2e/liquidity_source_notification.rs b/crates/e2e/tests/e2e/liquidity_source_notification.rs index 500210efa9..5575a180b4 100644 --- a/crates/e2e/tests/e2e/liquidity_source_notification.rs +++ b/crates/e2e/tests/e2e/liquidity_source_notification.rs @@ -5,7 +5,7 @@ use { signers::{SignerSync, local::PrivateKeySigner}, }, chrono::Utc, - contracts::alloy::{ERC20, InstanceExt, LiquoriceSettlement}, + contracts::alloy::{ERC20, LiquoriceSettlement}, driver::infra, e2e::{ api, diff --git a/crates/orderbook/src/run.rs b/crates/orderbook/src/run.rs index 43bea7eec5..272a24c12d 100644 --- a/crates/orderbook/src/run.rs +++ b/crates/orderbook/src/run.rs @@ -19,7 +19,6 @@ use { GPv2Settlement, HooksTrampoline, IUniswapV3Factory, - InstanceExt, WETH9, support::Balances, }, diff --git a/crates/shared/src/bad_token/trace_call.rs b/crates/shared/src/bad_token/trace_call.rs index ae8ad73018..7d92ec9df5 100644 --- a/crates/shared/src/bad_token/trace_call.rs +++ b/crates/shared/src/bad_token/trace_call.rs @@ -399,7 +399,7 @@ mod tests { }, alloy::primitives::address, chain::Chain, - contracts::alloy::{BalancerV2Vault, GPv2Settlement, IUniswapV3Factory, InstanceExt}, + contracts::alloy::{BalancerV2Vault, GPv2Settlement, IUniswapV3Factory}, ethrpc::{Web3, alloy::conversions::IntoLegacy}, std::{env, time::Duration}, web3::types::{ diff --git a/crates/shared/src/event_handling.rs b/crates/shared/src/event_handling.rs index 90b36fd622..63e3280215 100644 --- a/crates/shared/src/event_handling.rs +++ b/crates/shared/src/event_handling.rs @@ -773,7 +773,7 @@ mod tests { use { super::*, alloy::eips::BlockNumberOrTag, - contracts::alloy::{GPv2Settlement, InstanceExt}, + contracts::alloy::GPv2Settlement, ethcontract::{BlockNumber, H256}, ethrpc::{Web3, block_stream::block_number_to_block_number_hash}, std::str::FromStr, @@ -786,7 +786,7 @@ mod tests { Filter::new().address(*self.address()) } - fn provider(&self) -> &contracts::alloy::Provider { + fn provider(&self) -> &alloy::providers::DynProvider { self.provider() } } diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs b/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs index f245fa28c4..dc743db799 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs +++ b/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs @@ -47,7 +47,6 @@ use { BalancerV2WeightedPoolFactory, BalancerV2WeightedPoolFactoryV3, BalancerV2WeightedPoolFactoryV4, - InstanceExt, }, ethcontract::{BlockId, H160, H256}, ethrpc::block_stream::{BlockRetrieving, CurrentBlockWatcher}, diff --git a/crates/solvers/src/boundary/liquidity/concentrated.rs b/crates/solvers/src/boundary/liquidity/concentrated.rs index 51227e3148..b00fef96cc 100644 --- a/crates/solvers/src/boundary/liquidity/concentrated.rs +++ b/crates/solvers/src/boundary/liquidity/concentrated.rs @@ -1,12 +1,10 @@ use { alloy::primitives::aliases::U24, - contracts::{ - alloy::UniswapV3QuoterV2::IQuoterV2::{ - QuoteExactInputSingleParams, - QuoteExactOutputSingleParams, - }, - ethcontract::{H160, U256}, + contracts::alloy::UniswapV3QuoterV2::IQuoterV2::{ + QuoteExactInputSingleParams, + QuoteExactOutputSingleParams, }, + ethcontract::{H160, U256}, ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, model::TokenPair, shared::baseline_solver::BaselineSolvable, diff --git a/crates/solvers/src/boundary/liquidity/limit_order.rs b/crates/solvers/src/boundary/liquidity/limit_order.rs index 892729859f..8e5858c1d5 100644 --- a/crates/solvers/src/boundary/liquidity/limit_order.rs +++ b/crates/solvers/src/boundary/liquidity/limit_order.rs @@ -1,6 +1,6 @@ use { crate::domain::liquidity::limit_order::LimitOrder, - contracts::ethcontract::{H160, U256}, + ethcontract::{H160, U256}, shared::{baseline_solver::BaselineSolvable, price_estimation::gas::GAS_PER_ZEROEX_ORDER}, }; @@ -50,7 +50,7 @@ mod tests { use { super::*, crate::domain::{eth, liquidity::limit_order::TakerAmount}, - contracts::ethcontract::U256, + ethcontract::U256, shared::addr, }; diff --git a/crates/solvers/src/domain/solver.rs b/crates/solvers/src/domain/solver.rs index 1c612b3cec..1946b9c6e4 100644 --- a/crates/solvers/src/domain/solver.rs +++ b/crates/solvers/src/domain/solver.rs @@ -18,7 +18,6 @@ use { }, infra::metrics, }, - contracts::alloy::InstanceExt, ethereum_types::U256, reqwest::Url, std::{cmp, collections::HashSet, sync::Arc}, From 914055c325baf4272248f53533931bf24346554b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Thu, 27 Nov 2025 12:34:15 +0000 Subject: [PATCH 017/470] [TRIVIAL] Migrate order, quote, and validation modules to alloy (#3926) Large but overall trivial # Description This PR continues the migration from the deprecated `ethcontract` library to the modern `alloy` library by converting order, quote, and validation-related modules to use alloy primitive types (`Address`, `U256`). This is part of a broader effort to modernize the codebase and adopt alloy as the standard Ethereum library, replacing ethcontract's `H160` and `U256` types with their alloy equivalents. # Changes - **Model layer** - [x] Migrate `QuoteAmounts` struct to use `alloy::primitives::U256` in `crates/model/src/order.rs` - [x] Simplify `within_market` method by removing manual byte conversions - [x] Migrate `OrderQuoteRequest`, `OrderQuote`, `OrderQuoteResponse` to use `alloy::primitives::Address` in `crates/model/src/quote.rs` - [x] Update solver competition models to use alloy types - **Shared layer** - [x] Migrate `QuoteParameters`, `Quote`, and `QuoteData` structs to alloy types in `crates/shared/src/order_quoting.rs` - [x] Update quote scaling logic to use `widening_mul` instead of `full_mul` - [x] Migrate `Amounts` struct and validation logic in `crates/shared/src/order_validation.rs` - [x] Update `is_order_outside_market_price` to use typed `widening_mul` calls - [x] Migrate fee calculations, event storage, and price estimation modules - **Orderbook layer** - [x] Update database operations to handle alloy types with proper conversions - [x] Migrate DTOs (auction, order) to use alloy primitives - [x] Update quote API endpoints and quoter logic - [x] Migrate solver competition storage - **Autopilot** - [x] Update onchain order event handling - [x] Migrate quote domain logic - [x] Update run loop to work with alloy types - **E2E tests** - [x] Update all test files to use alloy `Address` creation methods (`with_last_byte` instead of `from_low_u64_be`) - [x] Update test setup infrastructure and onchain components - **Math utilities** - [x] Remove deprecated math functions from solvers util module - [x] Update driver math utilities ## How to test Existing tests --------- Co-authored-by: Claude --- .../src/database/onchain_order_events/mod.rs | 6 +- crates/autopilot/src/run_loop.rs | 4 +- crates/driver/src/util/math.rs | 4 +- crates/e2e/src/api/zeroex.rs | 55 +++-- .../e2e/src/setup/onchain_components/mod.rs | 129 +++++------ .../e2e/src/setup/onchain_components/safe.rs | 11 +- crates/e2e/tests/e2e/app_data.rs | 16 +- crates/e2e/tests/e2e/app_data_signer.rs | 20 +- crates/e2e/tests/e2e/autopilot_leader.rs | 18 +- crates/e2e/tests/e2e/banned_users.rs | 3 +- crates/e2e/tests/e2e/buffers.rs | 30 +-- crates/e2e/tests/e2e/cow_amm.rs | 103 ++++----- crates/e2e/tests/e2e/eth_integration.rs | 30 ++- crates/e2e/tests/e2e/eth_safe.rs | 10 +- crates/e2e/tests/e2e/ethflow.rs | 64 +++--- crates/e2e/tests/e2e/hooks.rs | 122 ++++------ crates/e2e/tests/e2e/jit_orders.rs | 40 +--- crates/e2e/tests/e2e/limit_orders.rs | 212 +++++++----------- crates/e2e/tests/e2e/liquidity.rs | 76 +++---- .../e2e/liquidity_source_notification.rs | 22 +- crates/e2e/tests/e2e/order_cancellation.rs | 25 ++- crates/e2e/tests/e2e/partial_fill.rs | 28 +-- .../tests/e2e/partially_fillable_balance.rs | 40 ++-- .../e2e/tests/e2e/partially_fillable_pool.rs | 40 ++-- .../e2e/tests/e2e/place_order_with_quote.rs | 18 +- crates/e2e/tests/e2e/protocol_fee.rs | 142 +++++++----- crates/e2e/tests/e2e/quote_verification.rs | 91 +++----- crates/e2e/tests/e2e/quoting.rs | 44 ++-- crates/e2e/tests/e2e/refunder.rs | 10 +- crates/e2e/tests/e2e/replace_order.rs | 106 ++++----- crates/e2e/tests/e2e/smart_contract_orders.rs | 12 +- crates/e2e/tests/e2e/solver_competition.rs | 66 +++--- .../tests/e2e/solver_participation_guard.rs | 46 ++-- crates/e2e/tests/e2e/submission.rs | 14 +- .../tests/e2e/tracking_insufficient_funds.rs | 20 +- crates/e2e/tests/e2e/uncovered_order.rs | 16 +- crates/e2e/tests/e2e/univ2.rs | 30 +-- crates/e2e/tests/e2e/vault_balances.rs | 18 +- crates/e2e/tests/e2e/wrapper.rs | 41 +--- crates/model/src/order.rs | 23 +- crates/model/src/quote.rs | 11 +- crates/model/src/solver_competition.rs | 23 +- crates/model/src/solver_competition_v2.rs | 17 +- crates/orderbook/src/api/post_quote.rs | 3 +- .../src/database/solver_competition_v2.rs | 2 +- crates/orderbook/src/quoter.rs | 16 +- crates/solvers/src/util/math.rs | 20 -- crates/solvers/src/util/mod.rs | 1 - 48 files changed, 806 insertions(+), 1092 deletions(-) delete mode 100644 crates/solvers/src/util/math.rs diff --git a/crates/autopilot/src/database/onchain_order_events/mod.rs b/crates/autopilot/src/database/onchain_order_events/mod.rs index b460768d80..6d7a3b7208 100644 --- a/crates/autopilot/src/database/onchain_order_events/mod.rs +++ b/crates/autopilot/src/database/onchain_order_events/mod.rs @@ -600,9 +600,9 @@ fn convert_onchain_order_placement( // executed fast (we don't want to reserve the user's ETH for too long) if quote.as_ref().is_ok_and(|quote| { !order_data.within_market(QuoteAmounts { - sell: quote.sell_amount.into_legacy(), - buy: quote.buy_amount.into_legacy(), - fee: quote.fee_amount.into_legacy(), + sell: quote.sell_amount, + buy: quote.buy_amount, + fee: quote.fee_amount, }) }) { tracing::debug!(%order_uid, ?owner, "order is outside market price"); diff --git a/crates/autopilot/src/run_loop.rs b/crates/autopilot/src/run_loop.rs index 5cfaa28a0b..9a71cb53d1 100644 --- a/crates/autopilot/src/run_loop.rs +++ b/crates/autopilot/src/run_loop.rs @@ -472,7 +472,9 @@ impl RunLoop { .map(|(index, participant)| SolverSettlement { solver: participant.driver().name.clone(), solver_address: participant.solution().solver().0.into_alloy(), - score: Some(Score::Solver(participant.solution().score().get().0)), + score: Some(Score::Solver( + participant.solution().score().get().0.into_alloy(), + )), ranking: index + 1, orders: participant .solution() diff --git a/crates/driver/src/util/math.rs b/crates/driver/src/util/math.rs index 582926d875..bb0210e605 100644 --- a/crates/driver/src/util/math.rs +++ b/crates/driver/src/util/math.rs @@ -28,14 +28,14 @@ pub fn mul_ratio_ceil(x: U256, q: U256, d: U256) -> Option { // fast path when math in U256 doesn't overflow if let Some(p) = x.checked_mul(q) { - let (div, rem) = (p / d, p % d); + let (div, rem) = p.div_rem(d); return div.checked_add(U256::from(!rem.is_zero())); } let p = x.widening_mul(q); let d = U512::from(d); // SAFETY: at this point !d.is_zero() upholds - let (div, rem) = (p / d, p % d); + let (div, rem) = p.div_rem(d); let result = U256::uint_try_from(div).ok()?; result.checked_add(U256::from(!rem.is_zero())) diff --git a/crates/e2e/src/api/zeroex.rs b/crates/e2e/src/api/zeroex.rs index 21fbf61376..bb176ba7a8 100644 --- a/crates/e2e/src/api/zeroex.rs +++ b/crates/e2e/src/api/zeroex.rs @@ -1,15 +1,12 @@ use { crate::setup::TestAccount, - autopilot::domain::eth::U256, + alloy::primitives::{Address, B256, U256}, chrono::{DateTime, NaiveDateTime, Utc}, - driver::domain::eth::H256, ethcontract::common::abi::{Token, encode}, + ethrpc::alloy::conversions::IntoLegacy, hex_literal::hex, model::DomainSeparator, - shared::{ - zeroex_api, - zeroex_api::{Order, OrderMetadata, OrderRecord, ZeroExSignature}, - }, + shared::zeroex_api::{self, Order, OrderMetadata, OrderRecord, ZeroExSignature}, std::{net::SocketAddr, sync::LazyLock}, warp::{Filter, Reply}, web3::{signing, types::H160}, @@ -55,17 +52,17 @@ impl ZeroExApi { } pub struct Eip712TypedZeroExOrder { - pub maker_token: H160, - pub taker_token: H160, + pub maker_token: Address, + pub taker_token: Address, pub maker_amount: u128, pub taker_amount: u128, pub remaining_fillable_taker_amount: u128, pub taker_token_fee_amount: u128, - pub maker: H160, - pub taker: H160, - pub sender: H160, - pub fee_recipient: H160, - pub pool: H256, + pub maker: Address, + pub taker: Address, + pub sender: Address, + pub fee_recipient: Address, + pub pool: B256, pub expiry: u64, pub salt: U256, } @@ -85,15 +82,15 @@ impl Eip712TypedZeroExOrder { Order { chain_id, expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - fee_recipient: self.fee_recipient, - maker: self.maker, - maker_token: self.maker_token, + fee_recipient: self.fee_recipient.into_legacy(), + maker: self.maker.into_legacy(), + maker_token: self.maker_token.into_legacy(), maker_amount: self.maker_amount, - pool: self.pool, - salt: self.salt, - sender: self.sender, - taker: self.taker, - taker_token: self.taker_token, + pool: self.pool.into_legacy(), + salt: self.salt.into_legacy(), + sender: self.sender.into_legacy(), + taker: self.taker.into_legacy(), + taker_token: self.taker_token.into_legacy(), taker_amount: self.taker_amount, taker_token_fee_amount: self.taker_token_fee_amount, verifying_contract, @@ -131,18 +128,18 @@ impl Eip712TypedZeroExOrder { fn hash_struct(&self) -> [u8; 32] { let mut hash_data = [0u8; 416]; hash_data[0..32].copy_from_slice(&Self::ZEROEX_LIMIT_ORDER_TYPEHASH); - hash_data[44..64].copy_from_slice(self.maker_token.as_fixed_bytes()); - hash_data[76..96].copy_from_slice(self.taker_token.as_fixed_bytes()); + hash_data[44..64].copy_from_slice(self.maker_token.as_slice()); + hash_data[76..96].copy_from_slice(self.taker_token.as_slice()); hash_data[112..128].copy_from_slice(&self.maker_amount.to_be_bytes()); hash_data[144..160].copy_from_slice(&self.taker_amount.to_be_bytes()); hash_data[176..192].copy_from_slice(&self.taker_token_fee_amount.to_be_bytes()); - hash_data[204..224].copy_from_slice(self.maker.as_fixed_bytes()); - hash_data[236..256].copy_from_slice(self.taker.as_fixed_bytes()); - hash_data[268..288].copy_from_slice(self.sender.as_fixed_bytes()); - hash_data[300..320].copy_from_slice(self.fee_recipient.as_fixed_bytes()); - hash_data[320..352].copy_from_slice(self.pool.as_fixed_bytes()); + hash_data[204..224].copy_from_slice(self.maker.as_slice()); + hash_data[236..256].copy_from_slice(self.taker.as_slice()); + hash_data[268..288].copy_from_slice(self.sender.as_slice()); + hash_data[300..320].copy_from_slice(self.fee_recipient.as_slice()); + hash_data[320..352].copy_from_slice(self.pool.as_slice()); hash_data[376..384].copy_from_slice(&self.expiry.to_be_bytes()); - self.salt.to_big_endian(&mut hash_data[384..416]); + hash_data[384..416].copy_from_slice(&self.salt.to_be_bytes::<32>()); signing::keccak256(&hash_data) } } diff --git a/crates/e2e/src/setup/onchain_components/mod.rs b/crates/e2e/src/setup/onchain_components/mod.rs index 9eac7591fa..ed6fb4936f 100644 --- a/crates/e2e/src/setup/onchain_components/mod.rs +++ b/crates/e2e/src/setup/onchain_components/mod.rs @@ -4,7 +4,10 @@ use { setup::{DeployedContracts, deploy::Contracts}, }, ::alloy::{ - network::{Ethereum, NetworkWallet}, + network::{Ethereum, NetworkWallet, TransactionBuilder}, + primitives::Address, + providers::Provider, + rpc::types::TransactionRequest, signers::local::PrivateKeySigner, }, app_data::Hook, @@ -13,14 +16,7 @@ use { GPv2AllowListAuthentication::GPv2AllowListAuthentication, test::CowProtocolToken, }, - core::panic, - ethcontract::{ - Account, - H160, - PrivateKey, - U256, - transaction::{TransactionBuilder, TransactionResult}, - }, + ethcontract::{Account, H160, PrivateKey, U256}, ethrpc::alloy::{ CallBuilderExt, ProviderSignerExt, @@ -93,23 +89,6 @@ pub fn eth(amount: u32) -> ::alloy::primitives::U256 { ::alloy::primitives::U256::from(amount) * ::alloy::primitives::utils::Unit::ETHER.wei() } -pub async fn hook_for_transaction(tx: TransactionBuilder) -> Hook -where - T: web3::Transport, -{ - let gas_limit = tx - .clone() - .estimate_gas() - .await - .expect("transaction reverted when estimating gas") - .as_u64(); - Hook { - target: tx.to.map(IntoAlloy::into_alloy).unwrap(), - call_data: tx.data.unwrap().0, - gas_limit, - } -} - #[derive(Clone, Debug)] pub struct TestAccount { account: Account, @@ -121,8 +100,8 @@ impl TestAccount { &self.account } - pub fn address(&self) -> H160 { - self.account.address() + pub fn address(&self) -> Address { + self.account.address().into_alloy() } pub fn private_key(&self) -> &[u8; 32] { @@ -142,9 +121,9 @@ impl TestAccount { ) } - pub async fn nonce(&self, web3: &Web3) -> U256 { - web3.eth() - .transaction_count(self.address(), None) + pub async fn nonce(&self, web3: &Web3) -> u64 { + web3.alloy + .get_transaction_count(self.address()) .await .unwrap() } @@ -192,9 +171,9 @@ pub struct MintableToken { } impl MintableToken { - pub async fn mint(&self, to: H160, amount: U256) { + pub async fn mint(&self, to: Address, amount: ::alloy::primitives::U256) { self.contract - .mint(to.into_alloy(), amount.into_alloy()) + .mint(to, amount) .from(self.minter.address().into_alloy()) .send_and_watch() .await @@ -217,9 +196,9 @@ pub struct CowToken { } impl CowToken { - pub async fn fund(&self, to: H160, amount: U256) { + pub async fn fund(&self, to: Address, amount: ::alloy::primitives::U256) { self.contract - .transfer(to.into_alloy(), amount.into_alloy()) + .transfer(to, amount) .from(self.holder.address().into_alloy()) .send_and_watch() .await @@ -230,7 +209,7 @@ impl CowToken { let domain = self.contract.DOMAIN_SEPARATOR().call().await.unwrap(); let nonce = self .contract - .nonces(owner.address().into_alloy()) + .nonces(owner.address()) .call() .await .unwrap() @@ -242,7 +221,7 @@ impl CowToken { buffer[0..32].copy_from_slice(&hex!( "6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9" )); - buffer[44..64].copy_from_slice(owner.address().as_bytes()); + buffer[44..64].copy_from_slice(owner.address().as_slice()); buffer[76..96].copy_from_slice(spender.as_bytes()); value.to_big_endian(&mut buffer[96..128]); nonce.to_big_endian(&mut buffer[128..160]); @@ -254,7 +233,7 @@ impl CowToken { let signature = owner.sign_typed_data(&DomainSeparator(domain.0), &struct_hash); let permit = self.contract.permit( - owner.address().into_alloy(), + owner.address(), spender.into_alloy(), value.into_alloy(), deadline.into_alloy(), @@ -320,7 +299,10 @@ impl OnchainComponents { } /// Generate next `N` accounts with the given initial balance. - pub async fn make_accounts(&mut self, with_wei: U256) -> [TestAccount; N] { + pub async fn make_accounts( + &mut self, + with_wei: ::alloy::primitives::U256, + ) -> [TestAccount; N] { let res = self.accounts.borrow_mut().take(N).collect::>(); assert_eq!(res.len(), N); @@ -336,7 +318,10 @@ impl OnchainComponents { /// Generate next `N` accounts with the given initial balance and /// authenticate them as solvers. - pub async fn make_solvers(&mut self, with_wei: U256) -> [TestAccount; N] { + pub async fn make_solvers( + &mut self, + with_wei: ::alloy::primitives::U256, + ) -> [TestAccount; N] { let solvers = self.make_accounts::(with_wei).await; for solver in &solvers { @@ -346,7 +331,7 @@ impl OnchainComponents { self.contracts .gp_authenticator - .addSolver(solver.address().into_alloy()) + .addSolver(solver.address()) .send_and_watch() .await .expect("failed to add solver"); @@ -355,18 +340,18 @@ impl OnchainComponents { solvers } - pub async fn set_solver_allowed(&self, solver: H160, allowed: bool) { + pub async fn set_solver_allowed(&self, solver: Address, allowed: bool) { if allowed { self.contracts .gp_authenticator - .addSolver(solver.into_alloy()) + .addSolver(solver) .send_and_watch() .await .expect("failed to add solver"); } else { self.contracts .gp_authenticator - .removeSolver(solver.into_alloy()) + .removeSolver(solver) .send_and_watch() .await .expect("failed to remove solver"); @@ -377,7 +362,7 @@ impl OnchainComponents { /// authenticate them as solvers on a forked network. pub async fn make_solvers_forked( &mut self, - with_wei: U256, + with_wei: ::alloy::primitives::U256, ) -> [TestAccount; N] { let authenticator = &self.contracts.gp_authenticator; @@ -408,7 +393,7 @@ impl OnchainComponents { for solver in &solvers { impersonated_authenticator - .addSolver(solver.address().into_alloy()) + .addSolver(solver.address()) .from(auth_manager.into_alloy()) .send_and_watch() .await @@ -542,12 +527,12 @@ impl OnchainComponents { pub async fn seed_uni_v2_pool( &self, - asset_a: (&MintableToken, U256), - asset_b: (&MintableToken, U256), + asset_a: (&MintableToken, ::alloy::primitives::U256), + asset_b: (&MintableToken, ::alloy::primitives::U256), ) { let lp = &asset_a.0.minter; - asset_a.0.mint(lp.address(), asset_a.1).await; - asset_b.0.mint(lp.address(), asset_b.1).await; + asset_a.0.mint(lp.address().into_alloy(), asset_a.1).await; + asset_b.0.mint(lp.address().into_alloy(), asset_b.1).await; self.contracts .uniswap_v2_factory @@ -559,10 +544,7 @@ impl OnchainComponents { asset_a .0 - .approve( - *self.contracts.uniswap_v2_router.address(), - asset_a.1.into_alloy(), - ) + .approve(*self.contracts.uniswap_v2_router.address(), asset_a.1) .from(lp.address().into_alloy()) .send_and_watch() .await @@ -570,10 +552,7 @@ impl OnchainComponents { asset_b .0 - .approve( - *self.contracts.uniswap_v2_router.address(), - asset_b.1.into_alloy(), - ) + .approve(*self.contracts.uniswap_v2_router.address(), asset_b.1) .from(lp.address().into_alloy()) .send_and_watch() .await @@ -583,8 +562,8 @@ impl OnchainComponents { .addLiquidity( *asset_a.0.address(), *asset_b.0.address(), - asset_a.1.into_alloy(), - asset_b.1.into_alloy(), + asset_a.1, + asset_b.1, ::alloy::primitives::U256::ZERO, ::alloy::primitives::U256::ZERO, lp.address().into_alloy(), @@ -599,7 +578,11 @@ impl OnchainComponents { /// Mints `amount` tokens to its `token`-WETH Uniswap V2 pool. /// /// This can be used to modify the pool reserves during a test. - pub async fn mint_token_to_weth_uni_v2_pool(&self, token: &MintableToken, amount: U256) { + pub async fn mint_token_to_weth_uni_v2_pool( + &self, + token: &MintableToken, + amount: ::alloy::primitives::U256, + ) { let pair = contracts::alloy::IUniswapLikePair::Instance::new( self.contracts .uniswap_v2_factory @@ -613,7 +596,9 @@ impl OnchainComponents { // Mint amount + 1 to the pool, and then swap out 1 of the minted token // in order to force it to update its K-value. - token.mint(pair.address().into_legacy(), amount + 1).await; + token + .mint(*pair.address(), amount + ::alloy::primitives::U256::ONE) + .await; let (out0, out1) = if self.contracts.weth.address() < token.address() { (1, 0) } else { @@ -707,25 +692,23 @@ impl OnchainComponents { cow } - pub async fn send_wei(&self, to: H160, amount: U256) { - let balance_before = self.web3.eth().balance(to, None).await.unwrap(); - let receipt = TransactionBuilder::new(self.web3.legacy.clone()) - .value(amount) - .to(to) - .send() + pub async fn send_wei(&self, to: Address, amount: ::alloy::primitives::U256) { + let balance_before = self.web3.alloy.get_balance(to).await.unwrap(); + self.web3 + .alloy + .send_transaction(TransactionRequest::default().with_to(to).with_value(amount)) + .await + .unwrap() + .watch() .await .unwrap(); - let TransactionResult::Receipt(receipt) = receipt else { - panic!("expected to get a transaction receipt"); - }; - assert_eq!(receipt.status, Some(1.into())); // There seems to be a bug in anvil where sending ETH does not work // reliably with a forked node. On some block numbers the transaction // supposedly succeeds but the balances still don't get changed. // If you hit this assert try using a different block number for your // forked test. - let balance_after = self.web3.eth().balance(to, None).await.unwrap(); + let balance_after = self.web3.alloy.get_balance(to).await.unwrap(); assert_eq!(balance_after, balance_before + amount); } diff --git a/crates/e2e/src/setup/onchain_components/safe.rs b/crates/e2e/src/setup/onchain_components/safe.rs index 5ac9f76343..bc063965fd 100644 --- a/crates/e2e/src/setup/onchain_components/safe.rs +++ b/crates/e2e/src/setup/onchain_components/safe.rs @@ -69,10 +69,7 @@ impl Infrastructure { let safe = GnosisSafe::Instance::new(safe_proxy, self.provider.clone()); safe.setup( - owners - .into_iter() - .map(|owner| owner.address().into_alloy()) - .collect(), + owners.into_iter().map(|owner| owner.address()).collect(), U256::from(threshold), Address::default(), // delegate call Bytes::default(), // delegate call bytes @@ -134,11 +131,9 @@ impl Safe { Default::default(), Default::default(), Default::default(), - crate::setup::safe::gnosis_safe_prevalidated_signature( - self.owner.address().into_alloy(), - ), + crate::setup::safe::gnosis_safe_prevalidated_signature(self.owner.address()), ) - .from(self.owner.address().into_alloy()) + .from(self.owner.address()) .send_and_watch() .await .unwrap(); diff --git a/crates/e2e/tests/e2e/app_data.rs b/crates/e2e/tests/e2e/app_data.rs index 6f7cec3148..2a8ad76747 100644 --- a/crates/e2e/tests/e2e/app_data.rs +++ b/crates/e2e/tests/e2e/app_data.rs @@ -32,17 +32,17 @@ async fn local_node_app_data_full_format() { // Test that orders can be placed with the new app data format. async fn app_data(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token_a.mint(trader.address(), to_wei(10)).await; + token_a.mint(trader.address(), eth(10)).await; token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -194,17 +194,17 @@ async fn app_data(web3: Web3) { /// all supported features. async fn app_data_full_format(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token_a.mint(trader.address(), to_wei(10)).await; + token_a.mint(trader.address(), eth(10)).await; token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); diff --git a/crates/e2e/tests/e2e/app_data_signer.rs b/crates/e2e/tests/e2e/app_data_signer.rs index 43a28a7f30..2a34354536 100644 --- a/crates/e2e/tests/e2e/app_data_signer.rs +++ b/crates/e2e/tests/e2e/app_data_signer.rs @@ -22,25 +22,25 @@ async fn local_node_order_creation_checks_metadata_signer() { async fn order_creation_checks_metadata_signer(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader, adversary, safe_owner] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader, adversary, safe_owner] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token_a.mint(trader.address(), to_wei(10)).await; + token_a.mint(trader.address(), eth(10)).await; token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); - token_a.mint(adversary.address(), to_wei(10)).await; + token_a.mint(adversary.address(), eth(10)).await; token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(adversary.address().into_alloy()) + .from(adversary.address()) .send_and_watch() .await .unwrap(); @@ -73,13 +73,13 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { services.start_protocol(solver).await; // Rejected: app data with different signer. - let full_app_data = full_app_data_with_signer(adversary.address().into_alloy()); + let full_app_data = full_app_data_with_signer(adversary.address()); let order1 = sign(create_order(full_app_data), &trader); let err = services.create_order(&order1).await.unwrap_err(); assert!(dbg!(err).1.contains("WrongOwner")); // Accepted: app data with correct signer. - let full_app_data = full_app_data_with_signer(trader.address().into_alloy()); + let full_app_data = full_app_data_with_signer(trader.address()); let order2 = sign(create_order(full_app_data.clone()), &trader); let uid = services.create_order(&order2).await.unwrap(); assert!(matches!(services.get_order(&uid).await, Ok(..))); @@ -99,7 +99,7 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { // EIP-1271 let safe = Safe::deploy(safe_owner.clone(), web3.alloy.clone()).await; - token_a.mint(safe.address().into_legacy(), to_wei(10)).await; + token_a.mint(safe.address(), eth(10)).await; safe.exec_alloy_call( token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) @@ -114,7 +114,7 @@ async fn order_creation_checks_metadata_signer(web3: Web3) { assert!(matches!(services.create_order(&order4).await, Ok(..))); // Rejected: from and signer are inconsistent. - let full_app_data = full_app_data_with_signer(adversary.address().into_alloy()); + let full_app_data = full_app_data_with_signer(adversary.address()); let mut order5 = create_order(full_app_data); order5.from = Some(safe.address().into_legacy()); safe.sign_order(&mut order5, &onchain); diff --git a/crates/e2e/tests/e2e/autopilot_leader.rs b/crates/e2e/tests/e2e/autopilot_leader.rs index 5eece8c177..d9e53c6bc8 100644 --- a/crates/e2e/tests/e2e/autopilot_leader.rs +++ b/crates/e2e/tests/e2e/autopilot_leader.rs @@ -33,22 +33,22 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { // TODO: Implement test that checks auction creation frequency against db // to see that only one autopilot produces auctions let mut onchain = OnchainComponents::deploy(web3).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; - let [solver1, solver2] = onchain.make_solvers(to_wei(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; + let [solver1, solver2] = onchain.make_solvers(eth(1)).await; let [token_a] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader, settlement accounts, and pool creation - token_a.mint(solver1.address(), to_wei(1000)).await; - token_a.mint(solver2.address(), to_wei(1000)).await; + token_a.mint(solver1.address(), eth(1000)).await; + token_a.mint(solver2.address(), eth(1000)).await; - token_a.mint(trader.address(), to_wei(200)).await; + token_a.mint(trader.address(), eth(200)).await; // Approve GPv2 for trading token_a .approve(onchain.contracts().allowance.into_alloy(), eth(1000)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -145,8 +145,7 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { .as_ref() .and_then(|competition| competition.solutions.first()) .map(|solution| { - solution.is_winner - && solution.solver_address == solver1.address().into_alloy() + solution.is_winner && solution.solver_address == solver1.address() }) } else { None @@ -182,8 +181,7 @@ async fn dual_autopilot_only_leader_produces_auctions(web3: Web3) { .as_ref() .and_then(|competition| competition.solutions.first()) .map(|solution| { - solution.is_winner - && solution.solver_address == solver2.address().into_alloy() + solution.is_winner && solution.solver_address == solver2.address() }) } else { None diff --git a/crates/e2e/tests/e2e/banned_users.rs b/crates/e2e/tests/e2e/banned_users.rs index 8b4e80351c..21027604d9 100644 --- a/crates/e2e/tests/e2e/banned_users.rs +++ b/crates/e2e/tests/e2e/banned_users.rs @@ -9,7 +9,6 @@ use { Services, eth, run_forked_test_with_block_number, - to_wei, to_wei_with_exp, }, ethrpc::{Web3, alloy::conversions::IntoAlloy}, @@ -37,7 +36,7 @@ const BANNED_USER: Address = address!("7F367cC41522cE07553e823bf3be79A889DEbe1B" async fn forked_mainnet_onchain_banned_user_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(eth(1)).await; let token_dai = ERC20::Instance::new( address!("6b175474e89094c44da98b954eedeac495271d0f"), diff --git a/crates/e2e/tests/e2e/buffers.rs b/crates/e2e/tests/e2e/buffers.rs index 688378b39e..6a5d31535c 100644 --- a/crates/e2e/tests/e2e/buffers.rs +++ b/crates/e2e/tests/e2e/buffers.rs @@ -23,28 +23,25 @@ async fn local_node_buffers() { async fn onchain_settlement_without_liquidity(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader, settlement accounts, and pool creation - token_a.mint(trader.address(), to_wei(100)).await; + token_a.mint(trader.address(), eth(100)).await; token_b - .mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(5), - ) + .mint(*onchain.contracts().gp_settlement.address(), eth(5)) .await; - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; // Approve GPv2 for trading token_a .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -112,12 +109,7 @@ async fn onchain_settlement_without_liquidity(web3: Web3) { tracing::info!("waiting for first trade"); onchain.mint_block().await; let trade_happened = || async { - token_b - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap() - == order.buy_amount.into_alloy() + token_b.balanceOf(trader.address()).call().await.unwrap() == order.buy_amount.into_alloy() }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); @@ -145,11 +137,7 @@ async fn onchain_settlement_without_liquidity(web3: Web3) { tracing::info!("waiting for second trade"); let trade_happened = || async { onchain.mint_block().await; - token_b - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap() + token_b.balanceOf(trader.address()).call().await.unwrap() == (order.buy_amount.into_alloy() * U256::from(2)) }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); diff --git a/crates/e2e/tests/e2e/cow_amm.rs b/crates/e2e/tests/e2e/cow_amm.rs index 459c6a91b0..3eeff7f5cc 100644 --- a/crates/e2e/tests/e2e/cow_amm.rs +++ b/crates/e2e/tests/e2e/cow_amm.rs @@ -57,8 +57,8 @@ async fn local_node_cow_amm_jit() { async fn cow_amm_jit(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(100)).await; - let [bob, cow_amm_owner] = onchain.make_accounts(to_wei(1000)).await; + let [solver] = onchain.make_solvers(eth(100)).await; + let [bob, cow_amm_owner] = onchain.make_accounts(eth(1000)).await; let [dai] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(100)) @@ -67,11 +67,8 @@ async fn cow_amm_jit(web3: Web3) { // Fund the buffers with a lot of buy tokens so we can pay out the required // tokens for 2 orders in the same direction without having to worry about // getting the liquidity on-chain. - dai.mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(100_000), - ) - .await; + dai.mint(*onchain.contracts().gp_settlement.address(), eth(100_000)) + .await; // set up cow_amm let oracle = @@ -88,10 +85,10 @@ async fn cow_amm_jit(web3: Web3) { .unwrap(); // Fund cow amm owner with 2_000 dai and allow factory take them - dai.mint(cow_amm_owner.address(), to_wei(2_000)).await; + dai.mint(cow_amm_owner.address(), eth(2_000)).await; dai.approve(*cow_amm_factory.address(), eth(2_000)) - .from(cow_amm_owner.address().into_alloy()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -101,7 +98,7 @@ async fn cow_amm_jit(web3: Web3) { .weth .deposit() .value(eth(1)) - .from(cow_amm_owner.address().into_alloy()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -109,7 +106,7 @@ async fn cow_amm_jit(web3: Web3) { .contracts() .weth .approve(*cow_amm_factory.address(), eth(1)) - .from(cow_amm_owner.address().into_alloy()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -124,7 +121,7 @@ async fn cow_amm_jit(web3: Web3) { let cow_amm = cow_amm_factory .ammDeterministicAddress( - cow_amm_owner.address().into_alloy(), + cow_amm_owner.address(), *dai.address(), *onchain.contracts().weth.address(), ) @@ -139,9 +136,9 @@ async fn cow_amm_jit(web3: Web3) { cow_amm_factory .create( *dai.address(), - to_wei(2_000).into_alloy(), + eth(2_000), *onchain.contracts().weth.address(), - to_wei(1).into_alloy(), + eth(1), U256::ZERO, // min traded token *oracle.address(), Bytes::copy_from_slice(&oracle_data), @@ -223,7 +220,7 @@ async fn cow_amm_jit(web3: Web3) { buyToken: *dai.address(), receiver: Default::default(), sellAmount: U256::from(10).pow(U256::from(17)), - buyAmount: to_wei(230).into_alloy(), + buyAmount: eth(230), validTo: valid_to, appData: FixedBytes(APP_DATA), feeAmount: U256::ZERO, @@ -272,7 +269,7 @@ async fn cow_amm_jit(web3: Web3) { .contracts() .weth .deposit() - .from(bob.address().into_alloy()) + .from(bob.address()) .value(alloy::primitives::U256::from(10u64.pow(17))) .send_and_watch() .await @@ -284,7 +281,7 @@ async fn cow_amm_jit(web3: Web3) { onchain.contracts().allowance.into_alloy(), alloy::primitives::U256::MAX, ) - .from(bob.address().into_alloy()) + .from(bob.address()) .send_and_watch() .await .unwrap(); @@ -307,11 +304,7 @@ async fn cow_amm_jit(web3: Web3) { let user_order_id = services.create_order(&user_order).await.unwrap(); let amm_balance_before = dai.balanceOf(*cow_amm.address()).call().await.unwrap(); - let bob_balance_before = dai - .balanceOf(bob.address().into_alloy()) - .call() - .await - .unwrap(); + let bob_balance_before = dai.balanceOf(bob.address()).call().await.unwrap(); let fee = ethcontract::U256::exp10(16); // 0.01 WETH @@ -364,11 +357,7 @@ async fn cow_amm_jit(web3: Web3) { onchain.mint_block().await; wait_for_condition(TIMEOUT, || async { let amm_balance = dai.balanceOf(*cow_amm.address()).call().await.unwrap(); - let bob_balance = dai - .balanceOf(bob.address().into_alloy()) - .call() - .await - .unwrap(); + let bob_balance = dai.balanceOf(bob.address()).call().await.unwrap(); let amm_received = amm_balance - amm_balance_before; let bob_received = bob_balance - bob_balance_before; @@ -413,8 +402,8 @@ async fn cow_amm_driver_support(web3: Web3) { }; let mut onchain = OnchainComponents::deployed_with(web3.clone(), deployed_contracts).await; - let [solver] = onchain.make_solvers_forked(to_wei(11)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(eth(11)).await; + let [trader] = onchain.make_accounts(eth(1)).await; // find some USDC available onchain const USDC_WHALE_MAINNET: Address = address!("28c6c06298d514db089934071355e5743bf21d60"); @@ -453,7 +442,7 @@ async fn cow_amm_driver_support(web3: Web3) { .contracts() .weth .deposit() - .from(solver.address().into_alloy()) + .from(solver.address()) .value(weth_to_send) .send_and_watch() .await @@ -462,7 +451,7 @@ async fn cow_amm_driver_support(web3: Web3) { .contracts() .weth .transfer(USDC_WETH_COW_AMM.into_alloy(), weth_to_send) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -480,12 +469,9 @@ async fn cow_amm_driver_support(web3: Web3) { // Give trader some USDC web3.alloy .anvil_send_impersonated_transaction_with_config( - usdc.transfer( - trader.address().into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) - .from(USDC_WHALE_MAINNET) - .into_transaction_request(), + usdc.transfer(trader.address(), to_wei_with_exp(1000, 6).into_alloy()) + .from(USDC_WHALE_MAINNET) + .into_transaction_request(), ImpersonateConfig { fund_amount: None, stop_impersonate: true, @@ -502,7 +488,7 @@ async fn cow_amm_driver_support(web3: Web3) { onchain.contracts().allowance.into_alloy(), to_wei_with_exp(1000, 6).into_alloy(), ) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -714,8 +700,8 @@ async fn local_node_cow_amm_opposite_direction() { async fn cow_amm_opposite_direction(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(100)).await; - let [bob, cow_amm_owner] = onchain.make_accounts(to_wei(1000)).await; + let [solver] = onchain.make_solvers(eth(100)).await; + let [bob, cow_amm_owner] = onchain.make_accounts(eth(1000)).await; let [dai] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(100)) @@ -740,10 +726,10 @@ async fn cow_amm_opposite_direction(web3: Web3) { // Fund the CoW AMM owner with DAI and WETH and approve the factory to transfer // them - dai.mint(cow_amm_owner.address(), to_wei(2_000)).await; + dai.mint(cow_amm_owner.address(), eth(2_000)).await; dai.approve(*cow_amm_factory.address(), eth(2_000)) - .from(cow_amm_owner.address().into_alloy()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -752,7 +738,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { .contracts() .weth .deposit() - .from(cow_amm_owner.address().into_alloy()) + .from(cow_amm_owner.address()) .value(eth(1)) .send_and_watch() .await @@ -761,7 +747,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { .contracts() .weth .approve(*cow_amm_factory.address(), eth(1)) - .from(cow_amm_owner.address().into_alloy()) + .from(cow_amm_owner.address()) .send_and_watch() .await .unwrap(); @@ -770,7 +756,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { .contracts() .weth .deposit() - .from(solver.address().into_alloy()) + .from(solver.address()) .value(eth(1)) .send_and_watch() .await @@ -786,7 +772,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { let cow_amm_address = cow_amm_factory .ammDeterministicAddress( - cow_amm_owner.address().into_alloy(), + cow_amm_owner.address(), *dai.address(), *onchain.contracts().weth.address(), ) @@ -802,9 +788,9 @@ async fn cow_amm_opposite_direction(web3: Web3) { cow_amm_factory .create( *dai.address(), - to_wei(2_000).into_alloy(), + eth(2_000), *onchain.contracts().weth.address(), - to_wei(1).into_alloy(), + eth(1), U256::ZERO, // min traded token *oracle.address(), Bytes::copy_from_slice(&oracle_data), @@ -923,13 +909,13 @@ async fn cow_amm_opposite_direction(web3: Web3) { }; // Fund trader "bob" with DAI and approve allowance - dai.mint(bob.address(), to_wei(250)).await; + dai.mint(bob.address(), eth(250)).await; dai.approve( onchain.contracts().allowance.into_alloy(), alloy::primitives::U256::MAX, ) - .from(bob.address().into_alloy()) + .from(bob.address()) .send_and_watch() .await .unwrap(); @@ -945,7 +931,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { let bob_weth_balance_before = onchain .contracts() .weth - .balanceOf(bob.address().into_alloy()) + .balanceOf(bob.address()) .call() .await .unwrap(); @@ -1008,7 +994,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { mock_solver.configure_solution(Some(mocked_quote_solution)); let quote_request = OrderQuoteRequest { - from: bob.address().into_alloy(), + from: bob.address(), sell_token: *dai.address(), buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { @@ -1022,16 +1008,19 @@ async fn cow_amm_opposite_direction(web3: Web3) { // Must align with the mocked_solutions. let quote_response = services.submit_quote("e_request).await.unwrap(); assert!(quote_response.verified); - assert_eq!(quote_response.quote.sell_token, dai.address().into_legacy()); + assert_eq!(quote_response.quote.sell_token, *dai.address()); assert_eq!( quote_response.quote.buy_token, - onchain.contracts().weth.address().into_legacy() + *onchain.contracts().weth.address() ); // Ensure the amounts are the same as the solution proposes. - assert_eq!(quote_response.quote.sell_amount, executed_amount); + assert_eq!( + quote_response.quote.sell_amount, + executed_amount.into_alloy() + ); assert_eq!( quote_response.quote.buy_amount, - ethcontract::U256::exp10(17) + U256::from(10).pow(U256::from(17)) ); // Place user order where bob sells DAI to buy WETH (opposite direction) @@ -1070,7 +1059,7 @@ async fn cow_amm_opposite_direction(web3: Web3) { let bob_weth_balance_after = onchain .contracts() .weth - .balanceOf(bob.address().into_alloy()) + .balanceOf(bob.address()) .call() .await .unwrap(); diff --git a/crates/e2e/tests/e2e/eth_integration.rs b/crates/e2e/tests/e2e/eth_integration.rs index b9e97b2ee6..23b2cdd7f4 100644 --- a/crates/e2e/tests/e2e/eth_integration.rs +++ b/crates/e2e/tests/e2e/eth_integration.rs @@ -25,33 +25,37 @@ async fn local_node_eth_integration() { async fn eth_integration(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader_a, trader_b] = onchain.make_accounts(eth(1)).await; // Create & mint tokens to trade, pools for fee connections let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) .await; - token.mint(trader_a.address(), to_wei(51)).await; - token.mint(trader_b.address(), to_wei(51)).await; + token.mint(trader_a.address(), eth(51)).await; + token.mint(trader_b.address(), eth(51)).await; // Approve GPv2 for trading token .approve(onchain.contracts().allowance.into_alloy(), eth(51)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token .approve(onchain.contracts().allowance.into_alloy(), eth(51)) - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); - let trader_a_eth_balance_before = web3.eth().balance(trader_a.address(), None).await.unwrap(); + let trader_a_eth_balance_before = web3 + .eth() + .balance(trader_a.address().into_legacy(), None) + .await + .unwrap(); let services = Services::new(&onchain).await; services.start_protocol(solver).await; @@ -121,8 +125,16 @@ async fn eth_integration(web3: Web3) { tracing::info!("Waiting for trade."); onchain.mint_block().await; let trade_happened = || async { - let balance_a = web3.eth().balance(trader_a.address(), None).await.unwrap(); - let balance_b = web3.eth().balance(trader_b.address(), None).await.unwrap(); + let balance_a = web3 + .eth() + .balance(trader_a.address().into_legacy(), None) + .await + .unwrap(); + let balance_b = web3 + .eth() + .balance(trader_b.address().into_legacy(), None) + .await + .unwrap(); let trader_a_eth_decreased = (balance_a - trader_a_eth_balance_before) == to_wei(49); let trader_b_eth_increased = balance_b >= to_wei(49); diff --git a/crates/e2e/tests/e2e/eth_safe.rs b/crates/e2e/tests/e2e/eth_safe.rs index c23ae7eacd..b3569ce341 100644 --- a/crates/e2e/tests/e2e/eth_safe.rs +++ b/crates/e2e/tests/e2e/eth_safe.rs @@ -31,25 +31,25 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; let safe = Safe::deploy(trader.clone(), web3.alloy.clone()).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1000), to_wei(1000)) .await; - token.mint(trader.address(), to_wei(4)).await; + token.mint(trader.address(), eth(4)).await; safe.exec_alloy_call( token .approve(onchain.contracts().allowance.into_alloy(), eth(4)) .into_transaction_request(), ) .await; - token.mint(safe.address().into_legacy(), to_wei(4)).await; + token.mint(safe.address(), eth(4)).await; token .approve(onchain.contracts().allowance.into_alloy(), eth(4)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); diff --git a/crates/e2e/tests/e2e/ethflow.rs b/crates/e2e/tests/e2e/ethflow.rs index 5b961461c4..726f2ab758 100644 --- a/crates/e2e/tests/e2e/ethflow.rs +++ b/crates/e2e/tests/e2e/ethflow.rs @@ -1,6 +1,6 @@ use { alloy::{ - primitives::{Address, Bytes}, + primitives::{Address, Bytes, U256 as AlloyU256}, rpc::types::TransactionReceipt, }, anyhow::bail, @@ -93,8 +93,8 @@ async fn local_node_eth_flow_zero_buy_amount() { async fn eth_flow_tx(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(eth(2)).await; + let [trader] = onchain.make_accounts(eth(2)).await; // Create token with Uniswap pool for price estimation let [dai] = onchain @@ -115,7 +115,7 @@ async fn eth_flow_tx(web3: Web3) { services.start_protocol(solver).await; let approve_call_data = { - let call_builder = dai.approve(trader.address().into_alloy(), eth(10)); + let call_builder = dai.approve(trader.address(), eth(10)); let calldata = call_builder.calldata(); const_hex::encode_prefixed(calldata) }; @@ -185,7 +185,7 @@ async fn eth_flow_tx(web3: Web3) { test_order_availability_in_api( &services, ðflow_order, - &trader.address().into_alloy(), + &trader.address(), onchain.contracts(), ethflow_contract, ) @@ -213,7 +213,7 @@ async fn eth_flow_tx(web3: Web3) { test_trade_availability_in_api( services.client(), ðflow_order, - &trader.address(), + &trader.address().into_legacy(), onchain.contracts(), ethflow_contract, ) @@ -224,7 +224,7 @@ async fn eth_flow_tx(web3: Web3) { // which proofs that the interactions were correctly sandboxed. let trampoline = *onchain.contracts().hooks.address(); let allowance = dai - .allowance(trampoline, trader.address().into_alloy()) + .allowance(trampoline, trader.address()) .call() .await .unwrap(); @@ -233,7 +233,7 @@ async fn eth_flow_tx(web3: Web3) { let allowance = onchain .contracts() .weth - .allowance(trampoline, trader.address().into_alloy()) + .allowance(trampoline, trader.address()) .call() .await .unwrap(); @@ -243,7 +243,7 @@ async fn eth_flow_tx(web3: Web3) { // able to set an allowance on behalf of the settlement contract. let settlement = onchain.contracts().gp_settlement.address(); let allowance = dai - .allowance(*settlement, trader.address().into_alloy()) + .allowance(*settlement, trader.address()) .call() .await .unwrap(); @@ -252,7 +252,7 @@ async fn eth_flow_tx(web3: Web3) { let allowance = onchain .contracts() .weth - .allowance(*settlement, trader.address().into_alloy()) + .allowance(*settlement, trader.address()) .call() .await .unwrap(); @@ -262,8 +262,8 @@ async fn eth_flow_tx(web3: Web3) { async fn eth_flow_without_quote(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(eth(2)).await; + let [trader] = onchain.make_accounts(eth(2)).await; // Create token with Uniswap pool for price estimation let [dai] = onchain @@ -302,7 +302,7 @@ async fn eth_flow_without_quote(web3: Web3) { test_order_availability_in_api( &services, ðflow_order, - &trader.address().into_alloy(), + &trader.address(), onchain.contracts(), ethflow_contract, ) @@ -315,8 +315,8 @@ async fn eth_flow_without_quote(web3: Web3) { async fn eth_flow_indexing_after_refund(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader, dummy_trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(eth(2)).await; + let [trader, dummy_trader] = onchain.make_accounts(eth(2)).await; let [dai] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(DAI_PER_ETH * 1000), to_wei(1000)) .await; @@ -357,7 +357,7 @@ async fn eth_flow_indexing_after_refund(web3: Web3) { onchain.mint_block().await; dummy_order - .mine_order_invalidation(dummy_trader.address().into_alloy(), ethflow_contract) + .mine_order_invalidation(dummy_trader.address(), ethflow_contract) .await; // Create the actual order that should be picked up by the services and matched. @@ -417,9 +417,13 @@ async fn test_submit_quote( // Ideally the fee would be nonzero, but this is not the case in the test // environment assert_ne!(response.quote.fee_amount, 0.into()); // Amount is reasonable (±10% from real price) - let approx_output: U256 = response.quote.sell_amount * DAI_PER_ETH; - assert!(response.quote.buy_amount.gt(&(approx_output * 9u64 / 10))); - assert!(response.quote.buy_amount.lt(&(approx_output * 11u64 / 10))); + let approx_output: AlloyU256 = response.quote.sell_amount * AlloyU256::from(DAI_PER_ETH); + assert!( + response.quote.buy_amount > (approx_output * AlloyU256::from(9u64) / AlloyU256::from(10)) + ); + assert!( + response.quote.buy_amount < (approx_output * AlloyU256::from(11u64) / AlloyU256::from(10)) + ); let OrderQuoteSide::Sell { sell_amount: @@ -431,7 +435,10 @@ async fn test_submit_quote( panic!("untested!"); }; - assert_eq!(response.quote.sell_amount, sell_amount_after_fees.get()); + assert_eq!( + response.quote.sell_amount, + sell_amount_after_fees.get().into_alloy() + ); response } @@ -656,13 +663,10 @@ impl ExtendedEthFlowOrder { pub fn from_quote(quote_response: &OrderQuoteResponse, valid_to: u32) -> Self { let quote = "e_response.quote; ExtendedEthFlowOrder(CoWSwapEthFlow::EthFlowOrder::Data { - buyToken: quote.buy_token.into_alloy(), - receiver: quote - .receiver - .expect("eth-flow order without receiver") - .into_alloy(), - sellAmount: quote.sell_amount.into_alloy(), - buyAmount: quote.buy_amount.into_alloy(), + buyToken: quote.buy_token, + receiver: quote.receiver.expect("eth-flow order without receiver"), + sellAmount: quote.sell_amount, + buyAmount: quote.buy_amount, appData: quote.app_data.hash().0.into(), feeAmount: alloy::primitives::U256::ZERO, validTo: valid_to, // note: valid to in the quote is always unlimited @@ -876,8 +880,8 @@ impl EthFlowTradeIntent { async fn eth_flow_zero_buy_amount(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(2)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(eth(2)).await; + let [trader_a, trader_b] = onchain.make_accounts(eth(2)).await; // Create token with Uniswap pool for price estimation let [dai] = onchain @@ -917,7 +921,7 @@ async fn eth_flow_zero_buy_amount(web3: Web3) { test_order_availability_in_api( &services, ðflow_order, - &trader.address().into_alloy(), + &trader.address(), onchain.contracts(), ethflow_contract, ) diff --git a/crates/e2e/tests/e2e/hooks.rs b/crates/e2e/tests/e2e/hooks.rs index 29a406ac74..36868d0fa5 100644 --- a/crates/e2e/tests/e2e/hooks.rs +++ b/crates/e2e/tests/e2e/hooks.rs @@ -62,16 +62,16 @@ async fn local_node_quote_verification() { async fn gas_limit(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let cow = onchain .deploy_cow_weth_pool(to_wei(1_000_000), to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts and approve relayer - cow.fund(trader.address(), to_wei(5)).await; + cow.fund(trader.address(), eth(5)).await; cow.approve(onchain.contracts().allowance.into_alloy(), eth(5)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -91,7 +91,7 @@ async fn gas_limit(web3: Web3) { "metadata": { "hooks": { "pre": [Hook { - target: trader.address().into_alloy(), + target: trader.address(), call_data: Default::default(), gas_limit: 8_000_000, }], @@ -116,14 +116,14 @@ async fn gas_limit(web3: Web3) { async fn allowance(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let cow = onchain .deploy_cow_weth_pool(to_wei(1_000_000), to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts - cow.fund(trader.address(), to_wei(5)).await; + cow.fund(trader.address(), eth(5)).await; // Sign a permit pre-interaction for trading. let permit = cow @@ -133,8 +133,8 @@ async fn allowance(web3: Web3) { // the settlement contract. let steal_cow = { let tx = cow - .approve(trader.address().into_alloy(), alloy::primitives::U256::MAX) - .from(solver.address().into_alloy()); + .approve(trader.address(), alloy::primitives::U256::MAX) + .from(solver.address()); Hook { target: *cow.address(), call_data: tx.calldata().to_vec(), @@ -142,10 +142,10 @@ async fn allowance(web3: Web3) { } }; let steal_weth = { - let approve = onchain.contracts().weth.approve( - trader.address().into_alloy(), - ::alloy::primitives::U256::MAX, - ); + let approve = onchain + .contracts() + .weth + .approve(trader.address(), ::alloy::primitives::U256::MAX); Hook { target: *onchain.contracts().weth.address(), call_data: approve.calldata().to_vec(), @@ -184,16 +184,12 @@ async fn allowance(web3: Web3) { services.create_order(&order).await.unwrap(); onchain.mint_block().await; - let balance = cow - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = cow.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, eth(5)); tracing::info!("Waiting for trade."); let trade_happened = || async { - cow.balanceOf(trader.address().into_alloy()) + cow.balanceOf(trader.address()) .call() .await .unwrap() @@ -205,7 +201,7 @@ async fn allowance(web3: Web3) { let balance = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -219,7 +215,7 @@ async fn allowance(web3: Web3) { let allowance = cow .allowance( *onchain.contracts().gp_settlement.address(), - trader.address().into_alloy(), + trader.address(), ) .call() .await @@ -230,7 +226,7 @@ async fn allowance(web3: Web3) { .weth .allowance( *onchain.contracts().gp_settlement.address(), - trader.address().into_alloy(), + trader.address(), ) .call() .await @@ -241,10 +237,7 @@ async fn allowance(web3: Web3) { // This is OK since the `HooksTrampoline` contract is not used for holding // any funds. let allowance = cow - .allowance( - *onchain.contracts().hooks.address(), - trader.address().into_alloy(), - ) + .allowance(*onchain.contracts().hooks.address(), trader.address()) .call() .await .unwrap(); @@ -252,10 +245,7 @@ async fn allowance(web3: Web3) { let allowance = onchain .contracts() .weth - .allowance( - *onchain.contracts().hooks.address(), - trader.address().into_alloy(), - ) + .allowance(*onchain.contracts().hooks.address(), trader.address()) .call() .await .unwrap(); @@ -267,8 +257,8 @@ async fn signature(web3: Web3) { let chain_id = alloy::primitives::U256::from(web3.alloy.get_chain_id().await.unwrap()); - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let safe_infra = onchain_components::safe::Infrastructure::new(web3.alloy.clone()).await; @@ -279,7 +269,7 @@ async fn signature(web3: Web3) { safe_infra .singleton .setup( - vec![trader.address().into_alloy()], // owners + vec![trader.address()], // owners alloy::primitives::U256::ONE, // threshold alloy::primitives::Address::default(), // delegate call alloy::primitives::Bytes::default(), // delegate call bytes @@ -308,7 +298,7 @@ async fn signature(web3: Web3) { let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) .await; - token.mint(safe.address().into_legacy(), to_wei(5)).await; + token.mint(safe.address(), eth(5)).await; // Sign an approval transaction for trading. This will be at nonce 0 because // it is the first transaction evah! @@ -429,8 +419,8 @@ async fn signature(web3: Web3) { async fn partial_fills(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(3)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(3)).await; let counter = contracts::alloy::test::Counter::Instance::deploy(web3.alloy.clone()) .await @@ -443,44 +433,34 @@ async fn partial_fills(web3: Web3) { let sell_token = onchain.contracts().weth.clone(); sell_token .approve(onchain.contracts().allowance.into_alloy(), eth(2)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); sell_token .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(1)) .send_and_watch() .await .unwrap(); - let balance_before_first_trade = sell_token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before_first_trade = sell_token.balanceOf(trader.address()).call().await.unwrap(); tracing::info!("Starting services."); let services = Services::new(&onchain).await; services.start_protocol(solver).await; - let pre_inc = counter.setCounterToBalance( - "pre".to_string(), - *sell_token.address(), - trader.address().into_alloy(), - ); + let pre_inc = + counter.setCounterToBalance("pre".to_string(), *sell_token.address(), trader.address()); let pre_hook = Hook { target: *counter.address(), call_data: pre_inc.calldata().to_vec(), gas_limit: pre_inc.estimate_gas().await.unwrap(), }; - let post_inc = counter.setCounterToBalance( - "post".to_string(), - *sell_token.address(), - trader.address().into_alloy(), - ); + let post_inc = + counter.setCounterToBalance("post".to_string(), *sell_token.address(), trader.address()); let post_hook = Hook { target: *counter.address(), call_data: post_inc.calldata().to_vec(), @@ -520,7 +500,7 @@ async fn partial_fills(web3: Web3) { tracing::info!("Waiting for first trade."); let trade_happened = || async { sell_token - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap() @@ -531,11 +511,8 @@ async fn partial_fills(web3: Web3) { counter.counters("pre".to_string()).call().await.unwrap(), balance_before_first_trade ); - let post_balance_after_first_trade = sell_token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let post_balance_after_first_trade = + sell_token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!( counter.counters("post".to_string()).call().await.unwrap(), post_balance_after_first_trade @@ -544,7 +521,7 @@ async fn partial_fills(web3: Web3) { tracing::info!("Fund remaining sell balance."); sell_token .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(1)) .send_and_watch() .await @@ -558,11 +535,7 @@ async fn partial_fills(web3: Web3) { ); assert_eq!( counter.counters("post".to_string()).call().await.unwrap(), - sell_token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap() + sell_token.balanceOf(trader.address()).call().await.unwrap() ); } @@ -573,8 +546,8 @@ async fn quote_verification(web3: Web3) { let chain_id = alloy::primitives::U256::from(web3.alloy.get_chain_id().await.unwrap()); - let [trader] = onchain.make_accounts(to_wei(1)).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; let safe_infra = onchain_components::safe::Infrastructure::new(web3.alloy.clone()).await; @@ -585,7 +558,7 @@ async fn quote_verification(web3: Web3) { safe_infra .singleton .setup( - vec![trader.address().into_alloy()], // owners + vec![trader.address()], // owners alloy::primitives::U256::ONE, // threshold alloy::primitives::Address::default(), // delegate call alloy::primitives::Bytes::default(), // delegate call bytes @@ -609,11 +582,11 @@ async fn quote_verification(web3: Web3) { let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) .await; - token.mint(safe.address().into_legacy(), to_wei(5)).await; + token.mint(safe.address(), eth(5)).await; token .approve(onchain.contracts().allowance.into_alloy(), eth(5)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -622,10 +595,7 @@ async fn quote_verification(web3: Web3) { // to fund the trade in a pre-hook. let transfer_builder = safe.sign_transaction( *token.address(), - token - .transfer(trader.address().into_alloy(), eth(5)) - .calldata() - .to_vec(), + token.transfer(trader.address(), eth(5)).calldata().to_vec(), alloy::primitives::U256::ZERO, ); let call_data = transfer_builder.calldata().to_vec(); @@ -647,7 +617,7 @@ async fn quote_verification(web3: Web3) { let quote = services .submit_quote(&OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *token.address(), buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { diff --git a/crates/e2e/tests/e2e/jit_orders.rs b/crates/e2e/tests/e2e/jit_orders.rs index 52555d75d0..bfca8853e6 100644 --- a/crates/e2e/tests/e2e/jit_orders.rs +++ b/crates/e2e/tests/e2e/jit_orders.rs @@ -25,19 +25,19 @@ async fn local_node_single_limit_order() { async fn single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(100)).await; - let [trader] = onchain.make_accounts(to_wei(100)).await; + let [solver] = onchain.make_solvers(eth(100)).await; + let [trader] = onchain.make_accounts(eth(100)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(1_000)) .await; - token.mint(solver.address(), to_wei(100)).await; + token.mint(solver.address(), eth(100)).await; onchain .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(20)) .send_and_watch() .await @@ -47,14 +47,14 @@ async fn single_limit_order_test(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), U256::MAX) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); token .approve(onchain.contracts().allowance.into_alloy(), U256::MAX) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -125,23 +125,15 @@ async fn single_limit_order_test(web3: Web3) { SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), ); - let trader_balance_before = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let solver_balance_before = token - .balanceOf(solver.address().into_alloy()) - .call() - .await - .unwrap(); + let trader_balance_before = token.balanceOf(trader.address()).call().await.unwrap(); + let solver_balance_before = token.balanceOf(solver.address()).call().await.unwrap(); let order_id = services.create_order(&order).await.unwrap(); let limit_order = services.get_order(&order_id).await.unwrap(); onchain.mint_block().await; assert_eq!(limit_order.metadata.class, OrderClass::Limit); let (jit_order, jit_order_uid) = JitOrder { - owner: trader.address(), + owner: trader.address().into_legacy(), sell: Asset { amount: to_wei(10), token: token.address().into_legacy(), @@ -154,7 +146,7 @@ async fn single_limit_order_test(web3: Web3) { partially_fillable: false, valid_to: model::time::now_in_epoch_seconds() + 300, app_data: Default::default(), - receiver: solver.address(), + receiver: solver.address().into_legacy(), } .sign( EcdsaSigningScheme::Eip712, @@ -194,16 +186,8 @@ async fn single_limit_order_test(web3: Web3) { tracing::info!("Waiting for trade."); onchain.mint_block().await; wait_for_condition(TIMEOUT, || async { - let trader_balance_after = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let solver_balance_after = token - .balanceOf(solver.address().into_alloy()) - .call() - .await - .unwrap(); + let trader_balance_after = token.balanceOf(trader.address()).call().await.unwrap(); + let solver_balance_after = token.balanceOf(solver.address()).call().await.unwrap(); let trader_balance_increased = trader_balance_after.saturating_sub(trader_balance_before) >= eth(5); diff --git a/crates/e2e/tests/e2e/limit_orders.rs b/crates/e2e/tests/e2e/limit_orders.rs index 7dfe8716cd..c3162d13d8 100644 --- a/crates/e2e/tests/e2e/limit_orders.rs +++ b/crates/e2e/tests/e2e/limit_orders.rs @@ -97,37 +97,37 @@ async fn forked_node_gnosis_single_limit_order() { async fn single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader_a] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), eth(10)).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -141,10 +141,10 @@ async fn single_limit_order_test(web3: Web3) { eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -153,7 +153,7 @@ async fn single_limit_order_test(web3: Web3) { token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -176,11 +176,7 @@ async fn single_limit_order_test(web3: Web3) { &onchain.contracts().domain_separator, SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), ); - let balance_before = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_b.balanceOf(trader_a.address()).call().await.unwrap(); let order_id = services.create_order(&order).await.unwrap(); // we hide the quote's execution plan while the order is still fillable @@ -197,11 +193,7 @@ async fn single_limit_order_test(web3: Web3) { // Drive solution tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = token_b.balanceOf(trader_a.address()).call().await.unwrap(); balance_after.checked_sub(balance_before).unwrap() >= eth(5) }) .await @@ -220,38 +212,38 @@ async fn single_limit_order_test(web3: Web3) { async fn two_limit_orders_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader_a, trader_b] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts and prepare funding Uniswap pool - token_a.mint(trader_a.address(), to_wei(10)).await; - token_b.mint(trader_b.address(), to_wei(10)).await; - token_a.mint(solver.address(), to_wei(1_000)).await; - token_b.mint(solver.address(), to_wei(1_000)).await; + token_a.mint(trader_a.address(), eth(10)).await; + token_b.mint(trader_b.address(), eth(10)).await; + token_a.mint(solver.address(), eth(1_000)).await; + token_b.mint(solver.address(), eth(1_000)).await; // Create and fund Uniswap pool onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -265,10 +257,10 @@ async fn two_limit_orders_test(web3: Web3) { eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -277,14 +269,14 @@ async fn two_limit_orders_test(web3: Web3) { token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_b .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -308,16 +300,8 @@ async fn two_limit_orders_test(web3: Web3) { SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), ); - let balance_before_a = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - let balance_before_b = token_a - .balanceOf(trader_b.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before_a = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + let balance_before_b = token_a.balanceOf(trader_b.address()).call().await.unwrap(); let order_id = services.create_order(&order_a).await.unwrap(); onchain.mint_block().await; @@ -347,16 +331,8 @@ async fn two_limit_orders_test(web3: Web3) { // Drive solution tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after_a = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); - let balance_after_b = token_a - .balanceOf(trader_b.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after_a = token_b.balanceOf(trader_a.address()).call().await.unwrap(); + let balance_after_b = token_a.balanceOf(trader_b.address()).call().await.unwrap(); let order_a_settled = balance_after_a.saturating_sub(balance_before_a) >= eth(5); let order_b_settled = balance_after_b.saturating_sub(balance_before_b) >= eth(2); order_a_settled && order_b_settled @@ -368,15 +344,15 @@ async fn two_limit_orders_test(web3: Web3) { async fn two_limit_orders_multiple_winners_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver_a, solver_b] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver_a, solver_b] = onchain.make_solvers(eth(1)).await; + let [trader_a, trader_b] = onchain.make_accounts(eth(1)).await; let [token_a, token_b, token_c, token_d] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund traders - token_a.mint(trader_a.address(), to_wei(10)).await; - token_b.mint(trader_b.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), eth(10)).await; + token_b.mint(trader_b.address(), eth(10)).await; // Create more liquid routes between token_a (token_b) and weth via base_a // (base_b). base_a has more liquidity than base_b, leading to the solver that @@ -385,24 +361,24 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { .deploy_tokens_with_weth_uni_v2_pools(to_wei(10_000), to_wei(10_000)) .await; onchain - .seed_uni_v2_pool((&token_a, to_wei(100_000)), (&base_a, to_wei(100_000))) + .seed_uni_v2_pool((&token_a, eth(100_000)), (&base_a, eth(100_000))) .await; onchain - .seed_uni_v2_pool((&token_b, to_wei(10_000)), (&base_b, to_wei(10_000))) + .seed_uni_v2_pool((&token_b, eth(10_000)), (&base_b, eth(10_000))) .await; // Approve GPv2 for trading token_a .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_b .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -528,7 +504,7 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { database::solver_competition_v2::fetch_solver_winning_solutions( &mut ex, competition.auction_id, - ByteArray(solver_a.address().0), + ByteArray(solver_a.address().into_legacy().0), ) .await .unwrap(); @@ -536,7 +512,7 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { database::solver_competition_v2::fetch_solver_winning_solutions( &mut ex, competition.auction_id, - ByteArray(solver_b.address().0), + ByteArray(solver_b.address().into_legacy().0), ) .await .unwrap(); @@ -573,10 +549,10 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { .unwrap(); assert_eq!(settlements.len(), 2); assert!(settlements.iter().any(|settlement| settlement.solver - == ByteArray(solver_a.address().0) + == ByteArray(solver_a.address().into_legacy().0) && settlement.solution_uid == solver_a_winning_solutions[0].uid)); assert!(settlements.iter().any(|settlement| settlement.solver - == ByteArray(solver_b.address().0) + == ByteArray(solver_b.address().into_legacy().0) && settlement.solution_uid == solver_b_winning_solutions[0].uid)); // Ensure all the reference scores are indexed @@ -591,11 +567,11 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { // fetch the reference scores of both winners let solver_a_reference_score = reference_scores - .get(&ByteArray(solver_a.address().0)) + .get(&ByteArray(solver_a.address().into_legacy().0)) .unwrap() .clone(); let solver_b_reference_score = reference_scores - .get(&ByteArray(solver_b.address().0)) + .get(&ByteArray(solver_b.address().into_legacy().0)) .unwrap() .clone(); @@ -610,18 +586,18 @@ async fn two_limit_orders_multiple_winners_test(web3: Web3) { async fn too_many_limit_orders_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_a] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token_a.mint(trader.address(), to_wei(1)).await; + token_a.mint(trader.address(), eth(1)).await; // Approve GPv2 for trading token_a .approve(onchain.contracts().allowance.into_alloy(), eth(101)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -692,18 +668,18 @@ async fn too_many_limit_orders_test(web3: Web3) { async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token.mint(trader.address(), to_wei(100)).await; + token.mint(trader.address(), eth(100)).await; // Approve GPv2 for trading token .approve(onchain.contracts().allowance.into_alloy(), eth(101)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -734,7 +710,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { .await; let quote_request = OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *token.address(), buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { @@ -749,9 +725,9 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place "in-market" order let order = OrderCreation { sell_token: token.address().into_legacy(), - sell_amount: quote.quote.sell_amount, + sell_amount: quote.quote.sell_amount.into_legacy(), buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(4)), + buy_amount: quote.quote.buy_amount.saturating_sub(eth(4)).into_legacy(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -785,9 +761,9 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place another "in-market" order in order to check it is not limited let order = OrderCreation { sell_token: token.address().into_legacy(), - sell_amount: quote.quote.sell_amount, + sell_amount: quote.quote.sell_amount.into_legacy(), buy_token: onchain.contracts().weth.address().into_legacy(), - buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(2)), + buy_amount: quote.quote.buy_amount.saturating_sub(eth(2)).into_legacy(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -823,9 +799,9 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { async fn forked_mainnet_single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(eth(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let token_usdc = ERC20::Instance::new( address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), @@ -841,10 +817,7 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { web3.alloy .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer( - trader.address().into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) + .transfer(trader.address(), to_wei_with_exp(1000, 6).into_alloy()) .from(USDC_WHALE_MAINNET) .into_transaction_request(), ImpersonateConfig { @@ -864,7 +837,7 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { onchain.contracts().allowance.into_alloy(), to_wei_with_exp(1000, 6).into_alloy(), ) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -905,16 +878,8 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { }) .await; - let sell_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_before = token_usdt - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_before = token_usdt.balanceOf(trader.address()).call().await.unwrap(); let order_id = services.create_order(&order).await.unwrap(); let limit_order = services.get_order(&order_id).await.unwrap(); assert_eq!(limit_order.metadata.class, OrderClass::Limit); @@ -924,16 +889,8 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { wait_for_condition(TIMEOUT, || async { onchain.mint_block().await; - let sell_token_balance_after = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_after = token_usdt - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_after = token_usdc.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_after = token_usdt.balanceOf(trader.address()).call().await.unwrap(); (sell_token_balance_before > sell_token_balance_after) && (buy_token_balance_after @@ -946,9 +903,9 @@ async fn forked_mainnet_single_limit_order_test(web3: Web3) { async fn forked_gnosis_single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(eth(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let token_usdc = ERC20::Instance::new( address!("ddafbb505ad214d7b80b1f830fccc89b60fb7a83"), @@ -964,10 +921,7 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { web3.alloy .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer( - trader.address().into_alloy(), - to_wei_with_exp(1000, 6).into_alloy(), - ) + .transfer(trader.address(), to_wei_with_exp(1000, 6).into_alloy()) .from(USDC_WHALE_GNOSIS) .into_transaction_request(), ImpersonateConfig { @@ -987,7 +941,7 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { onchain.contracts().allowance.into_alloy(), to_wei_with_exp(1000, 6).into_alloy(), ) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -1010,13 +964,9 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { &onchain.contracts().domain_separator, SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), ); - let sell_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); let buy_token_balance_before = token_wxdai - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -1028,13 +978,9 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { // Drive solution tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let sell_token_balance_after = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_after = token_usdc.balanceOf(trader.address()).call().await.unwrap(); let buy_token_balance_after = token_wxdai - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -1049,18 +995,18 @@ async fn forked_gnosis_single_limit_order_test(web3: Web3) { async fn no_liquidity_limit_order(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10_000)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(10_000)).await; + let [trader_a] = onchain.make_accounts(eth(1)).await; let [token_a, unsupported] = onchain.deploy_tokens(solver.account()).await; // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), eth(10)).await; // Approve GPv2 for trading token_a .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -1136,7 +1082,7 @@ async fn no_liquidity_limit_order(web3: Web3) { let balance_before = onchain .contracts() .weth - .balanceOf(trader_a.address().into_alloy()) + .balanceOf(trader_a.address()) .call() .await .unwrap(); @@ -1180,7 +1126,7 @@ async fn no_liquidity_limit_order(web3: Web3) { let balance_after = onchain .contracts() .weth - .balanceOf(trader_a.address().into_alloy()) + .balanceOf(trader_a.address()) .call() .await .unwrap(); diff --git a/crates/e2e/tests/e2e/liquidity.rs b/crates/e2e/tests/e2e/liquidity.rs index 31942b586d..98f3b775dd 100644 --- a/crates/e2e/tests/e2e/liquidity.rs +++ b/crates/e2e/tests/e2e/liquidity.rs @@ -15,13 +15,13 @@ use { TIMEOUT, TestAccount, colocation, + eth, run_forked_test_with_block_number, - to_wei, to_wei_with_exp, wait_for_condition, }, }, - ethcontract::{Account, H256, prelude::U256}, + ethcontract::{Account, H256}, ethrpc::{ Web3, alloy::{ @@ -58,8 +58,8 @@ async fn forked_node_zero_ex_liquidity_mainnet() { async fn zero_ex_liquidity(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; - let [trader, zeroex_maker] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(eth(1)).await; + let [trader, zeroex_maker] = onchain.make_accounts(eth(1)).await; let token_usdc = ERC20::Instance::new( address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), @@ -83,7 +83,7 @@ async fn zero_ex_liquidity(web3: Web3) { web3.alloy .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(trader.address().into_alloy(), amount) + .transfer(trader.address(), amount) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -103,7 +103,7 @@ async fn zero_ex_liquidity(web3: Web3) { .anvil_send_impersonated_transaction_with_config( token_usdt .transfer( - zeroex_maker.address().into_alloy(), + zeroex_maker.address(), amount * alloy::primitives::U256::from(4), ) .from(USDT_WHALE) @@ -122,7 +122,7 @@ async fn zero_ex_liquidity(web3: Web3) { web3.alloy .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(solver.address().into_alloy(), amount) + .transfer(solver.address(), amount) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -138,20 +138,20 @@ async fn zero_ex_liquidity(web3: Web3) { token_usdc .approve(onchain.contracts().allowance.into_alloy(), amount) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); // With a lower amount 0x contract shows much lower fillable amount token_usdt .approve(*zeroex.address(), amount * alloy::primitives::U256::from(4)) - .from(zeroex_maker.address().into_alloy()) + .from(zeroex_maker.address()) .send_and_watch() .await .unwrap(); token_usdc .approve(*zeroex.address(), amount) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -221,16 +221,8 @@ async fn zero_ex_liquidity(web3: Web3) { .await; // Drive solution - let sell_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_before = token_usdt - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_before = token_usdt.balanceOf(trader.address()).call().await.unwrap(); services.create_order(&order).await.unwrap(); onchain.mint_block().await; @@ -238,7 +230,7 @@ async fn zero_ex_liquidity(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { token_usdc - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .is_ok_and(|balance| balance < sell_token_balance_before) @@ -247,7 +239,7 @@ async fn zero_ex_liquidity(web3: Web3) { .unwrap(); wait_for_condition(TIMEOUT, || async { token_usdt - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .is_ok_and(|balance| balance >= buy_token_balance_before + amount) @@ -274,8 +266,8 @@ async fn zero_ex_liquidity(web3: Web3) { // Fill the remaining part of the 0x order let zeroex_order = Eip712TypedZeroExOrder { - maker_token: token_usdt.address().into_legacy(), - taker_token: token_usdc.address().into_legacy(), + maker_token: *token_usdt.address(), + taker_token: *token_usdc.address(), maker_amount: zeroex_order_amounts.fillable, taker_amount: zeroex_order_amounts.fillable, // doesn't participate in the hash calculation @@ -284,10 +276,10 @@ async fn zero_ex_liquidity(web3: Web3) { maker: zeroex_maker.address(), taker: Default::default(), sender: Default::default(), - fee_recipient: zeroex.address().into_legacy(), - pool: H256::default(), + fee_recipient: *zeroex.address(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), } .to_order_record(chain_id, zeroex.address().into_legacy(), zeroex_maker); fill_or_kill_zeroex_limit_order(&zeroex, &zeroex_order, solver.account().clone()) @@ -314,8 +306,8 @@ fn create_zeroex_liquidity_orders( weth_address: H160, ) -> [shared::zeroex_api::OrderRecord; 3] { let typed_order = Eip712TypedZeroExOrder { - maker_token: order_creation.buy_token, - taker_token: order_creation.sell_token, + maker_token: order_creation.buy_token.into_alloy(), + taker_token: order_creation.sell_token.into_alloy(), // fully covers execution costs maker_amount: order_creation.buy_amount.as_u128() * 3, taker_amount: order_creation.sell_amount.as_u128() * 2, @@ -327,14 +319,14 @@ fn create_zeroex_liquidity_orders( // Makes it possible for anyone to fill the order taker: Default::default(), sender: Default::default(), - fee_recipient: zeroex_addr, - pool: H256::default(), + fee_recipient: zeroex_addr.into_alloy(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), }; let usdt_weth_order = Eip712TypedZeroExOrder { - maker_token: weth_address, - taker_token: order_creation.buy_token, + maker_token: weth_address.into_alloy(), + taker_token: order_creation.buy_token.into_alloy(), // the value comes from the `--amount-to-estimate-prices-with` config to provide // sufficient liquidity maker_amount: 1_000_000_000_000_000_000u128, @@ -344,14 +336,14 @@ fn create_zeroex_liquidity_orders( maker: zeroex_maker.address(), taker: Default::default(), sender: Default::default(), - fee_recipient: zeroex_addr, - pool: H256::default(), + fee_recipient: zeroex_addr.into_alloy(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), }; let usdc_weth_order = Eip712TypedZeroExOrder { - maker_token: weth_address, - taker_token: order_creation.sell_token, + maker_token: weth_address.into_alloy(), + taker_token: order_creation.sell_token.into_alloy(), // the value comes from the `--amount-to-estimate-prices-with` config to provide // sufficient liquidity maker_amount: 1_000_000_000_000_000_000u128, @@ -361,10 +353,10 @@ fn create_zeroex_liquidity_orders( maker: zeroex_maker.address(), taker: Default::default(), sender: Default::default(), - fee_recipient: zeroex_addr, - pool: H256::default(), + fee_recipient: zeroex_addr.into_alloy(), + pool: Default::default(), expiry: NaiveDateTime::MAX.and_utc().timestamp() as u64, - salt: U256::from(Utc::now().timestamp()), + salt: alloy::primitives::U256::from(Utc::now().timestamp()), }; [typed_order, usdt_weth_order, usdc_weth_order] .map(|order| order.to_order_record(chain_id, zeroex_addr, zeroex_maker.clone())) diff --git a/crates/e2e/tests/e2e/liquidity_source_notification.rs b/crates/e2e/tests/e2e/liquidity_source_notification.rs index 5575a180b4..6fa29f60a6 100644 --- a/crates/e2e/tests/e2e/liquidity_source_notification.rs +++ b/crates/e2e/tests/e2e/liquidity_source_notification.rs @@ -14,6 +14,7 @@ use { Services, TIMEOUT, colocation::{self, SolverEngine}, + eth, mock::Mock, run_forked_test_with_block_number, to_wei, @@ -65,11 +66,11 @@ async fn liquidity_source_notification(web3: Web3) { // Create parties accounts // solver - represents both baseline solver engine for quoting and liquorice // solver engine for solving - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(eth(1)).await; // trader - the account that will place CoW order // liquorice_maker - the account that will place Liquorice order to fill CoW // order with - let [trader, liquorice_maker] = onchain.make_accounts(to_wei(1)).await; + let [trader, liquorice_maker] = onchain.make_accounts(eth(1)).await; // Access trade tokens contracts let token_usdc = ERC20::Instance::new( @@ -87,7 +88,7 @@ async fn liquidity_source_notification(web3: Web3) { web3.alloy .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(trader.address().into_alloy(), trade_amount.into_alloy()) + .transfer(trader.address(), trade_amount.into_alloy()) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -105,7 +106,7 @@ async fn liquidity_source_notification(web3: Web3) { web3.alloy .anvil_send_impersonated_transaction_with_config( token_usdc - .transfer(solver.address().into_alloy(), trade_amount.into_alloy()) + .transfer(solver.address(), trade_amount.into_alloy()) .from(USDC_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -125,7 +126,7 @@ async fn liquidity_source_notification(web3: Web3) { onchain.contracts().allowance.into_alloy(), alloy::primitives::U256::MAX, ) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -149,10 +150,7 @@ async fn liquidity_source_notification(web3: Web3) { web3.alloy .anvil_send_impersonated_transaction_with_config( token_usdt - .transfer( - liquorice_maker.address().into_alloy(), - trade_amount.into_alloy(), - ) + .transfer(liquorice_maker.address(), trade_amount.into_alloy()) .from(USDT_WHALE) .into_transaction_request(), ImpersonateConfig { @@ -172,7 +170,7 @@ async fn liquidity_source_notification(web3: Web3) { liquorice_balance_manager_address.into_alloy(), alloy::primitives::U256::MAX, ) - .from(liquorice_maker.address().into_alloy()) + .from(liquorice_maker.address()) .send_and_watch() .await .unwrap(); @@ -269,7 +267,7 @@ http-timeout = "10s" quoteTokenAmount: trade_amount.into_alloy(), minFillAmount: U256::from(1), quoteExpiry: U256::from(Utc::now().timestamp() as u64 + 10), - recipient: liquorice_maker.address().into_alloy(), + recipient: liquorice_maker.address(), }; // Create calldata @@ -287,7 +285,7 @@ http-timeout = "10s" // Create Liquorice settlement calldata liquorice_settlement .settleSingle( - liquorice_maker.address().into_alloy(), + liquorice_maker.address(), liquorice_order.clone(), LiquoriceSettlement::Signature::TypedSignature { signatureType: 3, // EIP712 diff --git a/crates/e2e/tests/e2e/order_cancellation.rs b/crates/e2e/tests/e2e/order_cancellation.rs index 9b00fb1e43..774c12d59b 100644 --- a/crates/e2e/tests/e2e/order_cancellation.rs +++ b/crates/e2e/tests/e2e/order_cancellation.rs @@ -1,7 +1,11 @@ use { + ::alloy::primitives::U256 as AlloyU256, database::order_events::OrderEventLabel, e2e::setup::{eth, *}, - ethrpc::alloy::{CallBuilderExt, conversions::IntoAlloy}, + ethrpc::alloy::{ + CallBuilderExt, + conversions::{IntoAlloy, IntoLegacy}, + }, model::{ order::{ CancellationPayload, @@ -32,19 +36,19 @@ async fn local_node_order_cancellation() { async fn order_cancellation(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token.mint(trader.address(), to_wei(10)).await; + token.mint(trader.address(), eth(10)).await; // Approve GPv2 for trading token .approve(onchain.contracts().allowance.into_alloy(), eth(10)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -89,7 +93,7 @@ async fn order_cancellation(web3: Web3) { let trader = &trader; let request = OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *token.address(), buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { @@ -107,11 +111,12 @@ async fn order_cancellation(web3: Web3) { let order = OrderCreation { kind: quote.kind, - sell_token: quote.sell_token, - sell_amount: quote.sell_amount, + sell_token: quote.sell_token.into_legacy(), + sell_amount: quote.sell_amount.into_legacy(), fee_amount: 0.into(), - buy_token: quote.buy_token, - buy_amount: (quote.buy_amount * 99) / 100, + buy_token: quote.buy_token.into_legacy(), + buy_amount: ((quote.buy_amount * AlloyU256::from(99)) / AlloyU256::from(100)) + .into_legacy(), valid_to: quote.valid_to, app_data: quote.app_data, ..Default::default() diff --git a/crates/e2e/tests/e2e/partial_fill.rs b/crates/e2e/tests/e2e/partial_fill.rs index 5779dce5df..81f017ac51 100644 --- a/crates/e2e/tests/e2e/partial_fill.rs +++ b/crates/e2e/tests/e2e/partial_fill.rs @@ -25,8 +25,8 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; // Use a shallow pool to make partial fills easier to setup. let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(10), to_wei(10)) @@ -36,7 +36,7 @@ async fn test(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(4)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -44,7 +44,7 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(4)) .send_and_watch() .await @@ -55,11 +55,7 @@ async fn test(web3: Web3) { services.start_protocol(solver.clone()).await; tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { sell_token: onchain.contracts().weth.address().into_legacy(), @@ -83,12 +79,12 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); let trade_happened = || async { - token - .balanceOf(trader.address().into_alloy()) + !token + .balanceOf(trader.address()) .call() .await .unwrap() - != U256::ZERO + .is_zero() }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); @@ -96,7 +92,7 @@ async fn test(web3: Web3) { let sell_balance = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -105,11 +101,7 @@ async fn test(web3: Web3) { (1_999_000_000_000_000_000_u128..2_000_000_000_000_000_000_u128) .contains(&u128::try_from(sell_balance).unwrap()) ); - let buy_balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let buy_balance = token.balanceOf(trader.address()).call().await.unwrap(); assert!( (1_650_000_000_000_000_000_u128..1_670_000_000_000_000_000_u128) .contains(&u128::try_from(buy_balance).unwrap()) diff --git a/crates/e2e/tests/e2e/partially_fillable_balance.rs b/crates/e2e/tests/e2e/partially_fillable_balance.rs index f8148a3b69..4d548d8a5a 100644 --- a/crates/e2e/tests/e2e/partially_fillable_balance.rs +++ b/crates/e2e/tests/e2e/partially_fillable_balance.rs @@ -23,35 +23,35 @@ async fn local_node_partially_fillable_balance() { async fn test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader_a] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(10_000), to_wei(10_000)) .await; - token_a.mint(trader_a.address(), to_wei(50)).await; - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(trader_a.address(), eth(50)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -65,17 +65,17 @@ async fn test(web3: Web3) { eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(onchain.contracts().allowance.into_alloy(), eth(500)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -106,11 +106,7 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); !balance.is_zero() }) .await @@ -118,18 +114,10 @@ async fn test(web3: Web3) { // Expecting a partial fill because order sells 100 but user only has balance of // 50. - let sell_balance = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_balance = token_a.balanceOf(trader_a.address()).call().await.unwrap(); // Depending on how the solver works might not have sold all balance. assert!(U256::ZERO <= sell_balance && sell_balance < U256::from(10u64.pow(18))); - let buy_balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let buy_balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); // We don't know exact buy balance because of the fee. assert!( U256::from(45) * U256::from(10u64.pow(18)) <= buy_balance diff --git a/crates/e2e/tests/e2e/partially_fillable_pool.rs b/crates/e2e/tests/e2e/partially_fillable_pool.rs index 6d39aee755..db8f925b49 100644 --- a/crates/e2e/tests/e2e/partially_fillable_pool.rs +++ b/crates/e2e/tests/e2e/partially_fillable_pool.rs @@ -22,35 +22,35 @@ async fn local_node_partially_fillable_pool() { async fn test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader_a] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token_a.mint(trader_a.address(), to_wei(500)).await; - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(trader_a.address(), eth(500)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -64,17 +64,17 @@ async fn test(web3: Web3) { eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(onchain.contracts().allowance.into_alloy(), eth(500)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -105,11 +105,7 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); onchain.mint_block().await; !balance.is_zero() }) @@ -117,21 +113,13 @@ async fn test(web3: Web3) { .unwrap(); // Expecting a partial fill because the pool cannot trade the full amount. - let sell_balance = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_balance = token_a.balanceOf(trader_a.address()).call().await.unwrap(); assert!( // Sell balance is strictly less than 250.0 because of the fee. (249_999_000_000_000_000_000_u128..250_000_000_000_000_000_000_u128) .contains(&u128::try_from(sell_balance).unwrap()) ); - let buy_balance = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let buy_balance = token_b.balanceOf(trader_a.address()).call().await.unwrap(); assert!( (199_000_000_000_000_000_000_u128..201_000_000_000_000_000_000_u128) .contains(&u128::try_from(buy_balance).unwrap()) diff --git a/crates/e2e/tests/e2e/place_order_with_quote.rs b/crates/e2e/tests/e2e/place_order_with_quote.rs index 423fdb4e5d..cc89a975d9 100644 --- a/crates/e2e/tests/e2e/place_order_with_quote.rs +++ b/crates/e2e/tests/e2e/place_order_with_quote.rs @@ -26,8 +26,8 @@ async fn local_node_test() { async fn place_order_with_quote(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -36,7 +36,7 @@ async fn place_order_with_quote(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -44,7 +44,7 @@ async fn place_order_with_quote(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(3)) .send_and_watch() .await @@ -63,7 +63,7 @@ async fn place_order_with_quote(web3: Web3) { tracing::info!("Quoting"); let quote_sell_amount = to_wei(1); let quote_request = OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *onchain.contracts().weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -84,18 +84,14 @@ async fn place_order_with_quote(web3: Web3) { tracing::debug!(?quote_metadata); tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { quote_id: quote_response.id, sell_token: onchain.contracts().weth.address().into_legacy(), sell_amount: quote_sell_amount, buy_token: token.address().into_legacy(), - buy_amount: quote_response.quote.buy_amount, + buy_amount: quote_response.quote.buy_amount.into_legacy(), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() diff --git a/crates/e2e/tests/e2e/protocol_fee.rs b/crates/e2e/tests/e2e/protocol_fee.rs index 2139f5bc85..180345274a 100644 --- a/crates/e2e/tests/e2e/protocol_fee.rs +++ b/crates/e2e/tests/e2e/protocol_fee.rs @@ -1,4 +1,5 @@ use { + ::alloy::primitives::U256 as AlloyU256, driver::domain::eth::NonZeroU256, e2e::{ assert_approximately_eq, @@ -82,8 +83,8 @@ async fn combined_protocol_fees(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(200)).await; - let [trader] = onchain.make_accounts(to_wei(200)).await; + let [solver] = onchain.make_solvers(eth(200)).await; + let [trader] = onchain.make_accounts(eth(200)).await; let [ limit_order_token, market_order_token, @@ -97,18 +98,18 @@ async fn combined_protocol_fees(web3: Web3) { &market_order_token, &partner_fee_order_token, ] { - token.mint(solver.address(), to_wei(1000)).await; + token.mint(solver.address(), eth(1000)).await; token .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token .approve(*onchain.contracts().uniswap_v2_router.address(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -118,7 +119,7 @@ async fn combined_protocol_fees(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -126,7 +127,7 @@ async fn combined_protocol_fees(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(100)) .send_and_watch() .await @@ -135,7 +136,7 @@ async fn combined_protocol_fees(web3: Web3) { .contracts() .weth .approve(*onchain.contracts().uniswap_v2_router.address(), eth(200)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -189,7 +190,9 @@ async fn combined_protocol_fees(web3: Web3) { let market_price_improvement_order = OrderCreation { sell_amount, // to make sure the order is in-market - buy_amount: market_quote_before.quote.buy_amount * 2 / 3, + buy_amount: (market_quote_before.quote.buy_amount * AlloyU256::from(2) + / AlloyU256::from(3)) + .into_legacy(), ..sell_order_from_quote(&market_quote_before) } .sign( @@ -200,7 +203,8 @@ async fn combined_protocol_fees(web3: Web3) { let limit_surplus_order = OrderCreation { sell_amount, // to make sure the order is out-of-market - buy_amount: limit_quote_before.quote.buy_amount * 3 / 2, + buy_amount: (limit_quote_before.quote.buy_amount * AlloyU256::from(3) / AlloyU256::from(2)) + .into_legacy(), ..sell_order_from_quote(&limit_quote_before) } .sign( @@ -211,7 +215,8 @@ async fn combined_protocol_fees(web3: Web3) { let partner_fee_order = OrderCreation { sell_amount, // to make sure the order is out-of-market - buy_amount: partner_fee_quote.quote.buy_amount * 3 / 2, + buy_amount: (partner_fee_quote.quote.buy_amount * AlloyU256::from(3) / AlloyU256::from(2)) + .into_legacy(), app_data: partner_fee_app_data.clone(), ..sell_order_from_quote(&partner_fee_quote) } @@ -223,13 +228,13 @@ async fn combined_protocol_fees(web3: Web3) { tracing::info!("Rebalancing AMM pools for market & limit order."); onchain - .mint_token_to_weth_uni_v2_pool(&market_order_token, to_wei(1000)) + .mint_token_to_weth_uni_v2_pool(&market_order_token, eth(1000)) .await; onchain - .mint_token_to_weth_uni_v2_pool(&limit_order_token, to_wei(1000)) + .mint_token_to_weth_uni_v2_pool(&limit_order_token, eth(1000)) .await; onchain - .mint_token_to_weth_uni_v2_pool(&partner_fee_order_token, to_wei(1000)) + .mint_token_to_weth_uni_v2_pool(&partner_fee_order_token, eth(1000)) .await; tracing::info!("Waiting for liquidity state to update"); @@ -249,7 +254,8 @@ async fn combined_protocol_fees(web3: Web3) { // Only proceed with test once the quote changes significantly (2x) to avoid // progressing due to tiny fluctuations in gas price which would lead to // errors down the line. - new_market_order_quote.quote.buy_amount > market_quote_before.quote.buy_amount * 2 + new_market_order_quote.quote.buy_amount + > market_quote_before.quote.buy_amount * AlloyU256::from(2) }) .await .expect("Timeout waiting for eviction of the cached liquidity"); @@ -335,21 +341,28 @@ async fn combined_protocol_fees(web3: Web3) { .buy_amount .saturating_sub(market_quote_before.quote.buy_amount); // see `market_price_improvement_policy.factor`, which is 0.3 - assert!(market_executed_fee_in_buy_token >= market_quote_diff * 3 / 10); + assert!( + market_executed_fee_in_buy_token.into_alloy() + >= (market_quote_diff * AlloyU256::from(3) / AlloyU256::from(10)) + ); let partner_fee_order = services.get_order(&partner_fee_order_uid).await.unwrap(); let partner_fee_executed_fee_in_buy_token = fee_in_buy_token(&partner_fee_order, &partner_fee_quote_after.quote); assert!( // see `--fee-policy-max-partner-fee` autopilot config argument, which is 0.02 - partner_fee_executed_fee_in_buy_token >= partner_fee_quote.quote.buy_amount * 2 / 100 + partner_fee_executed_fee_in_buy_token.into_alloy() + >= (partner_fee_quote.quote.buy_amount * AlloyU256::from(2) / AlloyU256::from(100)) ); let limit_quote_diff = partner_fee_quote_after .quote .buy_amount - .saturating_sub(partner_fee_order.data.buy_amount.into_legacy()); + .saturating_sub(partner_fee_order.data.buy_amount); // see `limit_surplus_policy.factor`, which is 0.3 - assert!(partner_fee_executed_fee_in_buy_token >= limit_quote_diff * 3 / 10); + assert!( + partner_fee_executed_fee_in_buy_token.into_alloy() + >= (limit_quote_diff * AlloyU256::from(3) / AlloyU256::from(10)) + ); let limit_surplus_order = services.get_order(&limit_surplus_order_uid).await.unwrap(); let limit_executed_fee_in_buy_token = @@ -357,9 +370,12 @@ async fn combined_protocol_fees(web3: Web3) { let limit_quote_diff = limit_quote_after .quote .buy_amount - .saturating_sub(limit_surplus_order.data.buy_amount.into_legacy()); + .saturating_sub(limit_surplus_order.data.buy_amount); // see `limit_surplus_policy.factor`, which is 0.3 - assert!(limit_executed_fee_in_buy_token >= limit_quote_diff * 3 / 10); + assert!( + limit_executed_fee_in_buy_token.into_alloy() + >= (limit_quote_diff * AlloyU256::from(3) / AlloyU256::from(10)) + ); let [ market_order_token_balance, @@ -438,24 +454,24 @@ async fn surplus_partner_fee(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(200)).await; - let [trader] = onchain.make_accounts(to_wei(200)).await; + let [solver] = onchain.make_solvers(eth(200)).await; + let [trader] = onchain.make_accounts(eth(200)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(20), to_wei(20)) .await; - token.mint(solver.address(), to_wei(1000)).await; + token.mint(solver.address(), eth(1000)).await; token .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token .approve(*onchain.contracts().uniswap_v2_router.address(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -463,7 +479,7 @@ async fn surplus_partner_fee(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -471,7 +487,7 @@ async fn surplus_partner_fee(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(100)) .send_and_watch() .await @@ -480,7 +496,7 @@ async fn surplus_partner_fee(web3: Web3) { .contracts() .weth .approve(*onchain.contracts().uniswap_v2_router.address(), eth(200)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -616,15 +632,15 @@ async fn get_quote( } fn fee_in_buy_token(order: &Order, quote: &OrderQuote) -> U256 { - order.metadata.executed_fee * quote.buy_amount / quote.sell_amount + (order.metadata.executed_fee.into_alloy() * quote.buy_amount / quote.sell_amount).into_legacy() } fn sell_order_from_quote(quote: &OrderQuoteResponse) -> OrderCreation { OrderCreation { - sell_token: quote.quote.sell_token, - sell_amount: quote.quote.sell_amount, - buy_token: quote.quote.buy_token, - buy_amount: quote.quote.buy_amount, + sell_token: quote.quote.sell_token.into_legacy(), + sell_amount: quote.quote.sell_amount.into_legacy(), + buy_token: quote.quote.buy_token.into_legacy(), + buy_amount: quote.quote.buy_amount.into_legacy(), valid_to: quote.quote.valid_to, kind: OrderKind::Sell, quote_id: quote.id, @@ -660,37 +676,37 @@ async fn volume_fee_buy_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_gno, token_dai] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1000)) .await; // Fund trader accounts - token_gno.mint(trader.address(), to_wei(100)).await; + token_gno.mint(trader.address(), eth(100)).await; // Create and fund Uniswap pool - token_gno.mint(solver.address(), to_wei(1000)).await; - token_dai.mint(solver.address(), to_wei(1000)).await; + token_gno.mint(solver.address(), eth(1000)).await; + token_dai.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_gno.address(), *token_dai.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_gno .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_dai .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -704,10 +720,10 @@ async fn volume_fee_buy_order_test(web3: Web3) { eth(1000), ::alloy::primitives::U256::ZERO, ::alloy::primitives::U256::ZERO, - solver.address().into_alloy(), + solver.address(), ::alloy::primitives::U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -716,7 +732,7 @@ async fn volume_fee_buy_order_test(web3: Web3) { token_gno .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -747,7 +763,7 @@ async fn volume_fee_buy_order_test(web3: Web3) { let order = OrderCreation { sell_token: token_gno.address().into_legacy(), - sell_amount: quote.sell_amount * 3 / 2, + sell_amount: (quote.sell_amount * AlloyU256::from(3) / AlloyU256::from(2)).into_legacy(), buy_token: token_dai.address().into_legacy(), buy_amount: to_wei(5), valid_to: model::time::now_in_epoch_seconds() + 300, @@ -772,7 +788,10 @@ async fn volume_fee_buy_order_test(web3: Web3) { let order = services.get_order(&uid).await.unwrap(); let fee_in_buy_token = quote.fee_amount * quote.buy_amount / quote.sell_amount; - assert!(order.metadata.executed_fee >= fee_in_buy_token + quote.sell_amount / 10); + assert!( + order.metadata.executed_fee.into_alloy() + >= fee_in_buy_token + (quote.sell_amount / AlloyU256::from(10)) + ); // Check settlement contract balance let balance_after = token_gno @@ -812,37 +831,37 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_gno, token_dai] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1000)) .await; // Fund trader accounts - token_gno.mint(trader.address(), to_wei(100)).await; + token_gno.mint(trader.address(), eth(100)).await; // Create and fund Uniswap pool - token_gno.mint(solver.address(), to_wei(1000)).await; - token_dai.mint(solver.address(), to_wei(1000)).await; + token_gno.mint(solver.address(), eth(1000)).await; + token_dai.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_gno.address(), *token_dai.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_gno .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_dai .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -856,10 +875,10 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { eth(1000), ::alloy::primitives::U256::ZERO, ::alloy::primitives::U256::ZERO, - solver.address().into_alloy(), + solver.address(), ::alloy::primitives::U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -868,7 +887,7 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { token_gno .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -899,7 +918,7 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { let order = OrderCreation { sell_token: token_gno.address().into_legacy(), - sell_amount: quote.sell_amount * 3 / 2, + sell_amount: (quote.sell_amount * AlloyU256::from(3) / AlloyU256::from(2)).into_legacy(), buy_token: token_dai.address().into_legacy(), buy_amount: to_wei(5), valid_to: model::time::now_in_epoch_seconds() + 300, @@ -924,7 +943,10 @@ async fn volume_fee_buy_order_upcoming_future_test(web3: Web3) { let order = services.get_order(&uid).await.unwrap(); let fee_in_buy_token = quote.fee_amount * quote.buy_amount / quote.sell_amount; - assert!(order.metadata.executed_fee >= fee_in_buy_token + quote.sell_amount / 10); + assert!( + order.metadata.executed_fee.into_alloy() + >= fee_in_buy_token + (quote.sell_amount / AlloyU256::from(10)) + ); // Check settlement contract balance let balance_after = token_gno diff --git a/crates/e2e/tests/e2e/quote_verification.rs b/crates/e2e/tests/e2e/quote_verification.rs index b1e2585f35..c67e307270 100644 --- a/crates/e2e/tests/e2e/quote_verification.rs +++ b/crates/e2e/tests/e2e/quote_verification.rs @@ -86,17 +86,17 @@ async fn standard_verified_quote(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token.mint(trader.address(), to_wei(1)).await; + token.mint(trader.address(), eth(1)).await; token .approve(onchain.contracts().allowance.into_alloy(), eth(1)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -108,7 +108,7 @@ async fn standard_verified_quote(web3: Web3) { // quote where the trader has sufficient balance and an approval set. let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *token.address(), buy_token: *onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { @@ -174,9 +174,8 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { in_amount: NonZeroU256::new(12.into()).unwrap(), }, &Verification { - from: H160::from_str("0x73688c2b34bf6c09c125fed02fe92d17a94b897a").unwrap().into_alloy(), - receiver: H160::from_str("0x73688c2b34bf6c09c125fed02fe92d17a94b897a") - .unwrap().into_alloy(), + from: address!("0x73688c2b34bf6c09c125fed02fe92d17a94b897a"), + receiver: address!("0x73688c2b34bf6c09c125fed02fe92d17a94b897a"), pre_interactions: vec![], post_interactions: vec![], sell_token_source: SellTokenSource::Erc20, @@ -237,8 +236,8 @@ async fn verified_quote_eth_balance(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -251,25 +250,22 @@ async fn verified_quote_eth_balance(web3: Web3) { // quote where the trader has no WETH balances or approval set, but // sufficient ETH for the trade assert!( - weth.balanceOf(trader.address().into_alloy()) + weth.balanceOf(trader.address()) .call() .await .unwrap() .is_zero() ); assert!( - weth.allowance( - trader.address().into_alloy(), - onchain.contracts().allowance.into_alloy() - ) - .call() - .await - .unwrap() - .is_zero() + weth.allowance(trader.address(), onchain.contracts().allowance.into_alloy()) + .call() + .await + .unwrap() + .is_zero() ); let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -290,8 +286,8 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(3)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(3)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -299,10 +295,7 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // Send 3 ETH to the settlement contract so we can get verified quotes for // selling WETH. onchain - .send_wei( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(3), - ) + .send_wei(*onchain.contracts().gp_settlement.address(), eth(3)) .await; tracing::info!("Starting services."); @@ -346,7 +339,7 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { let response = services .submit_quote(&OrderQuoteRequest { from: *onchain.contracts().gp_settlement.address(), - receiver: Some(trader.address().into_alloy()), + receiver: Some(trader.address()), ..request.clone() }) .await @@ -356,7 +349,7 @@ async fn verified_quote_for_settlement_contract(web3: Web3) { // quote where a random trader sends funds to the settlement contract let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), receiver: Some(*onchain.contracts().gp_settlement.address()), ..request.clone() }) @@ -371,8 +364,8 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(0)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(0)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -400,16 +393,9 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // quote where the trader has no balances or approval set from TOKEN->WETH assert_eq!( ( + token.balanceOf(trader.address()).call().await.unwrap(), token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(), - token - .allowance( - trader.address().into_alloy(), - onchain.contracts().allowance.into_alloy() - ) + .allowance(trader.address(), onchain.contracts().allowance.into_alloy()) .call() .await .unwrap(), @@ -421,7 +407,7 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { ); let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *token.address(), buy_token: *weth.address(), side: OrderQuoteSide::Sell { @@ -440,31 +426,28 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { onchain .web3() .eth() - .balance(trader.address(), None) + .balance(trader.address().into_legacy(), None) .await .unwrap() .is_zero() ); assert!( - weth.balanceOf(trader.address().into_alloy()) + weth.balanceOf(trader.address()) .call() .await .unwrap() .is_zero() ); assert!( - weth.allowance( - trader.address().into_alloy(), - onchain.contracts().allowance.into_alloy() - ) - .call() - .await - .unwrap() - .is_zero() + weth.allowance(trader.address(), onchain.contracts().allowance.into_alloy()) + .call() + .await + .unwrap() + .is_zero() ); let response = services .submit_quote(&OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -482,7 +465,7 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // which is used when no wallet is connected in the frontend let response = services .submit_quote(&OrderQuoteRequest { - from: H160::zero().into_alloy(), + from: Address::ZERO, sell_token: *weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -500,7 +483,7 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { // if the user provided pre-interactions. This works now. let response = services .submit_quote(&OrderQuoteRequest { - from: H160::zero().into_alloy(), + from: Address::ZERO, sell_token: *weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -536,7 +519,7 @@ async fn verified_quote_with_simulated_balance(web3: Web3) { async fn usdt_quote_verification(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; + let [solver] = onchain.make_solvers_forked(eth(1)).await; let usdc = address!("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"); let usdt = address!("dac17f958d2ee523a2206206994597c13d831ec7"); diff --git a/crates/e2e/tests/e2e/quoting.rs b/crates/e2e/tests/e2e/quoting.rs index e81176f27c..84ebc3776a 100644 --- a/crates/e2e/tests/e2e/quoting.rs +++ b/crates/e2e/tests/e2e/quoting.rs @@ -52,8 +52,8 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -62,7 +62,7 @@ async fn test(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -70,7 +70,7 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(3)) .send_and_watch() .await @@ -91,7 +91,7 @@ async fn test(web3: Web3) { tracing::info!("Quoting order"); let request = OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *onchain.contracts().weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -200,8 +200,8 @@ async fn uses_stale_liquidity(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(2)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -210,7 +210,7 @@ async fn uses_stale_liquidity(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(1)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -218,7 +218,7 @@ async fn uses_stale_liquidity(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(1)) .send_and_watch() .await @@ -229,7 +229,7 @@ async fn uses_stale_liquidity(web3: Web3) { services.start_protocol(solver).await; let quote = OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *onchain.contracts().weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -246,7 +246,7 @@ async fn uses_stale_liquidity(web3: Web3) { // Now, we want to manually unbalance the pools and assert that the quote // doesn't change (as the price estimation will use stale pricing data). onchain - .mint_token_to_weth_uni_v2_pool(&token, to_wei(1_000)) + .mint_token_to_weth_uni_v2_pool(&token, eth(1_000)) .await; tracing::info!("performining second quote, which should match first"); @@ -272,8 +272,8 @@ async fn quote_timeout(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(2)).await; let [sell_token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -330,7 +330,7 @@ async fn quote_timeout(web3: Web3) { })); let quote_request = |timeout| OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *onchain.contracts().weth.address(), buy_token: *sell_token.address(), side: OrderQuoteSide::Sell { @@ -385,11 +385,11 @@ async fn quote_timeout(web3: Web3) { assert_within_variance(start, MAX_QUOTE_TIME_MS); // set up trader to pass balance checks during order creation - sell_token.mint(trader.address(), to_wei(1)).await; + sell_token.mint(trader.address(), eth(1)).await; sell_token .approve(onchain.contracts().allowance.into_alloy(), eth(1)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -423,8 +423,8 @@ async fn quote_timeout(web3: Web3) { async fn volume_fee(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -433,7 +433,7 @@ async fn volume_fee(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -441,7 +441,7 @@ async fn volume_fee(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(3)) .send_and_watch() .await @@ -462,7 +462,7 @@ async fn volume_fee(web3: Web3) { tracing::info!("Testing SELL quote with volume fee"); let sell_request = OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *onchain.contracts().weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Sell { @@ -481,7 +481,7 @@ async fn volume_fee(web3: Web3) { tracing::info!("Testing BUY quote with volume fee"); let buy_request = OrderQuoteRequest { - from: trader.address().into_alloy(), + from: trader.address(), sell_token: *onchain.contracts().weth.address(), buy_token: *token.address(), side: OrderQuoteSide::Buy { diff --git a/crates/e2e/tests/e2e/refunder.rs b/crates/e2e/tests/e2e/refunder.rs index 29d6346baf..98de58b547 100644 --- a/crates/e2e/tests/e2e/refunder.rs +++ b/crates/e2e/tests/e2e/refunder.rs @@ -6,7 +6,7 @@ use { ethcontract::U256, ethrpc::{ Web3, - alloy::conversions::{IntoAlloy, TryIntoAlloyAsync}, + alloy::conversions::TryIntoAlloyAsync, block_stream::timestamp_of_current_block_in_seconds, }, model::quote::{OrderQuoteRequest, OrderQuoteSide, QuoteSigningScheme, Validity}, @@ -24,8 +24,8 @@ async fn local_node_refunder_tx() { async fn refunder_tx(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [user, refunder] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [user, refunder] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -93,10 +93,10 @@ async fn refunder_tx(web3: Web3) { ExtendedEthFlowOrder::from_quote("e_response, valid_to).include_slippage_bps(9999); ethflow_order - .mine_order_creation(user.address().into_alloy(), ethflow_contract) + .mine_order_creation(user.address(), ethflow_contract) .await; ethflow_order_2 - .mine_order_creation(user.address().into_alloy(), ethflow_contract_2) + .mine_order_creation(user.address(), ethflow_contract_2) .await; let order_id = ethflow_order diff --git a/crates/e2e/tests/e2e/replace_order.rs b/crates/e2e/tests/e2e/replace_order.rs index 979e532ce2..719b551c32 100644 --- a/crates/e2e/tests/e2e/replace_order.rs +++ b/crates/e2e/tests/e2e/replace_order.rs @@ -44,37 +44,37 @@ async fn local_node_try_replace_executed_order() { async fn try_replace_unreplaceable_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts - token_a.mint(trader.address(), to_wei(30)).await; + token_a.mint(trader.address(), eth(30)).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -88,10 +88,10 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -100,7 +100,7 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { token_a .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -129,11 +129,7 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { &onchain.contracts().domain_separator, SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), ); - let balance_before = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_a.balanceOf(trader.address()).call().await.unwrap(); onchain.mint_block().await; let order_id = services.create_order(&order).await.unwrap(); @@ -193,11 +189,7 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { tracing::info!("Waiting for the old order to be executed"); wait_for_condition(TIMEOUT, || async { - let balance_after = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = token_a.balanceOf(trader.address()).call().await.unwrap(); balance_before.saturating_sub(balance_after) == eth(10) && !services.get_trades(&order_id).await.unwrap().is_empty() }) @@ -224,38 +216,38 @@ async fn try_replace_unreplaceable_order_test(web3: Web3) { async fn try_replace_someone_else_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader_a, trader_b] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(30)).await; - token_a.mint(trader_b.address(), to_wei(30)).await; + token_a.mint(trader_a.address(), eth(30)).await; + token_a.mint(trader_b.address(), eth(30)).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -269,10 +261,10 @@ async fn try_replace_someone_else_order_test(web3: Web3) { eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -281,14 +273,14 @@ async fn try_replace_someone_else_order_test(web3: Web3) { token_a .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_a .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -337,11 +329,7 @@ async fn try_replace_someone_else_order_test(web3: Web3) { &onchain.contracts().domain_separator, SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()), ); - let balance_before = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_a.balanceOf(trader_a.address()).call().await.unwrap(); let response = services.create_order(&new_order).await; let (error_code, _) = response.err().unwrap(); assert_eq!(error_code, StatusCode::UNAUTHORIZED); @@ -350,11 +338,7 @@ async fn try_replace_someone_else_order_test(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { onchain.mint_block().await; - let balance_after = token_a - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = token_a.balanceOf(trader_a.address()).call().await.unwrap(); balance_before.saturating_sub(balance_after) == eth(10) }) .await @@ -364,37 +348,37 @@ async fn try_replace_someone_else_order_test(web3: Web3) { async fn single_replace_order_test(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts - token_a.mint(trader.address(), to_wei(30)).await; + token_a.mint(trader.address(), eth(30)).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -408,10 +392,10 @@ async fn single_replace_order_test(web3: Web3) { eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -420,7 +404,7 @@ async fn single_replace_order_test(web3: Web3) { token_a .approve(onchain.contracts().allowance.into_alloy(), eth(15)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -443,11 +427,7 @@ async fn single_replace_order_test(web3: Web3) { ) .await; - let balance_before = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_a.balanceOf(trader.address()).call().await.unwrap(); let order = OrderCreation { sell_token: token_a.address().into_legacy(), sell_amount: to_wei(10), @@ -526,11 +506,7 @@ async fn single_replace_order_test(web3: Web3) { // Drive solution to verify that new order can be settled tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after = token_a - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = token_a.balanceOf(trader.address()).call().await.unwrap(); onchain.mint_block().await; balance_before.saturating_sub(balance_after) == eth(3) }) diff --git a/crates/e2e/tests/e2e/smart_contract_orders.rs b/crates/e2e/tests/e2e/smart_contract_orders.rs index eb17c02e2e..0e238e7575 100644 --- a/crates/e2e/tests/e2e/smart_contract_orders.rs +++ b/crates/e2e/tests/e2e/smart_contract_orders.rs @@ -28,15 +28,15 @@ async fn local_node_max_gas_limit() { async fn smart_contract_orders(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let safe = Safe::deploy(trader, web3.alloy.clone()).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(100_000), to_wei(100_000)) .await; - token.mint(safe.address().into_legacy(), to_wei(10)).await; + token.mint(safe.address(), eth(10)).await; // Approve GPv2 for trading safe.exec_alloy_call( @@ -156,7 +156,7 @@ async fn smart_contract_orders(web3: Web3) { async fn erc1271_gas_limit(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; let trader = contracts::alloy::test::GasHog::Instance::deploy(web3.alloy.clone()) .await .unwrap(); @@ -166,14 +166,14 @@ async fn erc1271_gas_limit(web3: Web3) { .await; // Fund trader accounts and approve relayer - cow.fund(trader.address().into_legacy(), to_wei(5)).await; + cow.fund(*trader.address(), eth(5)).await; trader .approve( *cow.address(), onchain.contracts().allowance.into_alloy(), eth(10), ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); diff --git a/crates/e2e/tests/e2e/solver_competition.rs b/crates/e2e/tests/e2e/solver_competition.rs index 85dcbcd069..351862cd39 100644 --- a/crates/e2e/tests/e2e/solver_competition.rs +++ b/crates/e2e/tests/e2e/solver_competition.rs @@ -37,21 +37,21 @@ async fn local_node_store_filtered_solutions() { async fn solver_competition(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token_a] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader, settlement accounts, and pool creation - token_a.mint(trader.address(), to_wei(10)).await; - token_a.mint(solver.address(), to_wei(1000)).await; + token_a.mint(trader.address(), eth(10)).await; + token_a.mint(solver.address(), eth(1000)).await; // Approve GPv2 for trading token_a .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -117,11 +117,11 @@ async fn solver_competition(web3: Web3) { tracing::info!("waiting for trade"); let trade_happened = || async { token_a - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap() - == U256::ZERO + .is_zero() }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); @@ -156,15 +156,15 @@ async fn solver_competition(web3: Web3) { async fn wrong_solution_submission_address(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader_a, trader_b] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund traders - token_a.mint(trader_a.address(), to_wei(10)).await; - token_b.mint(trader_b.address(), to_wei(10)).await; + token_a.mint(trader_a.address(), eth(10)).await; + token_b.mint(trader_b.address(), eth(10)).await; // Create more liquid routes between token_a (token_b) and weth via base_a // (base_b). base_a has more liquidity then base_b, leading to the solver that @@ -173,24 +173,24 @@ async fn wrong_solution_submission_address(web3: Web3) { .deploy_tokens_with_weth_uni_v2_pools(to_wei(10_000), to_wei(10_000)) .await; onchain - .seed_uni_v2_pool((&token_a, to_wei(100_000)), (&base_a, to_wei(100_000))) + .seed_uni_v2_pool((&token_a, eth(100_000)), (&base_a, eth(100_000))) .await; onchain - .seed_uni_v2_pool((&token_b, to_wei(10_000)), (&base_b, to_wei(10_000))) + .seed_uni_v2_pool((&token_b, eth(10_000)), (&base_b, eth(10_000))) .await; // Approve GPv2 for trading token_a .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); token_b .approve(onchain.contracts().allowance.into_alloy(), eth(100)) - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -295,7 +295,7 @@ async fn wrong_solution_submission_address(web3: Web3) { tracing::info!(?competition, "competition"); assert_eq!( competition.solutions.last().unwrap().solver_address, - solver.address().into_alloy() + solver.address() ); assert_eq!(competition.solutions.len(), 1); } @@ -303,8 +303,8 @@ async fn wrong_solution_submission_address(web3: Web3) { async fn store_filtered_solutions(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [good_solver_account, bad_solver_account] = onchain.make_solvers(to_wei(100)).await; - let [trader] = onchain.make_accounts(to_wei(100)).await; + let [good_solver_account, bad_solver_account] = onchain.make_solvers(eth(100)).await; + let [trader] = onchain.make_accounts(eth(100)).await; let [token_a, token_b, token_c] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(300_000), to_wei(1_000)) .await; @@ -312,24 +312,18 @@ async fn store_filtered_solutions(web3: Web3) { // give the settlement contract a ton of the traded tokens so that the mocked // solver solutions can simply give money away to make the trade execute token_b - .mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(50), - ) + .mint(*onchain.contracts().gp_settlement.address(), eth(50)) .await; token_c - .mint( - onchain.contracts().gp_settlement.address().into_legacy(), - to_wei(50), - ) + .mint(*onchain.contracts().gp_settlement.address(), eth(50)) .await; // set up trader for their order - token_a.mint(trader.address(), to_wei(2)).await; + token_a.mint(trader.address(), eth(2)).await; token_a .approve(onchain.contracts().allowance.into_alloy(), eth(2)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -529,8 +523,8 @@ async fn store_filtered_solutions(web3: Web3) { assert_eq!( competition .reference_scores - .get(&good_solver_account.address().into_alloy()), - Some(&0.into()) + .get(&good_solver_account.address()), + Some(&U256::ZERO) ); assert_eq!(competition.solutions.len(), 2); @@ -540,10 +534,7 @@ async fn store_filtered_solutions(web3: Web3) { assert_eq!(bad_solution.ranking, 2); assert!(bad_solution.filtered_out); assert!(!bad_solution.is_winner); - assert_eq!( - bad_solution.solver_address, - bad_solver_account.address().into_alloy() - ); + assert_eq!(bad_solution.solver_address, bad_solver_account.address()); assert!(bad_solution.tx_hash.is_none()); assert!(bad_solution.reference_score.is_none()); @@ -551,13 +542,10 @@ async fn store_filtered_solutions(web3: Web3) { assert_eq!(good_solution.ranking, 1); assert!(!good_solution.filtered_out); assert!(good_solution.is_winner); - assert_eq!( - good_solution.solver_address, - good_solver_account.address().into_alloy() - ); + assert_eq!(good_solution.solver_address, good_solver_account.address()); assert_eq!(good_solution.tx_hash.unwrap(), trade.tx_hash.unwrap()); // since the only other solutions were unfair the reference score is zero - assert_eq!(good_solution.reference_score, Some(0.into())); + assert_eq!(good_solution.reference_score, Some(U256::ZERO)); // check that new DB tables contain the filtered solution let mut db = services.db().acquire().await.unwrap(); diff --git a/crates/e2e/tests/e2e/solver_participation_guard.rs b/crates/e2e/tests/e2e/solver_participation_guard.rs index dcc1e34ebe..9898443166 100644 --- a/crates/e2e/tests/e2e/solver_participation_guard.rs +++ b/crates/e2e/tests/e2e/solver_participation_guard.rs @@ -51,7 +51,7 @@ async fn local_node_not_allowed_solver() { async fn non_settling_solver(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver, solver_b] = onchain.make_solvers(to_wei(1)).await; + let [solver, solver_b] = onchain.make_solvers(eth(1)).await; let (trader_a, token_a, token_b) = setup(&mut onchain, &solver).await; let services = Services::new(&onchain).await; @@ -90,7 +90,7 @@ async fn non_settling_solver(web3: Web3) { .take(3) .cloned() .collect::>(); - replace_solver_for_auction_ids(pool, &last_auctions, &solver_b.address()).await; + replace_solver_for_auction_ids(pool, &last_auctions, &solver_b.address().into_legacy()).await; // The competition still passes since the stats are updated only after a new // solution from anyone is received and stored. let now = Instant::now(); @@ -122,7 +122,7 @@ async fn non_settling_solver(web3: Web3) { async fn low_settling_solver(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver, solver_b] = onchain.make_solvers(to_wei(1)).await; + let [solver, solver_b] = onchain.make_solvers(eth(1)).await; let (trader_a, token_a, token_b) = setup(&mut onchain, &solver).await; let services = Services::new(&onchain).await; @@ -162,7 +162,7 @@ async fn low_settling_solver(web3: Web3) { .enumerate() .filter_map(|(i, id)| (i % 2 == 0).then_some(*id)) .collect::>(); - replace_solver_for_auction_ids(pool, &random_auctions, &solver_b.address()).await; + replace_solver_for_auction_ids(pool, &random_auctions, &solver_b.address().into_legacy()).await; // The competition still passes since the stats are updated only after a new // solution from anyone is received and stored. let now = Instant::now(); @@ -194,7 +194,7 @@ async fn low_settling_solver(web3: Web3) { async fn not_allowed_solver(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; let (trader_a, token_a, token_b) = setup(&mut onchain, &solver).await; let solver_address = solver.address(); @@ -209,7 +209,7 @@ async fn not_allowed_solver(web3: Web3) { onchain .contracts() .gp_authenticator - .removeSolver(solver_address.into_alloy()) + .removeSolver(solver_address) .send_and_watch() .await .unwrap(); @@ -224,7 +224,7 @@ async fn not_allowed_solver(web3: Web3) { onchain .contracts() .gp_authenticator - .addSolver(solver_address.into_alloy()) + .addSolver(solver_address) .send_and_watch() .await .unwrap(); @@ -238,36 +238,36 @@ async fn setup( onchain: &mut OnchainComponents, solver: &TestAccount, ) -> (TestAccount, MintableToken, MintableToken) { - let [trader_a] = onchain.make_accounts(to_wei(1)).await; + let [trader_a] = onchain.make_accounts(eth(1)).await; let [token_a, token_b] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; // Fund trader accounts - token_a.mint(trader_a.address(), to_wei(1000)).await; + token_a.mint(trader_a.address(), eth(1000)).await; // Create and fund Uniswap pool - token_a.mint(solver.address(), to_wei(1000)).await; - token_b.mint(solver.address(), to_wei(1000)).await; + token_a.mint(solver.address(), eth(1000)).await; + token_b.mint(solver.address(), eth(1000)).await; onchain .contracts() .uniswap_v2_factory .createPair(*token_a.address(), *token_b.address()) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_a .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); token_b .approve(*onchain.contracts().uniswap_v2_router.address(), eth(1000)) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -281,10 +281,10 @@ async fn setup( eth(1000), U256::ZERO, U256::ZERO, - solver.address().into_alloy(), + solver.address(), U256::MAX, ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); @@ -293,7 +293,7 @@ async fn setup( token_a .approve(onchain.contracts().allowance.into_alloy(), eth(1000)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -346,11 +346,7 @@ async fn execute_order( &onchain.contracts().domain_separator, SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()), ); - let balance_before = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_before = token_b.balanceOf(trader_a.address()).call().await.unwrap(); let order_id = services.create_order(&order).await.unwrap(); onchain.mint_block().await; let limit_order = services.get_order(&order_id).await.unwrap(); @@ -360,11 +356,7 @@ async fn execute_order( // Drive solution tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after = token_b - .balanceOf(trader_a.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = token_b.balanceOf(trader_a.address()).call().await.unwrap(); let balance_changes = balance_after.checked_sub(balance_before).unwrap() >= eth(5); let auction_ids_after = fetch_last_settled_auction_ids(services.db()).await.len() > auction_ids_before; diff --git a/crates/e2e/tests/e2e/submission.rs b/crates/e2e/tests/e2e/submission.rs index 89416eba00..60a2c63b5d 100644 --- a/crates/e2e/tests/e2e/submission.rs +++ b/crates/e2e/tests/e2e/submission.rs @@ -26,9 +26,9 @@ async fn local_node_test() { async fn test_cancel_on_expiry(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3.clone()).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; let nonce = solver.nonce(&web3).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -37,7 +37,7 @@ async fn test_cancel_on_expiry(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -45,7 +45,7 @@ async fn test_cancel_on_expiry(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(3)) .send_and_watch() .await @@ -62,11 +62,7 @@ async fn test_cancel_on_expiry(web3: Web3) { .expect("Must be able to disable automine"); tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { sell_token: onchain.contracts().weth.address().into_legacy(), diff --git a/crates/e2e/tests/e2e/tracking_insufficient_funds.rs b/crates/e2e/tests/e2e/tracking_insufficient_funds.rs index e0094a3f90..eea7456e6b 100644 --- a/crates/e2e/tests/e2e/tracking_insufficient_funds.rs +++ b/crates/e2e/tests/e2e/tracking_insufficient_funds.rs @@ -24,8 +24,8 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader_a, trader_b] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader_a, trader_b] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -34,7 +34,7 @@ async fn test(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -42,7 +42,7 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .value(eth(3)) .send_and_watch() .await @@ -51,7 +51,7 @@ async fn test(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -59,7 +59,7 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .value(eth(3)) .send_and_watch() .await @@ -106,7 +106,7 @@ async fn test(web3: Web3) { .contracts() .weth .withdraw(eth(3)) - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .send_and_watch() .await .unwrap(); @@ -114,7 +114,7 @@ async fn test(web3: Web3) { .contracts() .weth .withdraw(eth(3)) - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .send_and_watch() .await .unwrap(); @@ -139,7 +139,7 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_a.address().into_alloy()) + .from(trader_a.address()) .value(eth(3)) .send_and_watch() .await @@ -161,7 +161,7 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader_b.address().into_alloy()) + .from(trader_b.address()) .value(eth(3)) .send_and_watch() .await diff --git a/crates/e2e/tests/e2e/uncovered_order.rs b/crates/e2e/tests/e2e/uncovered_order.rs index 97fb964011..3159477a4f 100644 --- a/crates/e2e/tests/e2e/uncovered_order.rs +++ b/crates/e2e/tests/e2e/uncovered_order.rs @@ -26,15 +26,15 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; let weth = &onchain.contracts().weth; weth.approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -66,7 +66,7 @@ async fn test(web3: Web3) { tracing::info!("Placing order with 1 wei of sell_tokens"); weth.deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(::alloy::primitives::U256::ONE) .send_and_watch() .await @@ -77,7 +77,7 @@ async fn test(web3: Web3) { tracing::info!("Deposit ETH to make order executable"); weth.deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(2)) .send_and_watch() .await @@ -85,11 +85,7 @@ async fn test(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { - let balance_after = weth - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance_after = weth.balanceOf(trader.address()).call().await.unwrap(); !balance_after.is_zero() }) .await diff --git a/crates/e2e/tests/e2e/univ2.rs b/crates/e2e/tests/e2e/univ2.rs index 27792283f4..f781e43ba1 100644 --- a/crates/e2e/tests/e2e/univ2.rs +++ b/crates/e2e/tests/e2e/univ2.rs @@ -26,8 +26,8 @@ async fn test(web3: Web3) { tracing::info!("Setting up chain state."); let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(10)).await; - let [trader] = onchain.make_accounts(to_wei(10)).await; + let [solver] = onchain.make_solvers(eth(10)).await; + let [trader] = onchain.make_accounts(eth(10)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; @@ -36,7 +36,7 @@ async fn test(web3: Web3) { .contracts() .weth .approve(onchain.contracts().allowance.into_alloy(), eth(3)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -44,7 +44,7 @@ async fn test(web3: Web3) { .contracts() .weth .deposit() - .from(trader.address().into_alloy()) + .from(trader.address()) .value(eth(3)) .send_and_watch() .await @@ -55,11 +55,7 @@ async fn test(web3: Web3) { services.start_protocol(solver.clone()).await; tracing::info!("Placing order"); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, U256::ZERO); let order = OrderCreation { sell_token: onchain.contracts().weth.address().into_legacy(), @@ -88,7 +84,7 @@ async fn test(web3: Web3) { Default::default(), [ vec![GPv2Settlement::GPv2Interaction::Data { - target: trader.address().into_alloy(), + target: trader.address(), value: U256::ZERO, callData: Default::default(), }], @@ -96,27 +92,23 @@ async fn test(web3: Web3) { Default::default(), ], ) - .from(solver.address().into_alloy()) + .from(solver.address()) .send_and_watch() .await .unwrap(); tracing::info!("Waiting for trade."); let trade_happened = || async { - token - .balanceOf(trader.address().into_alloy()) + !token + .balanceOf(trader.address()) .call() .await .unwrap() - != U256::ZERO + .is_zero() }; wait_for_condition(TIMEOUT, trade_happened).await.unwrap(); - let balance = token - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let balance = token.balanceOf(trader.address()).call().await.unwrap(); assert_eq!(balance, eth(1)); let all_events_registered = || async { diff --git a/crates/e2e/tests/e2e/vault_balances.rs b/crates/e2e/tests/e2e/vault_balances.rs index 5491410586..2569021e8d 100644 --- a/crates/e2e/tests/e2e/vault_balances.rs +++ b/crates/e2e/tests/e2e/vault_balances.rs @@ -22,19 +22,19 @@ async fn local_node_vault_balances() { async fn vault_balances(web3: Web3) { let mut onchain = OnchainComponents::deploy(web3).await; - let [solver] = onchain.make_solvers(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(1)).await; + let [solver] = onchain.make_solvers(eth(1)).await; + let [trader] = onchain.make_accounts(eth(1)).await; let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token.mint(trader.address(), to_wei(10)).await; + token.mint(trader.address(), eth(10)).await; // Approve GPv2 for trading token .approve(*onchain.contracts().balancer_vault.address(), eth(10)) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -42,11 +42,11 @@ async fn vault_balances(web3: Web3) { .contracts() .balancer_vault .setRelayerApproval( - trader.address().into_alloy(), + trader.address(), onchain.contracts().allowance.into_alloy(), true, ) - .from(trader.address().into_alloy()) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -75,7 +75,7 @@ async fn vault_balances(web3: Web3) { let balance_before = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); @@ -84,7 +84,7 @@ async fn vault_balances(web3: Web3) { tracing::info!("Waiting for trade."); wait_for_condition(TIMEOUT, || async { let token_balance = token - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .expect("Couldn't fetch token balance"); @@ -92,7 +92,7 @@ async fn vault_balances(web3: Web3) { let weth_balance_after = onchain .contracts() .weth - .balanceOf(trader.address().into_alloy()) + .balanceOf(trader.address()) .call() .await .unwrap(); diff --git a/crates/e2e/tests/e2e/wrapper.rs b/crates/e2e/tests/e2e/wrapper.rs index 55b07a95bc..612166664b 100644 --- a/crates/e2e/tests/e2e/wrapper.rs +++ b/crates/e2e/tests/e2e/wrapper.rs @@ -48,8 +48,8 @@ async fn forked_node_mainnet_wrapper() { async fn forked_mainnet_wrapper_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; - let [solver] = onchain.make_solvers_forked(to_wei(1)).await; - let [trader] = onchain.make_accounts(to_wei(2)).await; + let [solver] = onchain.make_solvers_forked(eth(1)).await; + let [trader] = onchain.make_accounts(eth(2)).await; let token_weth = onchain.contracts().weth.clone(); let token_usdc = ERC20::Instance::new( @@ -75,7 +75,7 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { ) .into_transaction_request(), ImpersonateConfig { - fund_amount: Some(to_wei(1).into_alloy()), + fund_amount: Some(eth(1)), stop_impersonate: true, }, ) @@ -88,19 +88,16 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { // Trader deposits ETH to get WETH token_weth .deposit() - .value(to_wei(1).into_alloy()) - .from(trader.address().into_alloy()) + .value(eth(1)) + .from(trader.address()) .send_and_watch() .await .unwrap(); // Approve GPv2 for trading token_weth - .approve( - onchain.contracts().allowance.into_alloy(), - to_wei(1).into_alloy(), - ) - .from(trader.address().into_alloy()) + .approve(onchain.contracts().allowance.into_alloy(), eth(1)) + .from(trader.address()) .send_and_watch() .await .unwrap(); @@ -171,16 +168,8 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), ); - let sell_token_balance_before = token_weth - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_before = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_before = token_weth.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_before = token_usdc.balanceOf(trader.address()).call().await.unwrap(); // Create the order let order_uid = services.create_order(&order).await.unwrap(); @@ -203,16 +192,8 @@ async fn forked_mainnet_wrapper_test(web3: Web3) { wait_for_condition(TIMEOUT, || async { onchain.mint_block().await; - let sell_token_balance_after = token_weth - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); - let buy_token_balance_after = token_usdc - .balanceOf(trader.address().into_alloy()) - .call() - .await - .unwrap(); + let sell_token_balance_after = token_weth.balanceOf(trader.address()).call().await.unwrap(); + let buy_token_balance_after = token_usdc.balanceOf(trader.address()).call().await.unwrap(); (sell_token_balance_before > sell_token_balance_after) && (buy_token_balance_after > buy_token_balance_before) diff --git a/crates/model/src/order.rs b/crates/model/src/order.rs index e9649ebd3b..970c50db0f 100644 --- a/crates/model/src/order.rs +++ b/crates/model/src/order.rs @@ -273,22 +273,9 @@ impl OrderData { /// Checks if the order is a market order. pub fn within_market(&self, quote: QuoteAmounts) -> bool { - // Manual transformation because this crate doesn't have the conversiont trait - let mut buy_buffer = [0; 32]; - quote.buy.to_big_endian(&mut buy_buffer); - let quote_buy = alloy::primitives::U256::from_be_bytes(buy_buffer); - - let mut sell_buffer = [0; 32]; - quote.sell.to_big_endian(&mut sell_buffer); - let quote_sell = alloy::primitives::U256::from_be_bytes(sell_buffer); - - let mut fee_buffer = [0; 32]; - quote.fee.to_big_endian(&mut fee_buffer); - let quote_fee = alloy::primitives::U256::from_be_bytes(fee_buffer); - // Using let here because widening_mul isn't able to infer the result size - let lhs: U512 = (self.sell_amount + self.fee_amount).widening_mul(quote_buy); - let rhs: U512 = (quote_sell + quote_fee).widening_mul(self.buy_amount); + let lhs: U512 = (self.sell_amount + self.fee_amount).widening_mul(quote.buy); + let rhs: U512 = (quote.sell + quote.fee).widening_mul(self.buy_amount); lhs >= rhs } } @@ -297,9 +284,9 @@ impl OrderData { /// sell token and buy `buy` amount of buy token. Additionally, `fee`` /// denominated in the sell token needs to be payed. pub struct QuoteAmounts { - pub sell: U256, - pub buy: U256, - pub fee: U256, + pub sell: alloy::primitives::U256, + pub buy: alloy::primitives::U256, + pub fee: alloy::primitives::U256, } /// An order as provided to the POST order endpoint. diff --git a/crates/model/src/quote.rs b/crates/model/src/quote.rs index 171fbd9da5..c1dc2dd05c 100644 --- a/crates/model/src/quote.rs +++ b/crates/model/src/quote.rs @@ -4,12 +4,11 @@ use { signature::SigningScheme, time, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, anyhow::bail, app_data::AppDataHash, chrono::{DateTime, Utc}, number::{nonzero::U256 as NonZeroU256, serialization::HexOrDecimalU256}, - primitive_types::{H160, U256}, serde::{ Deserialize, Deserializer, @@ -304,9 +303,9 @@ pub enum SellAmount { #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct OrderQuote { - pub sell_token: H160, - pub buy_token: H160, - pub receiver: Option, + pub sell_token: Address, + pub buy_token: Address, + pub receiver: Option
, #[serde_as(as = "HexOrDecimalU256")] pub sell_amount: U256, #[serde_as(as = "HexOrDecimalU256")] @@ -330,7 +329,7 @@ pub type QuoteId = i64; #[serde(rename_all = "camelCase")] pub struct OrderQuoteResponse { pub quote: OrderQuote, - pub from: H160, + pub from: Address, pub expiration: DateTime, pub id: Option, pub verified: bool, diff --git a/crates/model/src/solver_competition.rs b/crates/model/src/solver_competition.rs index 56c101643f..e2532459a8 100644 --- a/crates/model/src/solver_competition.rs +++ b/crates/model/src/solver_competition.rs @@ -1,8 +1,7 @@ use { crate::{AuctionId, order::OrderUid}, - alloy::primitives::{Address, B256}, + alloy::primitives::{Address, B256, U256}, number::serialization::HexOrDecimalU256, - primitive_types::U256, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, @@ -36,7 +35,7 @@ pub struct SolverCompetitionAPI { pub struct CompetitionAuction { pub orders: Vec, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub prices: BTreeMap, + pub prices: BTreeMap, } #[serde_as] @@ -51,7 +50,7 @@ pub struct SolverSettlement { #[serde(default)] pub ranking: usize, #[serde_as(as = "BTreeMap<_, HexOrDecimalU256>")] - pub clearing_prices: BTreeMap, + pub clearing_prices: BTreeMap, pub orders: Vec, #[serde(default)] pub is_winner: bool, @@ -189,28 +188,28 @@ mod tests { OrderUid([0x33; 56]), ], prices: btreemap! { - Address::repeat_byte(0x11) => alloy::primitives::U256::from(1000), - Address::repeat_byte(0x22) => alloy::primitives::U256::from(2000), - Address::repeat_byte(0x33) => alloy::primitives::U256::from(3000), + Address::repeat_byte(0x11) => U256::from(1000), + Address::repeat_byte(0x22) => U256::from(2000), + Address::repeat_byte(0x33) => U256::from(3000), }, }, solutions: vec![SolverSettlement { solver: "2".to_string(), solver_address: Address::repeat_byte(0x22), - score: Some(Score::Solver(1.into())), + score: Some(Score::Solver(U256::ONE)), ranking: 1, clearing_prices: btreemap! { - Address::repeat_byte(0x22) => alloy::primitives::U256::from(8), + Address::repeat_byte(0x22) => U256::from(8), }, orders: vec![ Order::Colocated { id: OrderUid([0x33; 56]), - sell_amount: alloy::primitives::U256::from(12), - buy_amount: alloy::primitives::U256::from(13), + sell_amount: U256::from(12), + buy_amount: U256::from(13), }, Order::Legacy { id: OrderUid([0x44; 56]), - executed_amount: alloy::primitives::U256::from(14), + executed_amount: U256::from(14), }, ], is_winner: true, diff --git a/crates/model/src/solver_competition_v2.rs b/crates/model/src/solver_competition_v2.rs index bb5d154db8..30d83f8a02 100644 --- a/crates/model/src/solver_competition_v2.rs +++ b/crates/model/src/solver_competition_v2.rs @@ -1,8 +1,7 @@ use { crate::{AuctionId, order::OrderUid}, - alloy::primitives::{Address, B256}, + alloy::primitives::{Address, B256, U256}, number::serialization::HexOrDecimalU256, - primitive_types::U256, serde::{Deserialize, Serialize}, serde_with::serde_as, std::collections::BTreeMap, @@ -121,32 +120,32 @@ mod tests { auction_start_block: 13, transaction_hashes: vec![tx], reference_scores: btreemap! { - solver => 0.into() + solver => U256::ZERO }, auction: Auction { orders: vec![OrderUid([0x11; 56])], prices: btreemap! { - Address::new([0x22; 20]) => 2000.into(), + Address::new([0x22; 20]) => U256::from(2000), }, }, solutions: vec![Solution { solver_address: solver, - score: 123.into(), + score: U256::from(123), ranking: 1, clearing_prices: btreemap! { - Address::new([0x22; 20]) => 8.into(), + Address::new([0x22; 20]) => U256::from(8), }, orders: vec![Order { id: OrderUid([0x11; 56]), - sell_amount: 12.into(), - buy_amount: 13.into(), + sell_amount: U256::from(12), + buy_amount: U256::from(13), buy_token: Address::new([0x22; 20]), sell_token: Address::new([0x22; 20]), }], is_winner: true, filtered_out: false, tx_hash: Some(tx), - reference_score: Some(10.into()), + reference_score: Some(U256::from(10)), }], }; diff --git a/crates/orderbook/src/api/post_quote.rs b/crates/orderbook/src/api/post_quote.rs index 46d18a06cd..ce8d9d2b75 100644 --- a/crates/orderbook/src/api/post_quote.rs +++ b/crates/orderbook/src/api/post_quote.rs @@ -92,7 +92,6 @@ mod tests { anyhow::anyhow, app_data::AppDataHash, chrono::{TimeZone, Utc}, - ethcontract::H160, model::{ order::{BuyTokenDestination, SellTokenSource}, quote::{ @@ -315,7 +314,7 @@ mod tests { }; let order_quote_response = OrderQuoteResponse { quote, - from: H160::zero(), + from: Address::ZERO, expiration: Utc.timestamp_millis_opt(0).unwrap(), id: Some(0), verified: false, diff --git a/crates/orderbook/src/database/solver_competition_v2.rs b/crates/orderbook/src/database/solver_competition_v2.rs index 71d735e089..8a38620fb4 100644 --- a/crates/orderbook/src/database/solver_competition_v2.rs +++ b/crates/orderbook/src/database/solver_competition_v2.rs @@ -8,7 +8,7 @@ use { order::OrderUid, solver_competition_v2::{Auction, Order, Response as ApiResponse, Solution}, }, - number::conversions::big_decimal_to_u256, + number::conversions::alloy::big_decimal_to_u256, std::collections::{BTreeMap, HashMap}, }; diff --git a/crates/orderbook/src/quoter.rs b/crates/orderbook/src/quoter.rs index dec7eb7769..7b274d4d60 100644 --- a/crates/orderbook/src/quoter.rs +++ b/crates/orderbook/src/quoter.rs @@ -5,7 +5,6 @@ use { }, alloy::primitives::{U256, U512, Uint, ruint::UintTryFrom}, chrono::{TimeZone, Utc}, - ethrpc::alloy::conversions::IntoLegacy, model::{ order::OrderCreationAppData, quote::{OrderQuote, OrderQuoteRequest, OrderQuoteResponse, OrderQuoteSide, PriceQuality}, @@ -129,11 +128,11 @@ impl QuoteHandler { .map_err(|err| OrderQuoteError::CalculateQuote(err.into()))?; let response = OrderQuoteResponse { quote: OrderQuote { - sell_token: request.sell_token.into_legacy(), - buy_token: request.buy_token.into_legacy(), - receiver: request.receiver.map(IntoLegacy::into_legacy), - sell_amount: adjusted_quote.sell_amount.into_legacy(), - buy_amount: adjusted_quote.buy_amount.into_legacy(), + sell_token: request.sell_token, + buy_token: request.buy_token, + receiver: request.receiver, + sell_amount: adjusted_quote.sell_amount, + buy_amount: adjusted_quote.buy_amount, valid_to, app_data: match &request.app_data { OrderCreationAppData::Full { full } => OrderCreationAppData::Both { @@ -142,14 +141,14 @@ impl QuoteHandler { }, app_data => app_data.clone(), }, - fee_amount: quote.fee_amount.into_legacy(), + fee_amount: quote.fee_amount, kind: quote.data.kind, partially_fillable: false, sell_token_balance: request.sell_token_balance, buy_token_balance: request.buy_token_balance, signing_scheme: request.signing_scheme.into(), }, - from: request.from.into_legacy(), + from: request.from, expiration: quote.data.expiration, id: quote.id, verified: quote.data.verified, @@ -256,6 +255,7 @@ mod tests { super::*, crate::arguments::FeeFactor, alloy::primitives::U256, + ethrpc::alloy::conversions::IntoLegacy, model::quote::OrderQuoteSide, shared::order_quoting::{Quote, QuoteData}, }; diff --git a/crates/solvers/src/util/math.rs b/crates/solvers/src/util/math.rs deleted file mode 100644 index 96018c1e5f..0000000000 --- a/crates/solvers/src/util/math.rs +++ /dev/null @@ -1,20 +0,0 @@ -use ethereum_types::U256; - -/// Perform a ceiled U256 integer division. -/// -/// Returns `None` when dividing by `0`. -pub fn div_ceil(q: U256, d: U256) -> Option { - if d.is_zero() { - return None; - } - - let (r, rem) = q.div_mod(d); - if rem.is_zero() { - Some(r) - } else { - Some( - r.checked_add(U256::one()) - .expect("unexpected ceiled division overflow"), - ) - } -} diff --git a/crates/solvers/src/util/mod.rs b/crates/solvers/src/util/mod.rs index ce85e8add0..051f909a2d 100644 --- a/crates/solvers/src/util/mod.rs +++ b/crates/solvers/src/util/mod.rs @@ -1,5 +1,4 @@ pub mod bytes; pub mod conv; pub mod fmt; -pub mod math; pub mod serialize; From 476bdff421a49e11e77d226643c2e43525ae14aa Mon Sep 17 00:00:00 2001 From: Martin Magnus Date: Thu, 27 Nov 2025 15:47:51 +0100 Subject: [PATCH 018/470] Post process settlements in parallel (#3853) # Description Currently we post-process settlements (i.e. associate the tx with a solution proposed by a solver) serially. IIRC it was done that way because it was simpler and that step simply ran in a background task at the time. Since then this logic has been moved onto the hot path so all the time we spend there delays the creation of the next auction. Additionally with the introduction of combinatorial auctions it's now possible and relatively common to have multiple settlement transactions in the same block. Whenever we have multiple settlements in one block this PR should result in a significant performance uplift because we process multiple concurrently. # Changes replaced loop to post-process auctions serially with logic that first fetches ALL unprocessed settlements and then works on up to 10 of them concurrently. This is fine for the post processing logic (as opposed to the raw event indexing) because it's okay for post-processing to happen out of order. So if the we successfully post-process settlement `n+1` but not settlement `n` (e.g. due to a crash) the DB query would still just return all unprocessed events instead of all NEW unprocessed events. I also adjusted how retrying works in this code. Instead of returning some result enum (ok, invalid, nothing_to_do) to make the serial loop retry something we now have a function `retry_with_sleep` that simply retires a passed in future n times and returns an `Option` to indicate whether it was successful or not. This is used in 2 places: 1. fetching all outstanding settlements 2. post-processing individual outstanding settlement With that the new logic should be as robust as the old one while being IMO easier to reason about. ## How to test Not sure how to test the improvement specifically. Since this is a performance optimization and I don't really want to test the internals of the implementation having a new test that makes sure that a big number of settlements can be post-processed would be enough to test correctness and for the performance aspect we'd have to deploy this on the cluster. Regarding the performance I temporarily deployed it to staging and it produced the expected effect of reducing the spikiness that comes from multiple settlements needing to be post-processed in the same block. Screenshot 2025-11-03 at 22 12 26 --- .../src/boundary/events/settlement.rs | 8 +- .../src/domain/settlement/observer.rs | 128 ++++++++++-------- crates/autopilot/src/infra/persistence/mod.rs | 11 +- crates/database/src/settlements.rs | 17 +-- 4 files changed, 90 insertions(+), 74 deletions(-) diff --git a/crates/autopilot/src/boundary/events/settlement.rs b/crates/autopilot/src/boundary/events/settlement.rs index e58ea68ce9..ef4206efe6 100644 --- a/crates/autopilot/src/boundary/events/settlement.rs +++ b/crates/autopilot/src/boundary/events/settlement.rs @@ -75,7 +75,9 @@ impl EventStoring<(GPv2SettlementEvents, Log)> for Indexer { database::settlements::delete(&mut transaction, from_block).await?; transaction.commit().await?; - self.settlement_observer.update().await; + self.settlement_observer + .post_process_outstanding_settlement_transactions() + .await; Ok(()) } @@ -84,7 +86,9 @@ impl EventStoring<(GPv2SettlementEvents, Log)> for Indexer { crate::database::events::append_events(&mut transaction, events).await?; transaction.commit().await?; - self.settlement_observer.update().await; + self.settlement_observer + .post_process_outstanding_settlement_transactions() + .await; Ok(()) } } diff --git a/crates/autopilot/src/domain/settlement/observer.rs b/crates/autopilot/src/domain/settlement/observer.rs index fc9af2e653..438208f49c 100644 --- a/crates/autopilot/src/domain/settlement/observer.rs +++ b/crates/autopilot/src/domain/settlement/observer.rs @@ -20,6 +20,8 @@ use { }, anyhow::{Context, Result, anyhow}, ethrpc::alloy::conversions::IntoLegacy, + futures::StreamExt, + rand::Rng, std::time::Duration, }; @@ -29,12 +31,6 @@ pub struct Observer { persistence: infra::Persistence, } -enum IndexSuccess { - NothingToDo, - IndexedSettlement, - SkippedInvalidTransaction, -} - impl Observer { /// Creates a new Observer and asynchronously schedules the first update /// run. @@ -42,67 +38,61 @@ impl Observer { Self { eth, persistence } } - /// Fetches all the available missing data needed for bookkeeping. - /// This needs to get called after indexing a new settlement event - /// since this code needs that data to already be present in the DB. - pub async fn update(&self) { - const MAX_RETRIES: usize = 5; - let mut attempts = 0; - while attempts < MAX_RETRIES { - match self.single_update().await { - Ok(IndexSuccess::IndexedSettlement) => { - tracing::debug!("on settlement event updater ran and processed event"); - } - Ok(IndexSuccess::SkippedInvalidTransaction) => { - tracing::warn!("stored default values for unindexable transaction"); - } - Ok(IndexSuccess::NothingToDo) => { - tracing::debug!("on settlement event updater ran without update"); + /// Post processes all outstanding settlements. This involves decoding the + /// settlement details from the transaction and associating it with a + /// solution proposed by a solver for the auction specified at the end of + /// the transaction call data. If no solution can be found a dummy mapping + /// gets saved to mark the settlement as processed. This can happen when a + /// solver submits a solution despite not winning or if the settlement + /// belongs to an auction that was arbitrated in another environment (i.e. + /// prod vs. staging). + pub async fn post_process_outstanding_settlement_transactions(&self) { + let settlements = + match Self::retry_with_sleep(|| self.persistence.get_settlements_without_auction()) + .await + { + Ok(settlements) => settlements, + Err(errs) => { + tracing::warn!(?errs, "failed to fetch unprocessed settlements"); return; } - Err(err) => { - tracing::debug!(?err, "encountered retryable error"); - // wait a little to give temporary errors a chance to resolve themselves - const TEMP_ERROR_BACK_OFF: Duration = Duration::from_millis(100); - tokio::time::sleep(TEMP_ERROR_BACK_OFF).await; - attempts += 1; - continue; - } - } + }; - // everything worked fine -> reset our attempts for the next settlement - attempts = 0; + if settlements.is_empty() { + tracing::debug!("no unprocessed settlements found"); + return; } - } - - /// Update database for settlement events that have not been processed yet. - /// - /// Returns whether an update was performed. - async fn single_update(&self) -> Result { - // Find a settlement event that has not been processed yet. - let Some(event) = self - .persistence - .get_settlement_without_auction() - .await - .context("failed to fetch unprocessed tx from DB")? - else { - return Ok(IndexSuccess::NothingToDo); - }; - tracing::debug!(tx = ?event.transaction, "found unprocessed settlement"); + // On mainnet it's common to have multiple settlements in the + // same block. So even if we process every block immediately, + // we should still post-process multiple settlements concurrently. + const MAX_CONCURRENCY: usize = 10; + futures::stream::iter(settlements) + .for_each_concurrent(MAX_CONCURRENCY, |settlement| async move { + tracing::debug!(tx = ?settlement.transaction, "start post processing of settlement"); + match Self::retry_with_sleep(|| self.post_process_settlement(settlement)).await { + Ok(_) => tracing::debug!( + tx = ?settlement.transaction, + "successfully post-processed settlement" + ), + Err(errs) => tracing::warn!( + tx = ?settlement.transaction, + ?errs, + "gave up on post-processing settlement" + ), + } + }) + .await; + } + async fn post_process_settlement(&self, settlement: eth::SettlementEvent) -> Result<()> { let settlement_data = self - .fetch_auction_data_for_transaction(event.transaction) + .fetch_auction_data_for_transaction(settlement.transaction) .await?; self.persistence - .save_settlement(event, settlement_data.as_ref()) + .save_settlement(settlement, settlement_data.as_ref()) .await - .context("failed to update settlement")?; - - match settlement_data { - None => Ok(IndexSuccess::SkippedInvalidTransaction), - Some(_) => Ok(IndexSuccess::IndexedSettlement), - } + .context("failed to update settlement") } /// Inspects the calldata of the transaction, decodes the arguments, and @@ -179,4 +169,28 @@ impl Observer { } } } + + async fn retry_with_sleep(future: impl Fn() -> F) -> Result> + where + F: Future>, + ERR: std::fmt::Debug, + { + const MAX_RETRIES: usize = 5; + + let mut errors = Vec::new(); + let mut tries = 0; + while tries < MAX_RETRIES { + match future().await { + Ok(res) => return Ok(res), + Err(err) => { + errors.push(err); + tries += 1; + // wait a little to give temporary errors a chance to resolve themselves + let timeout_with_jitter = 50u64 + rand::thread_rng().gen_range(0..=50); + tokio::time::sleep(Duration::from_millis(timeout_with_jitter)).await; + } + } + } + Err(errors) + } } diff --git a/crates/autopilot/src/infra/persistence/mod.rs b/crates/autopilot/src/infra/persistence/mod.rs index 13c2874fd6..c07925b9e3 100644 --- a/crates/autopilot/src/infra/persistence/mod.rs +++ b/crates/autopilot/src/infra/persistence/mod.rs @@ -594,17 +594,18 @@ impl Persistence { /// Returns the oldest settlement event for which the accociated auction is /// not yet populated in the database. - pub async fn get_settlement_without_auction( + pub async fn get_settlements_without_auction( &self, - ) -> Result, DatabaseError> { + ) -> Result, DatabaseError> { let _timer = Metrics::get() .database_queries .with_label_values(&["get_settlement_without_auction"]) .start_timer(); let mut ex = self.postgres.pool.acquire().await?; - let event = database::settlements::get_settlement_without_auction(&mut ex) + let events = database::settlements::get_settlements_without_auction(&mut ex) .await? + .into_iter() .map(|event| { let event = domain::eth::SettlementEvent { block: u64::try_from(event.block_number) @@ -615,8 +616,8 @@ impl Persistence { }; Ok::<_, DatabaseError>(event) }) - .transpose()?; - Ok(event) + .collect::, _>>()?; + Ok(events) } /// Returns the trade events that are associated with the settlement event diff --git a/crates/database/src/settlements.rs b/crates/database/src/settlements.rs index a0215d279a..36980ab2b3 100644 --- a/crates/database/src/settlements.rs +++ b/crates/database/src/settlements.rs @@ -31,17 +31,16 @@ pub struct SettlementEvent { } #[instrument(skip_all)] -pub async fn get_settlement_without_auction( +pub async fn get_settlements_without_auction( ex: &mut PgConnection, -) -> Result, sqlx::Error> { +) -> Result, sqlx::Error> { const QUERY: &str = r#" SELECT block_number, log_index, tx_hash FROM settlements WHERE auction_id IS NULL ORDER BY block_number ASC -LIMIT 1 "#; - sqlx::query_as(QUERY).fetch_optional(ex).await + sqlx::query_as(QUERY).fetch_all(ex).await } #[instrument(skip_all)] @@ -195,10 +194,8 @@ mod tests { .await .unwrap(); - let settlement = get_settlement_without_auction(&mut db) - .await - .unwrap() - .unwrap(); + let settlements = get_settlements_without_auction(&mut db).await.unwrap(); + let settlement = &settlements[0]; assert_eq!(settlement.block_number, event.block_number); assert_eq!(settlement.log_index, event.log_index); @@ -207,8 +204,8 @@ mod tests { .await .unwrap(); - let settlement = get_settlement_without_auction(&mut db).await.unwrap(); + let settlement = get_settlements_without_auction(&mut db).await.unwrap(); - assert!(settlement.is_none()); + assert!(settlement.is_empty()); } } From 66a5e283be3c69af6bfb83f138b276aa61edc3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Fri, 28 Nov 2025 10:40:53 +0000 Subject: [PATCH 019/470] [TRIVIAL] Migrate from H160 to alloy Address types (#3927) Simple despite being huge # Description This PR continues the migration from the `ethcontract` library to the `alloy` library by * replacing instances of `ethcontract::H160` and `primitive_types::H160` with `alloy::primitives::Address` * replacing instances of `ethcontract::U256` and `primitives_types::U256` with `alloy::primitives::U256` There are plenty left, the current commit has a focus on some structures are related code, however some of the structures only got a partial migration to avoid an even more complex PR This migration simplifies the codebase by reducing the need for type conversions and aligns the entire codebase with alloy's native types. # Changes - [x] Replace `H160` with `Address` - [x] Replace `ethcontract::U256` with `alloy::primitives::U256` - [x] Remove unnecessary `.into_alloy()` and `.into_legacy()` conversion calls - [x] Update function signatures across all affected crates - [x] Simplify bad token detection code - [x] Update liquidity source implementations (Balancer V2, Uniswap V2/V3) - [x] Update baseline solver and price estimation modules - [x] Simplify token owner finder implementations - [x] Update Cargo dependencies ## How to test Existing tests --------- Co-authored-by: Claude --- Cargo.lock | 4 + .../src/infra/blockchain/contracts.rs | 31 +-- crates/autopilot/src/run.rs | 18 +- .../src/boundary/liquidity/balancer/v2/mod.rs | 12 +- .../boundary/liquidity/balancer/v2/stable.rs | 2 +- .../liquidity/balancer/v2/weighted.rs | 2 +- crates/driver/src/boundary/liquidity/mod.rs | 10 +- .../src/boundary/liquidity/uniswap/v2.rs | 23 +- .../src/boundary/liquidity/uniswap/v3.rs | 12 +- .../competition/bad_tokens/simulation.rs | 23 +- crates/orderbook/src/run.rs | 19 +- crates/shared/Cargo.toml | 7 +- crates/shared/src/arguments.rs | 29 +-- .../token_owner_finder/blockscout.rs | 16 +- .../bad_token/token_owner_finder/ethplorer.rs | 14 +- .../bad_token/token_owner_finder/liquidity.rs | 28 +-- .../src/bad_token/token_owner_finder/mod.rs | 40 ++-- .../token_owner_finder/solvers/mod.rs | 6 +- .../token_owner_finder/solvers/solver_api.rs | 6 +- .../solvers/solver_finder.rs | 9 +- .../token_owner_finder/token_owner_list.rs | 21 +- crates/shared/src/bad_token/trace_call.rs | 63 +++--- crates/shared/src/baseline_solver.rs | 205 ++++++++---------- crates/shared/src/external_prices.rs | 32 +-- crates/shared/src/http_solver.rs | 9 +- .../shared/src/price_estimation/buffered.rs | 30 ++- crates/shared/src/price_estimation/factory.rs | 2 +- .../src/price_estimation/native/coingecko.rs | 45 ++-- .../src/price_estimation/native/oneinch.rs | 11 +- .../src/sources/balancer_v2/graph_api.rs | 63 +++--- .../sources/balancer_v2/pool_fetching/mod.rs | 26 +-- .../balancer_v2/pool_fetching/pool_storage.rs | 65 +++--- .../src/sources/balancer_v2/pools/common.rs | 142 ++++++------ .../balancer_v2/pools/composable_stable.rs | 13 +- .../pools/liquidity_bootstrapping.rs | 13 +- .../src/sources/balancer_v2/pools/stable.rs | 25 +-- .../src/sources/balancer_v2/pools/weighted.rs | 50 +++-- .../src/sources/balancer_v2/swap/mod.rs | 90 ++++---- crates/shared/src/sources/swapr.rs | 8 +- crates/shared/src/sources/uniswap_v2/mod.rs | 51 +++-- .../src/sources/uniswap_v2/pair_provider.rs | 22 +- .../src/sources/uniswap_v2/pool_fetching.rs | 84 ++++--- .../src/sources/uniswap_v3_pair_provider.rs | 14 +- crates/shared/src/token_info.rs | 44 ++-- crates/solver/src/interactions/allowances.rs | 152 +++++++------ crates/solver/src/interactions/balancer_v2.rs | 20 +- crates/solver/src/liquidity/balancer_v2.rs | 65 +++--- crates/solver/src/liquidity/mod.rs | 11 +- crates/solver/src/liquidity/slippage.rs | 46 ++-- crates/solver/src/liquidity/uniswap_v2.rs | 61 +++--- crates/solver/src/liquidity/uniswap_v3.rs | 60 +++-- crates/solver/src/liquidity/zeroex.rs | 97 ++++----- crates/solver/src/solver.rs | 11 +- crates/solvers/src/boundary/baseline.rs | 18 +- .../src/boundary/liquidity/concentrated.rs | 22 +- .../boundary/liquidity/constant_product.rs | 2 +- .../src/boundary/liquidity/limit_order.rs | 42 ++-- .../solvers/src/boundary/liquidity/stable.rs | 5 +- .../boundary/liquidity/weighted_product.rs | 5 +- 59 files changed, 1005 insertions(+), 1051 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8069c1f926..b09a995840 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,6 +353,7 @@ dependencies = [ "const-hex", "derive_more 2.0.1", "foldhash 0.2.0", + "getrandom 0.3.3", "hashbrown 0.16.0", "indexmap 2.10.0", "itoa", @@ -5794,6 +5795,9 @@ name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +dependencies = [ + "rand 0.8.5", +] [[package]] name = "rustc-hex" diff --git a/crates/autopilot/src/infra/blockchain/contracts.rs b/crates/autopilot/src/infra/blockchain/contracts.rs index 11dd601f51..a6eb92a1ae 100644 --- a/crates/autopilot/src/infra/blockchain/contracts.rs +++ b/crates/autopilot/src/infra/blockchain/contracts.rs @@ -1,5 +1,6 @@ use { crate::domain, + alloy::primitives::Address, chain::Chain, contracts::alloy::{ ChainalysisOracle, @@ -9,11 +10,7 @@ use { WETH9, support::Balances, }, - ethrpc::{ - Web3, - alloy::conversions::{IntoAlloy, IntoLegacy}, - }, - primitive_types::H160, + ethrpc::{Web3, alloy::conversions::IntoLegacy}, }; #[derive(Debug, Clone)] @@ -34,11 +31,11 @@ pub struct Contracts { #[derive(Debug, Clone)] pub struct Addresses { - pub settlement: Option, - pub signatures: Option, - pub weth: Option, - pub balances: Option, - pub trampoline: Option, + pub settlement: Option
, + pub signatures: Option
, + pub weth: Option
, + pub balances: Option
, + pub trampoline: Option
, } impl Contracts { @@ -46,7 +43,6 @@ impl Contracts { let settlement = GPv2Settlement::Instance::new( addresses .settlement - .map(IntoAlloy::into_alloy) .or_else(|| GPv2Settlement::deployment_address(&chain.id())) .unwrap(), web3.alloy.clone(), @@ -55,7 +51,6 @@ impl Contracts { let signatures = contracts::alloy::support::Signatures::Instance::new( addresses .signatures - .map(IntoAlloy::into_alloy) .or_else(|| contracts::alloy::support::Signatures::deployment_address(&chain.id())) .unwrap(), web3.alloy.clone(), @@ -64,7 +59,6 @@ impl Contracts { let weth = WETH9::Instance::new( addresses .weth - .map(IntoAlloy::into_alloy) .or_else(|| WETH9::deployment_address(&chain.id())) .unwrap(), web3.alloy.clone(), @@ -73,7 +67,6 @@ impl Contracts { let balances = Balances::Instance::new( addresses .balances - .map(IntoAlloy::into_alloy) .or_else(|| Balances::deployment_address(&chain.id())) .unwrap(), web3.alloy.clone(), @@ -82,7 +75,6 @@ impl Contracts { let trampoline = HooksTrampoline::Instance::new( addresses .trampoline - .map(IntoAlloy::into_alloy) .or_else(|| HooksTrampoline::deployment_address(&chain.id())) .unwrap(), web3.alloy.clone(), @@ -160,12 +152,3 @@ impl Contracts { &self.authenticator } } - -/// Returns the address of a contract for the specified chain, or `None` if -/// there is no known deployment for the contract on that chain. -pub fn deployment_address(contract: ðcontract::Contract, chain: &Chain) -> Option { - contract - .networks - .get(&chain.id().to_string()) - .map(|network| network.address) -} diff --git a/crates/autopilot/src/run.rs b/crates/autopilot/src/run.rs index f27d667bc1..8549da4acc 100644 --- a/crates/autopilot/src/run.rs +++ b/crates/autopilot/src/run.rs @@ -216,14 +216,8 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { let contracts = infra::blockchain::contracts::Addresses { settlement: args.shared.settlement_contract_address, signatures: args.shared.signatures_contract_address, - weth: args - .shared - .native_token_address - .map(IntoLegacy::into_legacy), - balances: args - .shared - .balances_contract_address - .map(IntoLegacy::into_legacy), + weth: args.shared.native_token_address, + balances: args.shared.balances_contract_address, trampoline: args.shared.hooks_contract_address, }; let eth = ethereum( @@ -322,11 +316,11 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { .await; let base_tokens = Arc::new(BaseTokens::new( - eth.contracts().weth().address().into_legacy(), + *eth.contracts().weth().address(), &args.shared.base_tokens, )); let mut allowed_tokens = args.allowed_tokens.clone(); - allowed_tokens.extend(base_tokens.tokens().iter().map(|t| t.into_alloy())); + allowed_tokens.extend(base_tokens.tokens().iter()); allowed_tokens.push(model::order::BUY_ETH_ADDRESS.into_alloy()); let unsupported_tokens = args.unsupported_tokens.clone(); @@ -339,7 +333,7 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { vault.as_ref(), uniswapv3_factory.as_ref(), &base_tokens, - eth.contracts().settlement().address().into_legacy(), + *eth.contracts().settlement().address(), ) .instrument(info_span!("token_owner_finder_init")) .await @@ -354,7 +348,7 @@ pub async fn run(args: Arguments, shutdown_controller: ShutdownController) { tracing_node_url, "trace", ), - eth.contracts().settlement().address().into_legacy(), + *eth.contracts().settlement().address(), finder, )), args.shared.token_quality_cache_expiry, diff --git a/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs b/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs index 820ad58e51..99f2c48270 100644 --- a/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs +++ b/crates/driver/src/boundary/liquidity/balancer/v2/mod.rs @@ -57,12 +57,18 @@ fn to_interaction( // change this assumption, we would need to change it there as well. receiver.0.into_alloy(), pool.vault.0.into_alloy(), - Allowances::empty(receiver.0), + Allowances::empty(receiver.0.into_alloy()), ); let interaction = handler.swap( - TokenAmount::new(input.0.token.into(), input.0.amount), - TokenAmount::new(output.0.token.into(), output.0.amount), + TokenAmount::new( + input.0.token.0.0.into_alloy(), + input.0.amount.0.into_alloy(), + ), + TokenAmount::new( + output.0.token.0.0.into_alloy(), + output.0.amount.0.into_alloy(), + ), ); let (target, value, call_data) = interaction.encode_swap(); diff --git a/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs b/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs index dc252d7312..0a9eb482ea 100644 --- a/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs +++ b/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs @@ -27,7 +27,7 @@ pub fn to_domain(id: liquidity::Id, pool: StablePoolOrder) -> Result Result>(), ); diff --git a/crates/driver/src/boundary/liquidity/uniswap/v2.rs b/crates/driver/src/boundary/liquidity/uniswap/v2.rs index 12da65e9eb..8bf9b979cc 100644 --- a/crates/driver/src/boundary/liquidity/uniswap/v2.rs +++ b/crates/driver/src/boundary/liquidity/uniswap/v2.rs @@ -7,6 +7,7 @@ use { }, infra::{self, blockchain::Ethereum}, }, + alloy::primitives::Address, async_trait::async_trait, contracts::alloy::IUniswapLikeRouter, ethrpc::{ @@ -75,7 +76,7 @@ pub(in crate::boundary::liquidity) fn to_domain_pool( ); Ok(liquidity::uniswap::v2::Pool { - address: pool.address.into(), + address: pool.address.into_legacy().into(), router: router(&pool), reserves: liquidity::uniswap::v2::Reserves::try_new( eth::Asset { @@ -100,12 +101,18 @@ pub fn to_interaction( let handler = uniswap_v2::Inner::new( pool.router.0.into_alloy(), receiver.0.into_alloy(), - Mutex::new(Allowances::empty(receiver.0)), + Mutex::new(Allowances::empty(receiver.0.into_alloy())), ); let (_, interaction) = handler.settle( - TokenAmount::new(input.0.token.into(), input.0.amount), - TokenAmount::new(output.0.token.into(), output.0.amount), + TokenAmount::new( + input.0.token.0.0.into_alloy(), + input.0.amount.0.into_alloy(), + ), + TokenAmount::new( + output.0.token.0.0.into_alloy(), + output.0.amount.0.into_alloy(), + ), ); let (target, value, call_data) = interaction.encode_swap(); @@ -142,7 +149,7 @@ where let pool_fetcher = { let factory = router.factory().call().await?; let pair_provider = PairProvider { - factory: factory.into_legacy(), + factory, init_code_digest: config.pool_code.into(), }; @@ -172,11 +179,7 @@ struct NoAllowanceManaging; #[async_trait] impl AllowanceManaging for NoAllowanceManaging { - async fn get_allowances( - &self, - _: HashSet, - spender: eth::H160, - ) -> Result { + async fn get_allowances(&self, _: HashSet
, spender: Address) -> Result { Ok(Allowances::empty(spender)) } diff --git a/crates/driver/src/boundary/liquidity/uniswap/v3.rs b/crates/driver/src/boundary/liquidity/uniswap/v3.rs index 6c4b368e99..6ac59e305a 100644 --- a/crates/driver/src/boundary/liquidity/uniswap/v3.rs +++ b/crates/driver/src/boundary/liquidity/uniswap/v3.rs @@ -83,13 +83,19 @@ pub fn to_interaction( let handler = UniswapV3SettlementHandler::new( pool.router.0.into_alloy(), receiver.0.into_alloy(), - Mutex::new(Allowances::empty(receiver.0)), + Mutex::new(Allowances::empty(receiver.0.into_alloy())), pool.fee.0, ); let (_, interaction) = handler.settle( - TokenAmount::new(input.0.token.into(), input.0.amount), - TokenAmount::new(output.0.token.into(), output.0.amount), + TokenAmount::new( + input.0.token.0.0.into_alloy(), + input.0.amount.0.into_alloy(), + ), + TokenAmount::new( + output.0.token.0.0.into_alloy(), + output.0.amount.0.into_alloy(), + ), ); let encoded = interaction.encode(); diff --git a/crates/driver/src/domain/competition/bad_tokens/simulation.rs b/crates/driver/src/domain/competition/bad_tokens/simulation.rs index 174a37c409..0568af3c94 100644 --- a/crates/driver/src/domain/competition/bad_tokens/simulation.rs +++ b/crates/driver/src/domain/competition/bad_tokens/simulation.rs @@ -1,16 +1,13 @@ use { crate::{ - domain::{ - competition::{ - Order, - bad_tokens::{Quality, cache::Cache}, - order, - }, - eth, + domain::competition::{ + Order, + bad_tokens::{Quality, cache::Cache}, + order, }, infra::{self, observe::metrics}, }, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethrpc::alloy::conversions::IntoAlloy, futures::FutureExt, model::interaction::InteractionData, shared::{ @@ -38,10 +35,8 @@ struct Inner { impl Detector { pub fn new(max_age: Duration, eth: &infra::Ethereum) -> Self { - let detector = TraceCallDetectorRaw::new( - eth.web3().clone(), - eth.contracts().settlement().address().into_legacy(), - ); + let detector = + TraceCallDetectorRaw::new(eth.web3().clone(), *eth.contracts().settlement().address()); Self(Arc::new(Inner { cache: Cache::new(max_age), detector, @@ -79,7 +74,7 @@ impl Detector { call_data: i.call_data.0.clone(), }) .collect(); - let trader = eth::Address::from(order.trader()).0; + let trader = order.trader().0.0.into_alloy(); let sell_amount = match order.partial { order::Partial::Yes { available } => available.0, order::Partial::No => order.sell.amount.0, @@ -88,7 +83,7 @@ impl Detector { async move { let result = inner .detector - .test_transfer(trader, sell_token.0 .0, sell_amount, &pre_interactions) + .test_transfer(trader, sell_token.0.0.into_alloy(), sell_amount, &pre_interactions) .await; match result { Err(err) => { diff --git a/crates/orderbook/src/run.rs b/crates/orderbook/src/run.rs index 272a24c12d..71683dca50 100644 --- a/crates/orderbook/src/run.rs +++ b/crates/orderbook/src/run.rs @@ -101,7 +101,7 @@ pub async fn run(args: Arguments) { } let settlement_contract = match args.shared.settlement_contract_address { - Some(address) => GPv2Settlement::Instance::new(address.into_alloy(), web3.alloy.clone()), + Some(address) => GPv2Settlement::Instance::new(address, web3.alloy.clone()), None => GPv2Settlement::Instance::deployed(&web3.alloy) .await .expect("load settlement contract"), @@ -118,10 +118,9 @@ pub async fn run(args: Arguments) { .await .expect("Couldn't get vault relayer address"); let signatures_contract = match args.shared.signatures_contract_address { - Some(address) => contracts::alloy::support::Signatures::Instance::new( - address.into_alloy(), - web3.alloy.clone(), - ), + Some(address) => { + contracts::alloy::support::Signatures::Instance::new(address, web3.alloy.clone()) + } None => contracts::alloy::support::Signatures::Instance::deployed(&web3.alloy) .await .expect("load signatures contract"), @@ -163,7 +162,7 @@ pub async fn run(args: Arguments) { vault_address.map(|address| BalancerV2Vault::Instance::new(address, web3.alloy.clone())); let hooks_contract = match args.shared.hooks_contract_address { - Some(address) => HooksTrampoline::Instance::new(address.into_alloy(), web3.alloy.clone()), + Some(address) => HooksTrampoline::Instance::new(address, web3.alloy.clone()), None => HooksTrampoline::Instance::deployed(&web3.alloy) .await .expect("load hooks trampoline contract"), @@ -227,11 +226,11 @@ pub async fn run(args: Arguments) { .await; let base_tokens = Arc::new(BaseTokens::new( - native_token.address().into_legacy(), + *native_token.address(), &args.shared.base_tokens, )); let mut allowed_tokens = args.allowed_tokens.clone(); - allowed_tokens.extend(base_tokens.tokens().iter().map(|t| t.into_alloy())); + allowed_tokens.extend(base_tokens.tokens().iter()); allowed_tokens.push(BUY_ETH_ADDRESS.into_alloy()); let unsupported_tokens = args.unsupported_tokens.clone(); @@ -249,7 +248,7 @@ pub async fn run(args: Arguments) { vault.as_ref(), uniswapv3_factory.as_ref(), &base_tokens, - settlement_contract.address().into_legacy(), + *settlement_contract.address(), ) .await .expect("failed to initialize token owner finders"); @@ -263,7 +262,7 @@ pub async fn run(args: Arguments) { tracing_node_url, "trace", ), - settlement_contract.address().into_legacy(), + *settlement_contract.address(), finder, )), args.shared.token_quality_cache_expiry, diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index cb5cee77c4..e34b048538 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -61,14 +61,15 @@ web3 = { workspace = true } mockall = { workspace = true, optional = true } [dev-dependencies] +alloy = { workspace = true, features = ["rand"] } +app-data = { workspace = true, features = ["test_helpers"] } async-stream = { workspace = true } ethcontract-mock = { workspace = true } +ethrpc = { workspace = true, features = ["test-util"] } +mockall = { workspace = true } regex = { workspace = true } testlib = { workspace = true } -app-data = { workspace = true, features = ["test_helpers"] } tokio = { workspace = true, features = ["rt-multi-thread"] } -mockall = { workspace = true } -ethrpc = {workspace = true, features = ["test-util"]} [features] test-util = ["dep:mockall"] diff --git a/crates/shared/src/arguments.rs b/crates/shared/src/arguments.rs index ac8fa00b8b..31d551bc22 100644 --- a/crates/shared/src/arguments.rs +++ b/crates/shared/src/arguments.rs @@ -12,9 +12,7 @@ use { tenderly_api, }, alloy::primitives::Address, - anyhow::{Context, Result, ensure}, - bigdecimal::BigDecimal, - ethcontract::{H160, U256}, + anyhow::{Result, ensure}, observe::TracingConfig, std::{ fmt::{self, Display, Formatter}, @@ -182,7 +180,7 @@ pub struct Arguments { /// Base tokens used for finding multi-hop paths between multiple AMMs /// Should be the most liquid tokens of the given network. #[clap(long, env, use_value_delimiter = true)] - pub base_tokens: Vec, + pub base_tokens: Vec
, /// Which Liquidity sources to be used by Price Estimator. #[clap(long, env, value_enum, ignore_case = true, use_value_delimiter = true)] @@ -249,7 +247,7 @@ pub struct Arguments { /// Override address of the settlement contract. #[clap(long, env)] - pub settlement_contract_address: Option, + pub settlement_contract_address: Option
, /// Override address of the Balances contract. #[clap(long, env)] @@ -257,7 +255,7 @@ pub struct Arguments { /// Override address of the Signatures contract. #[clap(long, env)] - pub signatures_contract_address: Option, + pub signatures_contract_address: Option
, /// Override address of the settlement contract. #[clap(long, env)] @@ -267,7 +265,7 @@ pub struct Arguments { /// trampolining custom order interactions. If not specified, the default /// contract deployment for the current network will be used. #[clap(long, env)] - pub hooks_contract_address: Option, + pub hooks_contract_address: Option
, /// Override address of the balancer vault contract. #[clap(long, env)] @@ -498,23 +496,6 @@ impl Display for ExternalSolver { } } -pub fn parse_percentage_factor(s: &str) -> Result { - let percentage_factor = f64::from_str(s)?; - ensure!(percentage_factor.is_finite() && (0. ..=1.0).contains(&percentage_factor)); - Ok(percentage_factor) -} - -pub fn wei_from_ether(s: &str) -> anyhow::Result { - let in_ether = s.parse::()?; - let base = BigDecimal::new(1.into(), -18); - number::conversions::big_decimal_to_u256(&(in_ether * base)).context("invalid Ether value") -} - -pub fn wei_from_gwei(s: &str) -> anyhow::Result { - let in_gwei: f64 = s.parse()?; - Ok(in_gwei * 1e9) -} - impl FromStr for ExternalSolver { type Err = anyhow::Error; diff --git a/crates/shared/src/bad_token/token_owner_finder/blockscout.rs b/crates/shared/src/bad_token/token_owner_finder/blockscout.rs index 9dec687e05..dacd5fd0d1 100644 --- a/crates/shared/src/bad_token/token_owner_finder/blockscout.rs +++ b/crates/shared/src/bad_token/token_owner_finder/blockscout.rs @@ -1,8 +1,8 @@ use { super::TokenOwnerProposing, + alloy::primitives::Address, anyhow::Result, chain::Chain, - ethcontract::H160, prometheus::IntCounterVec, prometheus_metric_storage::MetricStorage, rate_limit::{RateLimiter, Strategy, back_off}, @@ -55,7 +55,7 @@ impl BlockscoutTokenOwnerFinder { self } - async fn query_owners(&self, token: H160) -> Result> { + async fn query_owners(&self, token: Address) -> Result> { let mut url = self.base.clone(); url.query_pairs_mut() .append_pair("module", "token") @@ -101,7 +101,7 @@ struct Response { #[derive(Deserialize)] struct TokenOwner { - address: H160, + address: Address, } #[derive(MetricStorage, Clone, Debug)] @@ -114,7 +114,7 @@ struct Metrics { #[async_trait::async_trait] impl TokenOwnerProposing for BlockscoutTokenOwnerFinder { - async fn find_candidate_owners(&self, token: H160) -> Result> { + async fn find_candidate_owners(&self, token: Address) -> Result> { let metric = &Metrics::instance(observe::metrics::get_storage_registry()) .unwrap() .results; @@ -135,7 +135,7 @@ impl TokenOwnerProposing for BlockscoutTokenOwnerFinder { #[cfg(test)] mod tests { - use {super::*, hex_literal::hex}; + use {super::*, alloy::primitives::address}; #[tokio::test] #[ignore] @@ -143,7 +143,7 @@ mod tests { let finder = BlockscoutTokenOwnerFinder::with_network(Client::default(), &Chain::Mainnet).unwrap(); let owners = finder - .find_candidate_owners(H160(hex!("1337BedC9D22ecbe766dF105c9623922A27963EC"))) + .find_candidate_owners(address!("1337BedC9D22ecbe766dF105c9623922A27963EC")) .await; assert!(!owners.unwrap().is_empty()); } @@ -154,7 +154,7 @@ mod tests { let finder = BlockscoutTokenOwnerFinder::with_network(Client::default(), &Chain::Gnosis).unwrap(); let owners = finder - .find_candidate_owners(H160(hex!("1337BedC9D22ecbe766dF105c9623922A27963EC"))) + .find_candidate_owners(address!("1337BedC9D22ecbe766dF105c9623922A27963EC")) .await; assert!(!owners.unwrap().is_empty()); } @@ -165,7 +165,7 @@ mod tests { let finder = BlockscoutTokenOwnerFinder::with_network(Client::default(), &Chain::Gnosis).unwrap(); let owners = finder - .find_candidate_owners(H160(hex!("000000000000000000000000000000000000def1"))) + .find_candidate_owners(address!("000000000000000000000000000000000000def1")) .await; assert!(owners.unwrap().is_empty()); } diff --git a/crates/shared/src/bad_token/token_owner_finder/ethplorer.rs b/crates/shared/src/bad_token/token_owner_finder/ethplorer.rs index 1bf6f90ae7..7aa37517e4 100644 --- a/crates/shared/src/bad_token/token_owner_finder/ethplorer.rs +++ b/crates/shared/src/bad_token/token_owner_finder/ethplorer.rs @@ -1,8 +1,8 @@ use { super::TokenOwnerProposing, + alloy::primitives::Address, anyhow::{Result, ensure}, chain::Chain, - ethcontract::H160, prometheus::IntCounterVec, prometheus_metric_storage::MetricStorage, rate_limit::{RateLimiter, Strategy, back_off}, @@ -54,7 +54,7 @@ impl EthplorerTokenOwnerFinder { self } - async fn query_owners(&self, token: H160) -> Result> { + async fn query_owners(&self, token: Address) -> Result> { let mut url = crate::url::join(&self.base, &format!("getTopTokenHolders/{token:?}")); // We technically only need one candidate, returning the top 2 in case there // is a race condition and tokens have just been transferred out. @@ -104,7 +104,7 @@ struct Response { #[derive(Deserialize)] struct Holder { - address: H160, + address: Address, } #[derive(Deserialize)] @@ -134,7 +134,7 @@ struct Metrics { #[async_trait::async_trait] impl TokenOwnerProposing for EthplorerTokenOwnerFinder { - async fn find_candidate_owners(&self, token: H160) -> Result> { + async fn find_candidate_owners(&self, token: Address) -> Result> { let metric = &self.metrics.results; let result = self.query_owners(token).await; match &result { @@ -151,7 +151,7 @@ impl TokenOwnerProposing for EthplorerTokenOwnerFinder { #[cfg(test)] mod tests { - use {super::*, hex_literal::hex}; + use {super::*, alloy::primitives::address}; #[tokio::test] #[ignore] @@ -160,7 +160,7 @@ mod tests { EthplorerTokenOwnerFinder::try_with_network(Client::default(), None, &Chain::Mainnet) .unwrap(); let owners = finder - .find_candidate_owners(H160(hex!("1337BedC9D22ecbe766dF105c9623922A27963EC"))) + .find_candidate_owners(address!("1337BedC9D22ecbe766dF105c9623922A27963EC")) .await; assert!(!owners.unwrap().is_empty()); } @@ -172,7 +172,7 @@ mod tests { EthplorerTokenOwnerFinder::try_with_network(Client::default(), None, &Chain::Gnosis) .unwrap(); let owners = finder - .find_candidate_owners(H160(hex!("000000000000000000000000000000000000def1"))) + .find_candidate_owners(address!("000000000000000000000000000000000000def1")) .await; assert!(owners.unwrap().is_empty()); } diff --git a/crates/shared/src/bad_token/token_owner_finder/liquidity.rs b/crates/shared/src/bad_token/token_owner_finder/liquidity.rs index 34a633821e..a055df1de4 100644 --- a/crates/shared/src/bad_token/token_owner_finder/liquidity.rs +++ b/crates/shared/src/bad_token/token_owner_finder/liquidity.rs @@ -3,26 +3,24 @@ use { super::TokenOwnerProposing, crate::sources::{uniswap_v2::pair_provider::PairProvider, uniswap_v3_pair_provider}, - alloy::eips::BlockNumberOrTag, + alloy::{eips::BlockNumberOrTag, primitives::Address}, anyhow::Result, contracts::alloy::{BalancerV2Vault, IUniswapV3Factory}, - ethcontract::H160, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, model::TokenPair, }; pub struct UniswapLikePairProviderFinder { pub inner: PairProvider, - pub base_tokens: Vec, + pub base_tokens: Vec
, } #[async_trait::async_trait] impl TokenOwnerProposing for UniswapLikePairProviderFinder { - async fn find_candidate_owners(&self, token: H160) -> Result> { + async fn find_candidate_owners(&self, token: Address) -> Result> { Ok(self .base_tokens .iter() - .filter_map(|base_token| TokenPair::new(base_token.into_alloy(), token.into_alloy())) + .filter_map(|base_token| TokenPair::new(*base_token, token)) .map(|pair| self.inner.pair_address(&pair)) .collect()) } @@ -33,14 +31,14 @@ pub struct BalancerVaultFinder(pub BalancerV2Vault::Instance); #[async_trait::async_trait] impl TokenOwnerProposing for BalancerVaultFinder { - async fn find_candidate_owners(&self, _: H160) -> Result> { - Ok(vec![self.0.address().into_legacy()]) + async fn find_candidate_owners(&self, _: Address) -> Result> { + Ok(vec![*self.0.address()]) } } pub struct UniswapV3Finder { pub factory: IUniswapV3Factory::Instance, - pub base_tokens: Vec, + pub base_tokens: Vec
, fee_values: Vec, } @@ -57,7 +55,7 @@ pub enum FeeValues { impl UniswapV3Finder { pub async fn new( factory: IUniswapV3Factory::Instance, - base_tokens: Vec, + base_tokens: Vec
, fee_values: FeeValues, ) -> Result { let fee_values = match fee_values { @@ -101,18 +99,14 @@ impl UniswapV3Finder { #[async_trait::async_trait] impl TokenOwnerProposing for UniswapV3Finder { - async fn find_candidate_owners(&self, token: H160) -> Result> { + async fn find_candidate_owners(&self, token: Address) -> Result> { Ok(self .base_tokens .iter() - .filter_map(|base_token| TokenPair::new(base_token.into_alloy(), token.into_alloy())) + .filter_map(|base_token| TokenPair::new(*base_token, token)) .flat_map(|pair| self.fee_values.iter().map(move |fee| (pair, *fee))) .map(|(pair, fee)| { - uniswap_v3_pair_provider::pair_address( - &self.factory.address().into_legacy(), - &pair, - fee, - ) + uniswap_v3_pair_provider::pair_address(self.factory.address(), &pair, fee) }) .collect()) } diff --git a/crates/shared/src/bad_token/token_owner_finder/mod.rs b/crates/shared/src/bad_token/token_owner_finder/mod.rs index 9282789fb3..5aeb44aa4f 100644 --- a/crates/shared/src/bad_token/token_owner_finder/mod.rs +++ b/crates/shared/src/bad_token/token_owner_finder/mod.rs @@ -29,6 +29,7 @@ use { http_client::HttpClientFactory, sources::uniswap_v2::pair_provider::PairProvider, }, + alloy::primitives::Address, anyhow::{Context, Result}, chain::Chain, contracts::alloy::{BalancerV2Vault, ERC20, IUniswapV3Factory}, @@ -38,7 +39,6 @@ use { errors::ContractErrorExt, }, futures::{Stream, StreamExt as _}, - primitive_types::H160, rate_limit::Strategy, reqwest::Url, std::{ @@ -54,7 +54,7 @@ use { #[async_trait::async_trait] pub trait TokenOwnerProposing: Send + Sync { /// Find candidate addresses that might own the token. - async fn find_candidate_owners(&self, token: H160) -> Result>; + async fn find_candidate_owners(&self, token: Address) -> Result>; } /// To detect bad tokens we need to find some address on the network that owns @@ -63,7 +63,11 @@ pub trait TokenOwnerProposing: Send + Sync { pub trait TokenOwnerFinding: Send + Sync { /// Find an addresses with at least `min_balance` of tokens and return it, /// along with its actual balance. - async fn find_owner(&self, token: H160, min_balance: U256) -> Result>; + async fn find_owner( + &self, + token: Address, + min_balance: U256, + ) -> Result>; } /// Arguments related to the token owner finder. @@ -100,7 +104,7 @@ pub struct Arguments { value_parser = parse_owners, default_value = "", )] - pub whitelisted_owners: HashMap>, + pub whitelisted_owners: HashMap>, /// The solvers urls to query the token owner pairs. #[clap(long, env, use_value_delimiter = true)] @@ -153,7 +157,7 @@ pub struct Ethplorer { pub ethplorer_api_key: String, } -fn parse_owners(s: &str) -> Result>> { +fn parse_owners(s: &str) -> Result>> { if s.is_empty() { return Ok(Default::default()); } @@ -291,7 +295,7 @@ pub async fn init( vault: Option<&BalancerV2Vault::Instance>, uniswapv3_factory: Option<&IUniswapV3Factory::Instance>, base_tokens: &BaseTokens, - settlement_contract: H160, + settlement_contract: Address, ) -> Result> { let web3 = ethrpc::instrumented::instrument_with_label(&web3, "tokenOwners".into()); let finders = args @@ -392,12 +396,12 @@ pub async fn init( pub struct TokenOwnerFinder { pub web3: Web3, pub proposers: Vec>, - pub settlement_contract: H160, + pub settlement_contract: Address, } impl TokenOwnerFinder { /// Stream of addresses that might own the token. - fn candidate_owners(&self, token: H160) -> impl Stream + '_ { + fn candidate_owners(&self, token: Address) -> impl Stream + '_ { // Combine the results of all finders into a single stream. let streams = self.proposers.iter().map(|finder| { futures::stream::once(finder.find_candidate_owners(token)) @@ -419,8 +423,12 @@ impl TokenOwnerFinder { #[async_trait::async_trait] impl TokenOwnerFinding for TokenOwnerFinder { - async fn find_owner(&self, token: H160, min_balance: U256) -> Result> { - let instance = ERC20::Instance::new(token.into_alloy(), self.web3.alloy.clone()); + async fn find_owner( + &self, + token: Address, + min_balance: U256, + ) -> Result> { + let instance = ERC20::Instance::new(token, self.web3.alloy.clone()); // We use a stream with ready_chunks so that we can start with the addresses of // fast TokenOwnerFinding implementations first without having to wait @@ -435,7 +443,7 @@ impl TokenOwnerFinding for TokenOwnerFinder { // owner is not the settlement contract. .filter(|owner| *owner != self.settlement_contract) .map(|owner| { - let balance = instance.balanceOf(owner.into_alloy()); + let balance = instance.balanceOf(owner); async move { match balance.call().await { Ok(balance) => Ok((owner, balance)), @@ -462,12 +470,12 @@ impl TokenOwnerFinding for TokenOwnerFinder { #[cfg(test)] mod test { - use {super::*, clap::Parser}; + use {super::*, alloy::primitives::address, clap::Parser}; - const TOKEN1: H160 = addr!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); - const TOKEN2: H160 = addr!("7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"); - const OWNER1: H160 = addr!("06920c9fc643de77b99cb7670a944ad31eaaa260"); - const OWNER2: H160 = addr!("06601571aa9d3e8f5f7cdd5b993192618964bab5"); + const TOKEN1: Address = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"); + const TOKEN2: Address = address!("7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"); + const OWNER1: Address = address!("06920c9fc643de77b99cb7670a944ad31eaaa260"); + const OWNER2: Address = address!("06601571aa9d3e8f5f7cdd5b993192618964bab5"); #[test] fn parse_owners_empty() { diff --git a/crates/shared/src/bad_token/token_owner_finder/solvers/mod.rs b/crates/shared/src/bad_token/token_owner_finder/solvers/mod.rs index 5b1ab4983b..1b153c56a7 100644 --- a/crates/shared/src/bad_token/token_owner_finder/solvers/mod.rs +++ b/crates/shared/src/bad_token/token_owner_finder/solvers/mod.rs @@ -1,10 +1,10 @@ pub mod solver_api; pub mod solver_finder; -use {anyhow::Result, ethcontract::H160, std::collections::HashMap}; +use {alloy::primitives::Address, anyhow::Result, std::collections::HashMap}; -type Token = H160; -type Owner = H160; +type Token = Address; +type Owner = Address; #[async_trait::async_trait] pub trait TokenOwnerSolverApi: Send + Sync { diff --git a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_api.rs b/crates/shared/src/bad_token/token_owner_finder/solvers/solver_api.rs index d034c5ffe3..a14fa46537 100644 --- a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_api.rs +++ b/crates/shared/src/bad_token/token_owner_finder/solvers/solver_api.rs @@ -1,13 +1,13 @@ use { super::TokenOwnerSolverApi, + alloy::primitives::Address, anyhow::{Context, Result}, - ethcontract::H160, reqwest::{Client, Url}, std::collections::HashMap, }; -type Token = H160; -type Owner = H160; +type Token = Address; +type Owner = Address; #[derive(Clone, Debug)] pub struct SolverConfiguration { diff --git a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_finder.rs b/crates/shared/src/bad_token/token_owner_finder/solvers/solver_finder.rs index 7ad7aee2b2..a88ed4822f 100644 --- a/crates/shared/src/bad_token/token_owner_finder/solvers/solver_finder.rs +++ b/crates/shared/src/bad_token/token_owner_finder/solvers/solver_finder.rs @@ -1,8 +1,8 @@ use { super::TokenOwnerSolverApi, crate::bad_token::token_owner_finder::TokenOwnerProposing, + alloy::primitives::Address, anyhow::Result, - ethcontract::H160, prometheus::{ IntCounterVec, core::{AtomicU64, GenericCounter}, @@ -16,8 +16,8 @@ use { tracing::Instrument, }; -type Token = H160; -type Owner = H160; +type Token = Address; +type Owner = Address; #[derive(Debug)] pub struct AutoUpdatingSolverTokenOwnerFinder { @@ -126,6 +126,7 @@ mod tests { use { super::*, crate::bad_token::token_owner_finder::solvers::solver_api::SolverConfiguration, + alloy::primitives::address, reqwest::{Client, Url}, std::str::FromStr, }; @@ -145,7 +146,7 @@ mod tests { ); tokio::time::sleep(Duration::from_secs(10)).await; let owners = finder - .find_candidate_owners(addr!("132d8D2C76Db3812403431fAcB00F3453Fc42125")) + .find_candidate_owners(address!("132d8D2C76Db3812403431fAcB00F3453Fc42125")) .await .unwrap(); dbg!(owners); diff --git a/crates/shared/src/bad_token/token_owner_finder/token_owner_list.rs b/crates/shared/src/bad_token/token_owner_finder/token_owner_list.rs index 75eb953ea7..a1490661fe 100644 --- a/crates/shared/src/bad_token/token_owner_finder/token_owner_list.rs +++ b/crates/shared/src/bad_token/token_owner_finder/token_owner_list.rs @@ -1,7 +1,12 @@ -use {super::TokenOwnerProposing, anyhow::Result, ethcontract::H160, std::collections::HashMap}; +use { + super::TokenOwnerProposing, + alloy::primitives::Address, + anyhow::Result, + std::collections::HashMap, +}; -type Token = H160; -type Owner = H160; +type Token = Address; +type Owner = Address; pub struct TokenOwnerList { owners: HashMap>, @@ -15,7 +20,7 @@ impl TokenOwnerList { #[async_trait::async_trait] impl TokenOwnerProposing for TokenOwnerList { - async fn find_candidate_owners(&self, token: H160) -> Result> { + async fn find_candidate_owners(&self, token: Address) -> Result> { Ok(self.owners.get(&token).cloned().unwrap_or_default()) } } @@ -28,18 +33,18 @@ mod tests { async fn token_owner_list_constructor_empty() { let finder = TokenOwnerList::new(Default::default()); let candidate_owners = finder - .find_candidate_owners(H160::from_low_u64_be(10)) + .find_candidate_owners(Address::with_last_byte(10)) .await; assert!(candidate_owners.unwrap().is_empty()); } #[tokio::test] async fn token_owner_list_constructor() { - let token = H160::from_low_u64_be(1); - let owners = vec![H160::from_low_u64_be(2), H160::from_low_u64_be(3)]; + let token = Address::with_last_byte(1); + let owners = vec![Address::with_last_byte(2), Address::with_last_byte(3)]; let finder = TokenOwnerList::new(HashMap::from([(token, owners.clone())])); let candidate_owners = finder - .find_candidate_owners(H160::from_low_u64_be(1)) + .find_candidate_owners(Address::with_last_byte(1)) .await .unwrap(); assert_eq!(owners, candidate_owners); diff --git a/crates/shared/src/bad_token/trace_call.rs b/crates/shared/src/bad_token/trace_call.rs index 7d92ec9df5..a10871760c 100644 --- a/crates/shared/src/bad_token/trace_call.rs +++ b/crates/shared/src/bad_token/trace_call.rs @@ -40,7 +40,7 @@ impl BadTokenDetecting for TraceCallDetector { } impl TraceCallDetector { - pub fn new(web3: Web3, settlement: H160, finder: Arc) -> Self { + pub fn new(web3: Web3, settlement: Address, finder: Arc) -> Self { Self { inner: TraceCallDetectorRaw::new(web3, settlement), finder, @@ -53,7 +53,7 @@ impl TraceCallDetector { const MIN_AMOUNT: u64 = 100_000; let (take_from, amount) = match self .finder - .find_owner(token.into_legacy(), MIN_AMOUNT.into()) + .find_owner(token, MIN_AMOUNT.into()) .await .context("find_owner")? { @@ -79,7 +79,7 @@ impl TraceCallDetector { } }; self.inner - .test_transfer(take_from, token.into_legacy(), amount, &[]) + .test_transfer(take_from, token, amount, &[]) .await } } @@ -89,11 +89,11 @@ impl TraceCallDetector { #[derive(Debug, Clone)] pub struct TraceCallDetectorRaw { pub web3: Web3, - pub settlement_contract: H160, + pub settlement_contract: Address, } impl TraceCallDetectorRaw { - pub fn new(web3: Web3, settlement: H160) -> Self { + pub fn new(web3: Web3, settlement: Address) -> Self { Self { web3, settlement_contract: settlement, @@ -102,8 +102,8 @@ impl TraceCallDetectorRaw { pub async fn test_transfer( &self, - take_from: H160, - token: H160, + take_from: Address, + token: Address, amount: U256, pre_interactions: &[InteractionData], ) -> Result { @@ -148,7 +148,7 @@ impl TraceCallDetectorRaw { } }; let relevant_traces = &traces[pre_interactions.len()..]; - Self::handle_response(relevant_traces, amount, take_from) + Self::handle_response(relevant_traces, amount, take_from.into_legacy()) } // For the out transfer we use an arbitrary address without balance to detect @@ -160,10 +160,15 @@ impl TraceCallDetectorRaw { .public_address() } - fn create_trace_request(&self, token: H160, amount: U256, take_from: H160) -> Vec { + fn create_trace_request( + &self, + token: Address, + amount: U256, + take_from: Address, + ) -> Vec { let mut requests = Vec::new(); let recipient = Self::arbitrary_recipient().into_alloy(); - let settlement_contract = self.settlement_contract.into_alloy(); + let settlement_contract = self.settlement_contract; // 0 let calldata = ERC20::ERC20::balanceOfCall { @@ -341,10 +346,11 @@ impl TraceCallDetectorRaw { } } -fn call_request(from: Option, to: H160, calldata: Vec) -> CallRequest { +fn call_request(from: Option
, to: Address, calldata: Vec) -> CallRequest { + // TODO(jose): figure out the proper mapping of this call request to alloy CallRequest { - from, - to: Some(to), + from: from.map(IntoLegacy::into_legacy), + to: Some(to.into_legacy()), data: Some(calldata.into()), ..Default::default() } @@ -400,7 +406,7 @@ mod tests { alloy::primitives::address, chain::Chain, contracts::alloy::{BalancerV2Vault, GPv2Settlement, IUniswapV3Factory}, - ethrpc::{Web3, alloy::conversions::IntoLegacy}, + ethrpc::Web3, std::{env, time::Duration}, web3::types::{ Action, @@ -727,7 +733,7 @@ mod tests { .unwrap(); let finder = Arc::new(TokenOwnerFinder { web3: web3.clone(), - settlement_contract: settlement.address().into_legacy(), + settlement_contract: *settlement.address(), proposers: vec![ Arc::new(UniswapLikePairProviderFinder { inner: uniswap_v2::UniV2BaselineSourceParameters::from_baseline_source( @@ -739,10 +745,7 @@ mod tests { .await .unwrap() .pair_provider, - base_tokens: base_tokens - .iter() - .map(|token| token.into_legacy()) - .collect::>(), + base_tokens: base_tokens.to_vec(), }), Arc::new(UniswapLikePairProviderFinder { inner: uniswap_v2::UniV2BaselineSourceParameters::from_baseline_source( @@ -754,10 +757,7 @@ mod tests { .await .unwrap() .pair_provider, - base_tokens: base_tokens - .iter() - .map(|token| token.into_legacy()) - .collect::>(), + base_tokens: base_tokens.to_vec(), }), Arc::new(BalancerVaultFinder( BalancerV2Vault::Instance::deployed(&web3.alloy) @@ -769,10 +769,7 @@ mod tests { IUniswapV3Factory::Instance::deployed(&web3.alloy) .await .unwrap(), - base_tokens - .iter() - .map(|token| token.into_legacy()) - .collect::>(), + base_tokens.to_vec(), FeeValues::Static, ) .await @@ -787,7 +784,7 @@ mod tests { ), ], }); - let token_cache = TraceCallDetector::new(web3, settlement.address().into_legacy(), finder); + let token_cache = TraceCallDetector::new(web3, *settlement.address(), finder); println!("testing good tokens"); for &token in base_tokens { @@ -807,7 +804,7 @@ mod tests { async fn mainnet_univ3() { observe::tracing::initialize(&observe::Config::default().with_env_filter("shared=debug")); let web3 = Web3::new_from_env(); - let base_tokens = vec![testlib::tokens::WETH.into_legacy()]; + let base_tokens = vec![testlib::tokens::WETH]; let settlement = GPv2Settlement::Instance::deployed(&web3.alloy) .await .unwrap(); @@ -821,10 +818,10 @@ mod tests { ); let finder = Arc::new(TokenOwnerFinder { web3: web3.clone(), - settlement_contract: settlement.address().into_legacy(), + settlement_contract: *settlement.address(), proposers: vec![univ3], }); - let token_cache = TraceCallDetector::new(web3, settlement.address().into_legacy(), finder); + let token_cache = TraceCallDetector::new(web3, *settlement.address(), finder); let result = token_cache.detect(testlib::tokens::USDC).await; dbg!(&result); @@ -945,9 +942,9 @@ mod tests { let finder = Arc::new(TokenOwnerFinder { web3: web3.clone(), proposers: vec![solver_token_finder], - settlement_contract: settlement.address().into_legacy(), + settlement_contract: *settlement.address(), }); - let token_cache = TraceCallDetector::new(web3, settlement.address().into_legacy(), finder); + let token_cache = TraceCallDetector::new(web3, *settlement.address(), finder); for token in tokens { let result = token_cache.detect(token).await; diff --git a/crates/shared/src/baseline_solver.rs b/crates/shared/src/baseline_solver.rs index d6614f366b..38aac8b0ad 100644 --- a/crates/shared/src/baseline_solver.rs +++ b/crates/shared/src/baseline_solver.rs @@ -2,8 +2,8 @@ //! onchain liquidity. use { - ethcontract::{H160, U256}, - ethrpc::alloy::conversions::IntoAlloy, + alloy::primitives::Address, + ethcontract::U256, model::TokenPair, std::collections::{HashMap, HashSet}, }; @@ -11,7 +11,7 @@ use { /// The maximum number of hops to use when trading with AMMs along a path. const DEFAULT_MAX_HOPS: usize = 2; -type PathCandidate = Vec; +type PathCandidate = Vec
; /// Note that get_amount_out and get_amount_in are not always symmetrical. That /// is for some AMMs it is possible that get_amount_out returns an amount for @@ -24,16 +24,16 @@ pub trait BaselineSolvable { /// expected amount of output token. fn get_amount_out( &self, - out_token: H160, - input: (U256, H160), + out_token: Address, + input: (U256, Address), ) -> impl Future> + Send; /// Given the input token, the amount and token we want output, return the /// required amount of input token that needs to be provided. fn get_amount_in( &self, - in_token: H160, - out: (U256, H160), + in_token: Address, + out: (U256, Address), ) -> impl Future> + Send; /// Returns the approximate amount of gas that using this piece of liquidity @@ -65,7 +65,7 @@ impl Estimate<'_, V, L> { // result Returns None if the path is invalid or pool information doesn't exist. pub async fn estimate_buy_amount<'a, L: BaselineSolvable>( sell_amount: U256, - path: &[H160], + path: &[Address], liquidity: &'a HashMap>, ) -> Option> { let sell_token = path.first()?; @@ -74,10 +74,7 @@ pub async fn estimate_buy_amount<'a, L: BaselineSolvable>( for current in path.iter().skip(1) { let (amount, previous_token, mut path) = previous; - let pools = liquidity.get(&TokenPair::new( - current.into_alloy(), - previous_token.into_alloy(), - )?)?; + let pools = liquidity.get(&TokenPair::new(*current, previous_token)?)?; let outputs = futures::future::join_all(pools.iter().map(|liquidity| async move { let output = liquidity .get_amount_out(*current, (amount, previous_token)) @@ -105,7 +102,7 @@ pub async fn estimate_buy_amount<'a, L: BaselineSolvable>( // result Returns None if the path is invalid or pool information doesn't exist. pub async fn estimate_sell_amount<'a, L: BaselineSolvable>( buy_amount: U256, - path: &[H160], + path: &[Address], liquidity: &'a HashMap>, ) -> Option> { let buy_token = path.last()?; @@ -114,10 +111,7 @@ pub async fn estimate_sell_amount<'a, L: BaselineSolvable>( for current in path.iter().rev().skip(1) { let (amount, previous_token, mut path) = previous; - let pools = liquidity.get(&TokenPair::new( - current.into_alloy(), - previous_token.into_alloy(), - )?)?; + let pools = liquidity.get(&TokenPair::new(*current, previous_token)?)?; let outputs = futures::future::join_all(pools.iter().map(|liquidity| async move { let output = liquidity .get_amount_in(*current, (amount, previous_token)) @@ -148,13 +142,13 @@ pub struct BaseTokens { /// solver. /// /// Always includes the native token. - tokens: HashSet, + tokens: HashSet
, /// All pairs of above. pairs: HashSet, } impl BaseTokens { - pub fn new(native_token: H160, base_tokens: &[H160]) -> Self { + pub fn new(native_token: Address, base_tokens: &[Address]) -> Self { let mut tokens = base_tokens.to_vec(); tokens.push(native_token); tokens.sort(); @@ -166,7 +160,7 @@ impl BaseTokens { } } - pub fn tokens(&self) -> &HashSet { + pub fn tokens(&self) -> &HashSet
{ &self.tokens } @@ -180,8 +174,7 @@ impl BaseTokens { result.extend( self.tokens .iter() - .map(|base_token| base_token.into_alloy()) - .filter_map(move |base_token| TokenPair::new(base_token, token)), + .filter_map(move |base_token| TokenPair::new(*base_token, token)), ); } } @@ -197,7 +190,11 @@ impl BaseTokens { // potential intermediate base tokens and a maximum number of intermediate // steps. Can contain token pairs between base tokens or a base token and // the sell or buy token. - pub fn path_candidates(&self, sell_token: H160, buy_token: H160) -> HashSet { + pub fn path_candidates( + &self, + sell_token: Address, + buy_token: Address, + ) -> HashSet { self.path_candidates_with_hops(sell_token, buy_token, DEFAULT_MAX_HOPS) } @@ -205,8 +202,8 @@ impl BaseTokens { /// hops. pub fn path_candidates_with_hops( &self, - sell_token: H160, - buy_token: H160, + sell_token: Address, + buy_token: Address, max_hops: usize, ) -> HashSet { path_candidates(sell_token, buy_token, &self.tokens, max_hops) @@ -214,9 +211,9 @@ impl BaseTokens { } fn path_candidates( - sell_token: H160, - buy_token: H160, - base_tokens: &HashSet, + sell_token: Address, + buy_token: Address, + base_tokens: &HashSet
, max_hops: usize, ) -> HashSet { if sell_token == buy_token { @@ -252,7 +249,7 @@ fn path_candidates( } /// All token pairs between base tokens. -fn base_token_pairs(base_tokens: &[H160]) -> impl Iterator + '_ { +fn base_token_pairs(base_tokens: &[Address]) -> impl Iterator + '_ { base_tokens .iter() .copied() @@ -262,7 +259,7 @@ fn base_token_pairs(base_tokens: &[H160]) -> impl Iterator + ' .iter() .copied() .skip(index) - .filter_map(move |token_| TokenPair::new(token.into_alloy(), token_.into_alloy())) + .filter_map(move |token_| TokenPair::new(token, token_)) }) } @@ -271,16 +268,15 @@ mod tests { use { super::*, crate::sources::uniswap_v2::pool_fetching::Pool, - ethcontract::H160, maplit::{hashmap, hashset}, model::TokenPair, }; #[test] fn path_candidates_empty_when_same_token() { - let base = BaseTokens::new(H160::from_low_u64_be(0), &[H160::from_low_u64_be(1)]); - let sell_token = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(2); + let base = BaseTokens::new(Address::with_last_byte(0), &[Address::with_last_byte(1)]); + let sell_token = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(2); assert!(base.path_candidates(sell_token, buy_token).is_empty()); } @@ -288,14 +284,14 @@ mod tests { #[test] fn test_path_candidates() { let base_tokens = [ - H160::from_low_u64_be(0), - H160::from_low_u64_be(1), - H160::from_low_u64_be(2), + Address::with_last_byte(0), + Address::with_last_byte(1), + Address::with_last_byte(2), ]; - let base_token_set: HashSet = base_tokens.iter().copied().collect(); + let base_token_set: HashSet
= base_tokens.iter().copied().collect(); - let sell_token = H160::from_low_u64_be(4); - let buy_token = H160::from_low_u64_be(5); + let sell_token = Address::with_last_byte(4); + let buy_token = Address::with_last_byte(5); // 0 hops assert_eq!( @@ -354,14 +350,14 @@ mod tests { #[tokio::test] async fn test_estimate_amount_returns_none_if_it_contains_pair_without_pool() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let path = vec![sell_token, intermediate, buy_token]; let pools = [Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(path[0], path[1]).unwrap(), (100, 100), )]; let pools = hashmap! { @@ -378,20 +374,20 @@ mod tests { #[tokio::test] async fn test_estimate_amount() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let path = vec![sell_token, intermediate, buy_token]; let pools = [ Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(path[0], path[1]).unwrap(), (100, 100), ), Pool::uniswap( - H160::from_low_u64_be(2), - TokenPair::new(path[1].into_alloy(), path[2].into_alloy()).unwrap(), + Address::with_last_byte(2), + TokenPair::new(path[1], path[2]).unwrap(), (200, 50), ), ]; @@ -419,20 +415,20 @@ mod tests { #[tokio::test] async fn test_estimate_sell_amount_returns_none_buying_too_much() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let path = vec![sell_token, intermediate, buy_token]; let pools = [ Pool::uniswap( - H160::from_low_u64_be(1), - TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(), + Address::with_last_byte(1), + TokenPair::new(path[0], path[1]).unwrap(), (100, 100), ), Pool::uniswap( - H160::from_low_u64_be(2), - TokenPair::new(path[1].into_alloy(), path[2].into_alloy()).unwrap(), + Address::with_last_byte(2), + TokenPair::new(path[1], path[2]).unwrap(), (200, 50), ), ]; @@ -450,22 +446,22 @@ mod tests { #[tokio::test] async fn test_estimate_amount_multiple_pools() { - let sell_token = H160::from_low_u64_be(1); - let intermediate = H160::from_low_u64_be(2); - let buy_token = H160::from_low_u64_be(3); + let sell_token = Address::with_last_byte(1); + let intermediate = Address::with_last_byte(2); + let buy_token = Address::with_last_byte(3); let mut path = vec![sell_token, intermediate, buy_token]; - let first_pair = TokenPair::new(path[0].into_alloy(), path[1].into_alloy()).unwrap(); - let second_pair = TokenPair::new(path[1].into_alloy(), path[2].into_alloy()).unwrap(); + let first_pair = TokenPair::new(path[0], path[1]).unwrap(); + let second_pair = TokenPair::new(path[1], path[2]).unwrap(); let first_hop_high_price = - Pool::uniswap(H160::from_low_u64_be(1), first_pair, (101_000, 100_000)); + Pool::uniswap(Address::with_last_byte(1), first_pair, (101_000, 100_000)); let first_hop_low_price = - Pool::uniswap(H160::from_low_u64_be(1), first_pair, (100_000, 101_000)); + Pool::uniswap(Address::with_last_byte(1), first_pair, (100_000, 101_000)); let second_hop_high_slippage = - Pool::uniswap(H160::from_low_u64_be(2), second_pair, (200_000, 50_000)); + Pool::uniswap(Address::with_last_byte(2), second_pair, (200_000, 50_000)); let second_hop_low_slippage = Pool::uniswap( - H160::from_low_u64_be(2), + Address::with_last_byte(2), second_pair, (200_000_000, 50_000_000), ); @@ -512,13 +508,13 @@ mod tests { #[tokio::test] async fn test_estimate_amount_invalid_pool() { - let sell_token = H160::from_low_u64_be(1); - let buy_token = H160::from_low_u64_be(2); - let pair = TokenPair::new(sell_token.into_alloy(), buy_token.into_alloy()).unwrap(); + let sell_token = Address::with_last_byte(1); + let buy_token = Address::with_last_byte(2); + let pair = TokenPair::new(sell_token, buy_token).unwrap(); let path = vec![sell_token, buy_token]; - let valid_pool = Pool::uniswap(H160::from_low_u64_be(1), pair, (100_000, 100_000)); - let invalid_pool = Pool::uniswap(H160::default(), pair, (0, 0)); + let valid_pool = Pool::uniswap(Address::with_last_byte(1), pair, (100_000, 100_000)); + let invalid_pool = Pool::uniswap(Default::default(), pair, (0, 0)); let pools = hashmap! { pair => vec![valid_pool, invalid_pool], }; @@ -536,72 +532,41 @@ mod tests { #[test] fn base_token_pairs_() { - let base_tokens: Vec = [0, 1, 2] + let base_tokens: Vec
= [0, 1, 2] .iter() .copied() - .map(H160::from_low_u64_le) + .map(Address::with_last_byte) .collect(); let pairs: Vec = base_token_pairs(&base_tokens).collect(); assert_eq!(pairs.len(), 3); - assert!(pairs.contains( - &TokenPair::new(base_tokens[0].into_alloy(), base_tokens[1].into_alloy()).unwrap() - )); - assert!(pairs.contains( - &TokenPair::new(base_tokens[0].into_alloy(), base_tokens[2].into_alloy()).unwrap() - )); - assert!(pairs.contains( - &TokenPair::new(base_tokens[1].into_alloy(), base_tokens[2].into_alloy()).unwrap() - )); + assert!(pairs.contains(&TokenPair::new(base_tokens[0], base_tokens[1]).unwrap())); + assert!(pairs.contains(&TokenPair::new(base_tokens[0], base_tokens[2]).unwrap())); + assert!(pairs.contains(&TokenPair::new(base_tokens[1], base_tokens[2]).unwrap())); } #[test] fn relevant_pairs() { - let tokens: Vec = [0, 1, 2, 3, 4] + let tokens: Vec
= [0, 1, 2, 3, 4] .iter() .copied() - .map(H160::from_low_u64_le) + .map(Address::with_last_byte) .collect(); let base = BaseTokens::new(tokens[0], &tokens[1..2]); let pairs = base.relevant_pairs(&mut std::iter::empty()); assert!(pairs.is_empty()); - let pairs = base.relevant_pairs( - &mut TokenPair::new(tokens[0].into_alloy(), tokens[1].into_alloy()).into_iter(), - ); + let pairs = base.relevant_pairs(&mut TokenPair::new(tokens[0], tokens[1]).into_iter()); assert_eq!(pairs.len(), 1); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[1].into_alloy()).unwrap()) - ); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[1]).unwrap())); - let pairs = base.relevant_pairs( - &mut TokenPair::new(tokens[3].into_alloy(), tokens[4].into_alloy()).into_iter(), - ); + let pairs = base.relevant_pairs(&mut TokenPair::new(tokens[3], tokens[4]).into_iter()); assert_eq!(pairs.len(), 6); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[1].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[3].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[0].into_alloy(), tokens[4].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[1].into_alloy(), tokens[3].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[1].into_alloy(), tokens[4].into_alloy()).unwrap()) - ); - assert!( - pairs - .contains(&TokenPair::new(tokens[3].into_alloy(), tokens[4].into_alloy()).unwrap()) - ); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[1]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[3]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[0], tokens[4]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[1], tokens[3]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[1], tokens[4]).unwrap())); + assert!(pairs.contains(&TokenPair::new(tokens[3], tokens[4]).unwrap())); } } diff --git a/crates/shared/src/external_prices.rs b/crates/shared/src/external_prices.rs index 77a08cd6d3..63da862b19 100644 --- a/crates/shared/src/external_prices.rs +++ b/crates/shared/src/external_prices.rs @@ -7,8 +7,9 @@ use { crate::conversions::U256Ext, + alloy::primitives::{Address, U256}, anyhow::{Result, bail}, - ethcontract::{H160, U256}, + ethrpc::alloy::conversions::IntoAlloy, model::order::BUY_ETH_ADDRESS, num::{BigInt, BigRational, One as _, ToPrimitive as _}, std::{ @@ -20,16 +21,19 @@ use { /// A collection of external prices used for converting token amounts to native /// assets. #[derive(Clone, Debug)] -pub struct ExternalPrices(HashMap); +pub struct ExternalPrices(HashMap); impl ExternalPrices { /// Creates a new set of external prices for the specified exchange rates. - pub fn try_new(native_token: H160, mut xrates: HashMap) -> Result { + pub fn try_new( + native_token: Address, + mut xrates: HashMap, + ) -> Result { // Make sure to verify our invariant that native asset price and native // 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] { + for token in [native_token, BUY_ETH_ADDRESS.into_alloy()] { match xrates.get(&token) { Some(price) if !price.is_one() => { let price = price.to_f64().unwrap_or(f64::NAN); @@ -47,8 +51,8 @@ impl ExternalPrices { /// Returns a set of external prices for the specified auction model prices. pub fn try_from_auction_prices( - native_token: H160, - prices: BTreeMap, + native_token: Address, + prices: BTreeMap, ) -> Result { Self::try_new( native_token, @@ -63,7 +67,7 @@ impl ExternalPrices { /// I.e., the price of the native token is 1 and /// the price of a token T is represented as how much native token // is needed in order to buy 1 atom of the token T - pub fn price(&self, token: &H160) -> Option<&BigRational> { + pub fn price(&self, token: &Address) -> Option<&BigRational> { self.0.get(token) } } @@ -103,7 +107,7 @@ mod tests { // GNO is typically traded at around Ξ0.1. With the price // representation we use here, this would be 1e17. - let gno_price = U256::from_f64_lossy(1e17); + let gno_price = U256::from(10).pow(U256::from(17)); let gno_xrate = to_native_xrate(gno_price); assert_eq!( gno_xrate, @@ -121,27 +125,27 @@ mod tests { #[test] fn augments_price_map_with_native_token_prices() { - let native_token = H160([42; 20]); + let native_token = Address::repeat_byte(42); assert_eq!( ExternalPrices::try_from_auction_prices( native_token, btreemap! { - H160([1; 20]) => U256::from(100_000_000_000_000_000_u128), + Address::repeat_byte(1) => U256::from(100_000_000_000_000_000_u128), }, ) .unwrap() .0, hashmap! { - H160([1; 20]) => BigRational::new(1.into(), 10.into()), + Address::repeat_byte(1) => BigRational::new(1.into(), 10.into()), native_token => BigRational::one(), - BUY_ETH_ADDRESS => BigRational::one(), + BUY_ETH_ADDRESS.into_alloy() => BigRational::one(), }, ); } #[test] fn from_auction_price_errors_on_invalid_native_prices() { - let native_token = H160([42; 20]); + let native_token = Address::repeat_byte(42); assert!( ExternalPrices::try_from_auction_prices( native_token, @@ -155,7 +159,7 @@ mod tests { ExternalPrices::try_from_auction_prices( native_token, btreemap! { - BUY_ETH_ADDRESS => U256::from(13_370_000_000_000_000_000_u128), + BUY_ETH_ADDRESS.into_alloy() => U256::from(13_370_000_000_000_000_000_u128), }, ) .is_err() diff --git a/crates/shared/src/http_solver.rs b/crates/shared/src/http_solver.rs index 805e2d84ab..161e2e464b 100644 --- a/crates/shared/src/http_solver.rs +++ b/crates/shared/src/http_solver.rs @@ -1,14 +1,17 @@ pub mod model { - use {ethcontract::H160, primitive_types::U256, serde::Serialize}; + use { + alloy::primitives::{Address, U256}, + serde::Serialize, + }; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct TokenAmount { pub amount: U256, - pub token: H160, + pub token: Address, } impl TokenAmount { - pub fn new>(token: H160, amount: T) -> Self { + pub fn new>(token: Address, amount: T) -> Self { Self { amount: amount.into(), token, diff --git a/crates/shared/src/price_estimation/buffered.rs b/crates/shared/src/price_estimation/buffered.rs index 0f23d3bc25..62fe21cd15 100644 --- a/crates/shared/src/price_estimation/buffered.rs +++ b/crates/shared/src/price_estimation/buffered.rs @@ -8,13 +8,11 @@ use { }, alloy::primitives::Address, anyhow::anyhow, - ethrpc::alloy::conversions::IntoLegacy, futures::{ channel::mpsc, future::FutureExt as _, stream::{self, FusedStream, Stream, StreamExt as _}, }, - primitive_types::H160, std::{ collections::{HashMap, HashSet}, future::Future, @@ -53,11 +51,11 @@ pub trait NativePriceBatchFetching: Sync + Send + NativePriceEstimating { /// estimator result fn fetch_native_prices( &self, - tokens: HashSet, + tokens: HashSet
, timeout: Duration, ) -> futures::future::BoxFuture< '_, - Result, PriceEstimationError>, + Result, PriceEstimationError>, >; /// Returns the number of prices that can be fetched in a single batch. @@ -69,14 +67,14 @@ pub trait NativePriceBatchFetching: Sync + Send + NativePriceEstimating { #[derive(Clone)] pub struct BufferedRequest { inner: std::marker::PhantomData, - requests: mpsc::UnboundedSender, + requests: mpsc::UnboundedSender
, results: broadcast::Sender, } /// Object to map the token with its native price estimator result #[derive(Clone)] struct NativePriceResult { - token: H160, + token: Address, result: Result, } @@ -99,19 +97,17 @@ where let mut rx = self.results.subscribe(); // Sends the token for requesting price - self.requests - .unbounded_send(token.into_legacy()) - .map_err(|e| { - PriceEstimationError::ProtocolInternal(anyhow!( - "failed to append a new token to the queue: {e:?}" - )) - })?; + self.requests.unbounded_send(token).map_err(|e| { + PriceEstimationError::ProtocolInternal(anyhow!( + "failed to append a new token to the queue: {e:?}" + )) + })?; tokio::time::timeout(timeout, async { loop { match rx.recv().await { Ok(value) => { - if value.token == token.into_legacy() { + if value.token == token { return value.result; } } @@ -161,7 +157,7 @@ where fn background_worker( inner: Arc, config: Configuration, - requests: mpsc::UnboundedReceiver, + requests: mpsc::UnboundedReceiver
, results_sender: broadcast::Sender, ) -> JoinHandle<()> { let timeout = config.result_ready_timeout; @@ -271,10 +267,10 @@ mod tests { ) -> futures::future::BoxFuture<'_, NativePriceEstimateResult> { async move { let prices = self - .fetch_native_prices(HashSet::from([token.into_legacy()]), timeout) + .fetch_native_prices(HashSet::from([token]), timeout) .await?; prices - .get(&token.into_legacy()) + .get(&token) .cloned() .ok_or(PriceEstimationError::NoLiquidity)? } diff --git a/crates/shared/src/price_estimation/factory.rs b/crates/shared/src/price_estimation/factory.rs index af5a6e7d9b..800dcfc311 100644 --- a/crates/shared/src/price_estimation/factory.rs +++ b/crates/shared/src/price_estimation/factory.rs @@ -237,7 +237,7 @@ impl<'a> PriceEstimatorFactory<'a> { self.args.coin_gecko.coin_gecko_url.clone(), self.args.coin_gecko.coin_gecko_api_key.clone(), &self.network.chain, - weth.address().into_legacy(), + *weth.address(), self.components.tokens.clone(), ) .await?; diff --git a/crates/shared/src/price_estimation/native/coingecko.rs b/crates/shared/src/price_estimation/native/coingecko.rs index ccf6d371ea..745b1eaab6 100644 --- a/crates/shared/src/price_estimation/native/coingecko.rs +++ b/crates/shared/src/price_estimation/native/coingecko.rs @@ -7,9 +7,7 @@ use { alloy::primitives::Address, anyhow::{Context, Result, anyhow}, chain::Chain, - ethrpc::alloy::conversions::IntoLegacy, futures::{FutureExt, future::BoxFuture}, - primitive_types::H160, reqwest::{Client, StatusCode}, rust_decimal::{Decimal, MathematicalOps, prelude::ToPrimitive}, serde::Deserialize, @@ -23,14 +21,14 @@ use { }; #[derive(Debug, Deserialize)] -struct Response(HashMap); +struct Response(HashMap); #[derive(Debug, Deserialize)] struct Price { eth: Option, } -type Token = H160; +type Token = Address; pub struct CoinGecko { client: Client, @@ -43,7 +41,7 @@ pub struct CoinGecko { /// The token in which prices are denominated in. struct Denominator { - address: H160, + address: Address, /// Number of decimals of the token. This is necessary /// to know in order to normalize prices for tokens /// with a different number of decimals. @@ -59,7 +57,7 @@ impl CoinGecko { base_url: Url, api_key: Option, chain: &Chain, - native_token: H160, + native_token: Address, token_infos: Arc, ) -> Result { let denominator_decimals = token_infos @@ -154,7 +152,7 @@ impl CoinGecko { &self, mut tokens: HashSet, timeout: Duration, - ) -> Result, PriceEstimationError> { + ) -> Result, PriceEstimationError> { tokens.insert(self.denominator.address); let tokens_vec: Vec<_> = tokens.iter().cloned().collect(); @@ -235,7 +233,8 @@ impl NativePriceBatchFetching for CoinGecko { &'_ self, tokens: HashSet, timeout: Duration, - ) -> BoxFuture<'_, Result, PriceEstimationError>> { + ) -> BoxFuture<'_, Result, PriceEstimationError>> + { self.bulk_fetch_denominated_in_token(tokens, timeout) .boxed() } @@ -259,10 +258,10 @@ impl NativePriceEstimating for CoinGecko { ) -> BoxFuture<'_, NativePriceEstimateResult> { async move { let prices = self - .fetch_native_prices(HashSet::from([token.into_legacy()]), timeout) + .fetch_native_prices(HashSet::from([token]), timeout) .await?; prices - .get(&token.into_legacy()) + .get(&token) .ok_or(PriceEstimationError::NoLiquidity)? .clone() } @@ -342,21 +341,21 @@ mod tests { Chain::Mainnet => ( "ethereum".to_string(), Denominator { - address: addr!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), + address: address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"), decimals: 18, }, ), Chain::Gnosis => ( "xdai".to_string(), Denominator { - address: addr!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), + address: address!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), decimals: 18, }, ), Chain::ArbitrumOne => ( "arbitrum-one".to_string(), Denominator { - address: addr!("82af49447d8a07e3bd95bd0d56f35241523fbab1"), + address: address!("82af49447d8a07e3bd95bd0d56f35241523fbab1"), decimals: 18, }, ), @@ -450,8 +449,8 @@ mod tests { #[tokio::test] #[ignore] async fn works_multiple_tokens() { - let usdt_token = addr!("4ECaBa5870353805a9F068101A40E0f32ed605C6"); - let usdc_token = addr!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); + let usdt_token = address!("4ECaBa5870353805a9F068101A40E0f32ed605C6"); + let usdc_token = address!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); let instance = CoinGecko::new_for_test( Client::default(), Url::parse(BASE_API_PRO_URL).unwrap(), @@ -479,8 +478,8 @@ mod tests { #[tokio::test] #[ignore] async fn unknown_token_does_not_ruin_batch() { - let usdc = addr!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); - let unknown_token = addr!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + let usdc = address!("2a22f9c3b484c3629090FeED35F17Ff8F88f76F0"); + let unknown_token = address!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); let instance = CoinGecko::new_for_test( Client::default(), Url::parse(BASE_API_PRO_URL).unwrap(), @@ -515,11 +514,7 @@ mod tests { tokens .iter() .map(|t| { - let decimals = if *t == usdc.into_legacy() { - Some(6) - } else { - Some(18) - }; + let decimals = if *t == usdc { Some(6) } else { Some(18) }; let info = TokenInfo { decimals, symbol: None, @@ -573,11 +568,7 @@ mod tests { .map(|t| { // Let's pretend USDC has 21 decimals to check if the price adjustment // also works when the requested token has more decimals. - let decimals = if *t == usdc.into_legacy() { - Some(21) - } else { - Some(18) - }; + let decimals = if *t == usdc { Some(21) } else { Some(18) }; let info = TokenInfo { decimals, symbol: None, diff --git a/crates/shared/src/price_estimation/native/oneinch.rs b/crates/shared/src/price_estimation/native/oneinch.rs index 71328f2954..6f0959d3de 100644 --- a/crates/shared/src/price_estimation/native/oneinch.rs +++ b/crates/shared/src/price_estimation/native/oneinch.rs @@ -3,14 +3,11 @@ use { crate::{price_estimation::PriceEstimationError, token_info::TokenInfoFetching}, alloy::primitives::Address, anyhow::{Context, Result, anyhow}, - ethrpc::{ - alloy::conversions::IntoAlloy, - block_stream::{CurrentBlockWatcher, into_stream}, - }, + ethrpc::block_stream::{CurrentBlockWatcher, into_stream}, futures::{FutureExt, StreamExt, future::BoxFuture}, num::ToPrimitive, number::{conversions::u256_to_big_rational, serialization::HexOrDecimalU256}, - primitive_types::{H160, U256}, + primitive_types::U256, reqwest::{Client, header::AUTHORIZATION}, serde::Deserialize, serde_with::serde_as, @@ -25,7 +22,7 @@ use { #[serde_as] #[derive(Debug, Deserialize)] -struct Response(#[serde_as(as = "HashMap<_, HexOrDecimalU256>")] HashMap); +struct Response(#[serde_as(as = "HashMap<_, HexOrDecimalU256>")] HashMap); type Token = Address; @@ -155,7 +152,7 @@ async fn get_current_prices( let unit = num::BigRational::from_integer(num::BigInt::from(10u64).pow(decimals.into())); let normalized_price = u256_to_big_rational(&price) / unit; - Some((token.into_alloy(), normalized_price.to_f64()?)) + Some((token, normalized_price.to_f64()?)) }) .collect(); Ok(normalized_prices) diff --git a/crates/shared/src/sources/balancer_v2/graph_api.rs b/crates/shared/src/sources/balancer_v2/graph_api.rs index ae64119fea..bd2f133a85 100644 --- a/crates/shared/src/sources/balancer_v2/graph_api.rs +++ b/crates/shared/src/sources/balancer_v2/graph_api.rs @@ -11,8 +11,9 @@ use { super::swap::fixed_point::Bfp, crate::{event_handling::MAX_REORG_BLOCK_COUNT, subgraph::SubgraphClient}, + alloy::primitives::Address, anyhow::Result, - ethcontract::{H160, H256}, + ethcontract::H256, reqwest::{Client, Url}, serde::Deserialize, serde_json::json, @@ -124,7 +125,7 @@ impl RegisteredPools { } /// Groups registered pools by factory addresses. - pub fn group_by_factory(self) -> HashMap { + pub fn group_by_factory(self) -> HashMap { let fetched_block_number = self.fetched_block_number; self.pools .into_iter() @@ -148,8 +149,8 @@ impl RegisteredPools { pub struct PoolData { pub pool_type: PoolType, pub id: H256, - pub address: H160, - pub factory: H160, + pub address: Address, + pub factory: Address, pub swap_enabled: bool, pub tokens: Vec, } @@ -167,7 +168,7 @@ pub enum PoolType { #[serde_as] #[derive(Debug, Deserialize, Eq, PartialEq)] pub struct Token { - pub address: H160, + pub address: Address, pub decimals: u8, #[serde_as(as = "Option")] #[serde(default)] @@ -244,7 +245,7 @@ mod tests { use { super::*, crate::sources::balancer_v2::swap::fixed_point::Bfp, - ethcontract::{H160, H256}, + ethcontract::H256, maplit::hashmap, }; @@ -335,17 +336,17 @@ mod tests { PoolData { pool_type: PoolType::Weighted, id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), }, @@ -354,17 +355,17 @@ mod tests { PoolData { pool_type: PoolType::Stable, id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: None, }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, weight: None, }, @@ -373,17 +374,17 @@ mod tests { PoolData { pool_type: PoolType::LiquidityBootstrapping, id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), }, @@ -392,17 +393,17 @@ mod tests { PoolData { pool_type: PoolType::ComposableStable, id: H256([0x11; 32]), - address: H160([0x22; 20]), - factory: H160([0x55; 20]), + address: Address::repeat_byte(0x22), + factory: Address::repeat_byte(0x55), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: None, }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 4, weight: None, }, @@ -436,7 +437,7 @@ mod tests { #[test] fn groups_pools_by_factory() { - let pool = |factory: H160, id: u8| PoolData { + let pool = |factory: Address, id: u8| PoolData { id: H256([id; 32]), factory, pool_type: PoolType::Weighted, @@ -447,9 +448,9 @@ mod tests { let registered_pools = RegisteredPools { pools: vec![ - pool(H160([1; 20]), 1), - pool(H160([1; 20]), 2), - pool(H160([2; 20]), 3), + pool(Address::repeat_byte(1), 1), + pool(Address::repeat_byte(1), 2), + pool(Address::repeat_byte(2), 3), ], fetched_block_number: 42, }; @@ -457,16 +458,16 @@ mod tests { assert_eq!( registered_pools.group_by_factory(), hashmap! { - H160([1; 20]) => RegisteredPools { + Address::repeat_byte(1) => RegisteredPools { pools: vec![ - pool(H160([1; 20]), 1), - pool(H160([1; 20]), 2), + pool(Address::repeat_byte(1), 1), + pool(Address::repeat_byte(1), 2), ], fetched_block_number: 42, }, - H160([2; 20]) => RegisteredPools { + Address::repeat_byte(2) => RegisteredPools { pools: vec![ - pool(H160([2; 20]), 3), + pool(Address::repeat_byte(2), 3), ], fetched_block_number: 42, }, diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs b/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs index dc743db799..91a37f9be7 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs +++ b/crates/shared/src/sources/balancer_v2/pool_fetching/mod.rs @@ -30,7 +30,7 @@ use { recent_block_cache::{Block, CacheConfig}, token_info::TokenInfoFetching, }, - alloy::providers::DynProvider, + alloy::{primitives::Address, providers::DynProvider}, anyhow::{Context, Result}, clap::ValueEnum, contracts::alloy::{ @@ -48,7 +48,7 @@ use { BalancerV2WeightedPoolFactoryV3, BalancerV2WeightedPoolFactoryV4, }, - ethcontract::{BlockId, H160, H256}, + ethcontract::{BlockId, H256}, ethrpc::block_stream::{BlockRetrieving, CurrentBlockWatcher}, model::TokenPair, reqwest::{Client, Url}, @@ -77,7 +77,7 @@ pub trait BalancerPoolEvaluating { #[derive(Clone, Debug)] pub struct CommonPoolState { pub id: H256, - pub address: H160, + pub address: Address, pub swap_fee: Bfp, pub paused: bool, } @@ -85,7 +85,7 @@ pub struct CommonPoolState { #[derive(Clone, Debug)] pub struct WeightedPool { pub common: CommonPoolState, - pub reserves: BTreeMap, + pub reserves: BTreeMap, pub version: WeightedPoolVersion, } @@ -107,7 +107,7 @@ impl WeightedPool { #[derive(Clone, Debug)] pub struct StablePool { pub common: CommonPoolState, - pub reserves: BTreeMap, + pub reserves: BTreeMap, pub amplification_parameter: AmplificationParameter, } @@ -133,7 +133,7 @@ pub struct FetchedBalancerPools { } impl FetchedBalancerPools { - pub fn relevant_tokens(&self) -> HashSet { + pub fn relevant_tokens(&self) -> HashSet
{ let mut tokens = HashSet::new(); tokens.extend( self.stable_pools @@ -468,8 +468,6 @@ async fn create_aggregate_pool_fetcher( macro_rules! registry { ($factory:ident, $instance:expr_2021) => {{ - use ethrpc::alloy::conversions::IntoLegacy; - create_internal_pool_fetcher( contracts.vault.clone(), $factory::Instance::new(*$instance.address(), $instance.provider().clone()), @@ -477,7 +475,7 @@ async fn create_aggregate_pool_fetcher( token_infos.clone(), $instance, registered_pools_by_factory - .remove(&(*$instance.address()).into_legacy()) + .remove(&(*$instance.address())) .unwrap_or_else(|| RegisteredPools::empty(fetched_block_number)), fetched_block_hash, )? @@ -583,15 +581,13 @@ where /// the pool. For example the GNO-BAL pool with ID /// `0x36128d5436d2d70cab39c9af9cce146c38554ff0000200000000000000000009`: /// -fn pool_address_from_id(pool_id: H256) -> H160 { - let mut address = H160::default(); - address.0.copy_from_slice(&pool_id.0[..20]); - address +fn pool_address_from_id(pool_id: H256) -> Address { + Address::from_slice(&pool_id.0[..20]) } #[cfg(test)] mod tests { - use {super::*, hex_literal::hex}; + use {super::*, alloy::primitives::address, hex_literal::hex}; #[test] fn can_extract_address_from_pool_id() { @@ -599,7 +595,7 @@ mod tests { pool_address_from_id(H256(hex!( "36128d5436d2d70cab39c9af9cce146c38554ff0000200000000000000000009" ))), - addr!("36128d5436d2d70cab39c9af9cce146c38554ff0"), + address!("36128d5436d2d70cab39c9af9cce146c38554ff0"), ); } } diff --git a/crates/shared/src/sources/balancer_v2/pool_fetching/pool_storage.rs b/crates/shared/src/sources/balancer_v2/pool_fetching/pool_storage.rs index f26737083b..a986bbe877 100644 --- a/crates/shared/src/sources/balancer_v2/pool_fetching/pool_storage.rs +++ b/crates/shared/src/sources/balancer_v2/pool_fetching/pool_storage.rs @@ -20,14 +20,14 @@ use { event_handling::EventStoring, sources::balancer_v2::pools::{FactoryIndexing, PoolIndexing, common}, }, - alloy::rpc::types::Log, + alloy::{primitives::Address, rpc::types::Log}, anyhow::{Context, Result}, contracts::alloy::BalancerV2BasePoolFactory::BalancerV2BasePoolFactory::{ BalancerV2BasePoolFactoryEvents, PoolCreated, }, - ethcontract::{H160, H256}, - ethrpc::{alloy::conversions::IntoLegacy, block_stream::RangeInclusive}, + ethcontract::H256, + ethrpc::block_stream::RangeInclusive, model::TokenPair, std::{ cmp, @@ -44,7 +44,7 @@ where /// Component used to fetch pool information. pool_info_fetcher: Arc>, /// Used for O(1) access to all pool_ids for a given token - pools_by_token: HashMap>, + pools_by_token: HashMap>, /// All indexed pool infos by ID. pools: HashMap, /// The block the initial pools were fetched on. This block is considered @@ -84,8 +84,8 @@ where ) -> impl Iterator + '_ + use<'_, Factory> { let (token0, token1) = token_pair.get(); - let pools0 = self.pools_by_token.get(&token0.into_legacy()); - let pools1 = self.pools_by_token.get(&token1.into_legacy()); + let pools0 = self.pools_by_token.get(&token0); + let pools1 = self.pools_by_token.get(&token1); pools0 .zip(pools1) @@ -135,7 +135,7 @@ where ) -> Result<()> { let pool = self .pool_info_fetcher - .fetch_pool_info(pool_creation.pool.into_legacy(), block_created) + .fetch_pool_info(pool_creation.pool, block_created) .await?; self.insert_pool(pool); @@ -233,34 +233,35 @@ mod tests { pools::{MockFactoryIndexing, common::MockPoolInfoFetching, weighted}, swap::fixed_point::Bfp, }, - ethrpc::alloy::conversions::IntoAlloy, maplit::{hashmap, hashset}, mockall::predicate::eq, }; pub type PoolInitData = ( Vec, - Vec, - Vec, + Vec
, + Vec
, Vec, Vec<(PoolCreated, u64)>, ); + // This can be made cleaner by making the start and end be u8's but the H256 + // doesn't support for a from(u8) so this needs to be reviewed upon migration fn pool_init_data(start: usize, end: usize) -> PoolInitData { let pool_ids: Vec = (start..=end) .map(|i| H256::from_low_u64_be(i as u64)) .collect(); - let pool_addresses: Vec = (start..=end) - .map(|i| H160::from_low_u64_be(i as u64)) + let pool_addresses: Vec
= (start..=end) + .map(|i| Address::with_last_byte(i as u8)) .collect(); - let tokens: Vec = (start..=end + 1) - .map(|i| H160::from_low_u64_be(i as u64)) + let tokens: Vec
= (start..=end + 1) + .map(|i| Address::with_last_byte(i as u8)) .collect(); let weights: Vec = (start..=end + 1).map(|i| Bfp::from_wei(i.into())).collect(); let creation_events: Vec<(PoolCreated, u64)> = (start..=end) .map(|i| { ( PoolCreated { - pool: pool_addresses[i].into_alloy(), + pool: pool_addresses[i], }, i as u64, ) @@ -277,8 +278,8 @@ mod tests { weighted::PoolInfo { common: common::PoolInfo { id: H256([1; 32]), - address: H160([1; 20]), - tokens: vec![H160([0x11; 20]), H160([0x22; 20])], + address: Address::repeat_byte(1), + tokens: vec![Address::repeat_byte(0x11), Address::repeat_byte(0x22)], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0)], block_created: 0, }, @@ -290,8 +291,12 @@ mod tests { weighted::PoolInfo { common: common::PoolInfo { id: H256([2; 32]), - address: H160([2; 20]), - tokens: vec![H160([0x11; 20]), H160([0x33; 20]), H160([0x77; 20])], + address: Address::repeat_byte(2), + tokens: vec![ + Address::repeat_byte(0x11), + Address::repeat_byte(0x33), + Address::repeat_byte(0x77), + ], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0)], block_created: 0, }, @@ -304,8 +309,8 @@ mod tests { weighted::PoolInfo { common: common::PoolInfo { id: H256([3; 32]), - address: H160([3; 20]), - tokens: vec![H160([0x11; 20]), H160([0x77; 20])], + address: Address::repeat_byte(3), + tokens: vec![Address::repeat_byte(0x11), Address::repeat_byte(0x77)], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0)], block_created: 0, }, @@ -321,10 +326,10 @@ mod tests { assert_eq!( storage.pools_by_token, hashmap! { - H160([0x11; 20]) => hashset![H256([1; 32]), H256([2; 32]), H256([3; 32])], - H160([0x22; 20]) => hashset![H256([1; 32])], - H160([0x33; 20]) => hashset![H256([2; 32])], - H160([0x77; 20]) => hashset![H256([2; 32]), H256([3; 32])], + Address::repeat_byte(0x11) => hashset![H256([1; 32]), H256([2; 32]), H256([3; 32])], + Address::repeat_byte(0x22) => hashset![H256([1; 32])], + Address::repeat_byte(0x33) => hashset![H256([2; 32])], + Address::repeat_byte(0x77) => hashset![H256([2; 32]), H256([3; 32])], } ); } @@ -434,15 +439,15 @@ mod tests { let new_pool = weighted::PoolInfo { common: common::PoolInfo { id: H256::from_low_u64_be(43110), - address: H160::from_low_u64_be(42), - tokens: vec![H160::from_low_u64_be(808)], + address: Address::with_last_byte(42), + tokens: vec![Address::left_padding_from(808u64.to_be_bytes().as_slice())], scaling_factors: vec![Bfp::exp10(0)], block_created: 3, }, weights: vec![Bfp::from_wei(1337.into())], }; let new_creation = PoolCreated { - pool: new_pool.common.address.into_alloy(), + pool: new_pool.common.address, }; mock_pool_fetcher @@ -534,9 +539,7 @@ mod tests { let n = 3; let (pool_ids, pool_addresses, tokens, _, _) = pool_init_data(0, n); let token_pairs: Vec = (0..n) - .map(|i| { - TokenPair::new(tokens[i].into_alloy(), tokens[(i + 1) % n].into_alloy()).unwrap() - }) + .map(|i| TokenPair::new(tokens[i], tokens[(i + 1) % n]).unwrap()) .collect(); let mut registry = PoolStorage::new( diff --git a/crates/shared/src/sources/balancer_v2/pools/common.rs b/crates/shared/src/sources/balancer_v2/pools/common.rs index cc657846d6..559e23b05b 100644 --- a/crates/shared/src/sources/balancer_v2/pools/common.rs +++ b/crates/shared/src/sources/balancer_v2/pools/common.rs @@ -9,9 +9,10 @@ use { }, token_info::TokenInfoFetching, }, + alloy::primitives::Address, anyhow::{Context, Result, anyhow, ensure}, contracts::alloy::{BalancerV2BasePool, BalancerV2Vault}, - ethcontract::{BlockId, H160, H256, U256}, + ethcontract::{BlockId, H256, U256}, ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::{FutureExt as _, future::BoxFuture}, std::{collections::BTreeMap, future::Future, sync::Arc}, @@ -27,7 +28,7 @@ where { async fn fetch_pool_info( &self, - pool_address: H160, + pool_address: Address, block_created: u64, ) -> Result; @@ -60,13 +61,13 @@ impl PoolInfoFetcher { } /// Returns a Balancer base pool contract instance at the specified address. - fn base_pool_at(&self, pool_address: H160) -> BalancerV2BasePool::Instance { + fn base_pool_at(&self, pool_address: Address) -> BalancerV2BasePool::Instance { let provider = self.vault.provider().clone(); - BalancerV2BasePool::Instance::new(pool_address.into_alloy(), provider) + BalancerV2BasePool::Instance::new(pool_address, provider) } /// Retrieves the scaling exponents for the specified tokens. - async fn scaling_factors(&self, tokens: &[H160]) -> Result> { + async fn scaling_factors(&self, tokens: &[Address]) -> Result> { let token_infos = self.token_infos.get_token_infos(tokens).await; tokens .iter() @@ -83,7 +84,7 @@ impl PoolInfoFetcher { async fn fetch_common_pool_info( &self, - pool_address: H160, + pool_address: Address, block_created: u64, ) -> Result { let pool = self.base_pool_at(pool_address); @@ -94,10 +95,7 @@ impl PoolInfoFetcher { .getPoolTokens(pool_id.0.into()) .call() .await? - .tokens - .into_iter() - .map(IntoLegacy::into_legacy) - .collect::>(); + .tokens; let scaling_factors = self.scaling_factors(&tokens).await?; Ok(PoolInfo { @@ -155,11 +153,7 @@ impl PoolInfoFetcher { let swap_fee = Bfp::from_wei(swap_fee.into_legacy()); let balances = pool_tokens.balances; - let tokens = pool_tokens - .tokens - .into_iter() - .map(IntoLegacy::into_legacy) - .collect::>(); + let tokens = pool_tokens.tokens.into_iter().collect::>(); ensure!(pool.tokens == tokens, "pool token mismatch"); let tokens = itertools::izip!(&pool.tokens, balances, &pool.scaling_factors) .map(|(&address, balance, &scaling_factor)| { @@ -190,7 +184,7 @@ where { async fn fetch_pool_info( &self, - pool_address: H160, + pool_address: Address, block_created: u64, ) -> Result { let common_pool_info = self @@ -234,8 +228,8 @@ where #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct PoolInfo { pub id: H256, - pub address: H160, - pub tokens: Vec, + pub address: Address, + pub tokens: Vec
, pub scaling_factors: Vec, pub block_created: u64, } @@ -276,7 +270,7 @@ impl PoolInfo { pub struct PoolState { pub paused: bool, pub swap_fee: Bfp, - pub tokens: BTreeMap, + pub tokens: BTreeMap, } /// Common pool token state information that is shared among all pool types. @@ -387,21 +381,25 @@ mod tests { #[tokio::test] async fn fetch_common_pool_info() { let pool_id = alloy::primitives::FixedBytes([0x90; 32]); - let tokens = [H160([1; 20]), H160([2; 20]), H160([3; 20])]; + let tokens = [ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ]; let asserter = Asserter::new(); let provider = ProviderBuilder::new() .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); asserter.push_success(&pool_id); let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: tokens.iter().copied().map(|t| t.into_alloy()).collect(), + tokens: tokens.to_vec(), balances: vec![], lastChangeBlock: U256::zero().into_alloy(), }, @@ -426,7 +424,7 @@ mod tests { token_infos: Arc::new(token_infos), }; let pool_info = pool_info_fetcher - .fetch_common_pool_info(pool.address().into_legacy(), 1337) + .fetch_common_pool_info(*pool.address(), 1337) .await .unwrap(); @@ -434,7 +432,7 @@ mod tests { pool_info, PoolInfo { id: pool_id.into_legacy(), - address: pool.address().into_legacy(), + address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)], block_created: 1337, @@ -445,7 +443,11 @@ mod tests { #[tokio::test] async fn fetch_common_pool_state() { let pool_id = H256([0x90; 32]); - let tokens = [H160([1; 20]), H160([2; 20]), H160([3; 20])]; + let tokens = [ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ]; let balances = [bfp!("1000.0"), bfp!("10.0"), bfp!("15.0")]; let scaling_factors = [Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)]; @@ -454,8 +456,8 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( @@ -475,7 +477,7 @@ mod tests { let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: tokens.iter().copied().map(|t| t.into_alloy()).collect(), + tokens: tokens.to_vec(), balances: balances .iter() .map(|b| b.as_uint256().into_alloy()) @@ -494,7 +496,7 @@ mod tests { }; let pool_info = PoolInfo { id: pool_id, - address: pool.address().into_legacy(), + address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: scaling_factors.to_vec(), block_created: 1337, @@ -534,15 +536,19 @@ mod tests { #[tokio::test] async fn fetch_state_errors_on_token_mismatch() { - let tokens = [H160([1; 20]), H160([2; 20]), H160([3; 20])]; + let tokens = [ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ]; let asserter = Asserter::new(); let provider = ProviderBuilder::new() .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( @@ -563,7 +569,7 @@ mod tests { let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: vec![H160([1; 20]).into_alloy(), H160([4; 20]).into_alloy()], + tokens: vec![Address::repeat_byte(1), Address::repeat_byte(4)], balances: vec![U256::zero().into_alloy(), U256::zero().into_alloy()], lastChangeBlock: U256::zero().into_alloy(), }, @@ -579,7 +585,7 @@ mod tests { }; let pool_info = PoolInfo { id: Default::default(), - address: pool.address().into_legacy(), + address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(0)], block_created: 1337, @@ -606,8 +612,8 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( @@ -627,8 +633,12 @@ mod tests { let pool_info = weighted::PoolInfo { common: PoolInfo { id: H256([0x90; 32]), - address: pool.address().into_legacy(), - tokens: vec![H160([1; 20]), H160([2; 20]), H160([3; 20])], + address: *pool.address(), + tokens: vec![ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ], scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)], block_created: 1337, }, @@ -665,13 +675,7 @@ mod tests { let get_pool_tokens_response = BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { - tokens: pool_info - .common - .tokens - .iter() - .copied() - .map(|t| t.into_alloy()) - .collect(), + tokens: pool_info.common.tokens.clone(), balances: pool_state .tokens .values() @@ -723,8 +727,8 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( @@ -777,7 +781,7 @@ mod tests { let pool_info = weighted::PoolInfo { common: PoolInfo { id: Default::default(), - address: pool.address().into_legacy(), + address: *pool.address(), tokens: Default::default(), scaling_factors: Default::default(), block_created: Default::default(), @@ -802,8 +806,8 @@ mod tests { .connect_mocked_client(asserter.clone()) .erased(); - let pool = BalancerV2BasePool::Instance::new(H160::random().into_alloy(), provider.clone()); - let vault = BalancerV2Vault::Instance::new(H160::random().into_alloy(), provider.clone()); + let pool = BalancerV2BasePool::Instance::new(Address::random(), provider.clone()); + let vault = BalancerV2Vault::Instance::new(Address::random(), provider.clone()); let get_paused_state_response = BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( @@ -849,7 +853,7 @@ mod tests { let pool_info = weighted::PoolInfo { common: PoolInfo { id: Default::default(), - address: pool.address().into_legacy(), + address: *pool.address(), tokens: Default::default(), scaling_factors: Default::default(), block_created: Default::default(), @@ -876,7 +880,7 @@ mod tests { let pool_info_fetcher = PoolInfoFetcher { vault: BalancerV2Vault::Instance::new( - H160([0xba; 20]).into_alloy(), + Address::repeat_byte(0xba), ethrpc::mock::web3().alloy, ), factory: MockFactoryIndexing::new(), @@ -884,7 +888,7 @@ mod tests { }; assert!( pool_info_fetcher - .scaling_factors(&[H160([0xff; 20])]) + .scaling_factors(&[Address::repeat_byte(0xff)]) .await .is_err() ); @@ -892,7 +896,7 @@ mod tests { #[tokio::test] async fn scaling_factor_error_on_missing_decimals() { - let token = H160([0xff; 20]); + let token = Address::repeat_byte(0xff); let mut token_infos = MockTokenInfoFetching::new(); token_infos.expect_get_token_infos().returning(move |_| { hashmap! { @@ -902,7 +906,7 @@ mod tests { let pool_info_fetcher = PoolInfoFetcher { vault: BalancerV2Vault::Instance::new( - H160([0xba; 20]).into_alloy(), + Address::repeat_byte(0xba), ethrpc::mock::web3().alloy, ), factory: MockFactoryIndexing::new(), @@ -916,17 +920,17 @@ mod tests { let pool = PoolData { pool_type: PoolType::Stable, id: H256([4; 32]), - address: H160([3; 20]), - factory: H160([0xfb; 20]), + address: Address::repeat_byte(3), + factory: Address::repeat_byte(0xfb), swap_enabled: true, tokens: vec![ Token { - address: H160([0x33; 20]), + address: Address::repeat_byte(0x33), decimals: 3, weight: None, }, Token { - address: H160([0x44; 20]), + address: Address::repeat_byte(0x44), decimals: 18, weight: None, }, @@ -937,8 +941,8 @@ mod tests { PoolInfo::from_graph_data(&pool, 42).unwrap(), PoolInfo { id: H256([4; 32]), - address: H160([3; 20]), - tokens: vec![H160([0x33; 20]), H160([0x44; 20])], + address: Address::repeat_byte(3), + tokens: vec![Address::repeat_byte(0x33), Address::repeat_byte(0x44)], scaling_factors: vec![Bfp::exp10(15), Bfp::exp10(0)], block_created: 42, } @@ -950,11 +954,11 @@ mod tests { let pool = PoolData { pool_type: PoolType::Weighted, id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0; 20]), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0), swap_enabled: true, tokens: vec![Token { - address: H160([2; 20]), + address: Address::repeat_byte(2), decimals: 18, weight: Some("1.337".parse().unwrap()), }], @@ -967,17 +971,17 @@ mod tests { let pool = PoolData { pool_type: PoolType::Weighted, id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0; 20]), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0), swap_enabled: true, tokens: vec![ Token { - address: H160([2; 20]), + address: Address::repeat_byte(2), decimals: 19, weight: Some("1.337".parse().unwrap()), }, Token { - address: H160([3; 20]), + address: Address::repeat_byte(3), decimals: 18, weight: Some("1.337".parse().unwrap()), }, diff --git a/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs b/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs index 258fbbdb2d..68eeb33f00 100644 --- a/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs +++ b/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs @@ -48,7 +48,7 @@ impl FactoryIndexing for BalancerV2ComposableStablePoolFactory::Instance { block: BlockId, ) -> BoxFuture<'static, Result>> { let pool_contract = BalancerV2ComposableStablePool::Instance::new( - pool_info.common.address.into_alloy(), + pool_info.common.address, self.provider().clone(), ); @@ -114,7 +114,8 @@ mod tests { use { super::*, crate::sources::balancer_v2::graph_api::Token, - ethcontract::{H160, H256}, + alloy::primitives::Address, + ethcontract::H256, }; #[test] @@ -122,17 +123,17 @@ mod tests { let pool = PoolData { pool_type: PoolType::Stable, id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: None, }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: None, }, diff --git a/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs b/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs index 8080ca3138..8e83f29872 100644 --- a/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs +++ b/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs @@ -55,7 +55,7 @@ impl FactoryIndexing for BalancerV2LiquidityBootstrappingPoolFactory::Instance { block: BlockId, ) -> BoxFuture<'static, Result>> { let pool_contract = BalancerV2LiquidityBootstrappingPool::Instance::new( - pool_info.common.address.into_alloy(), + pool_info.common.address, self.provider().clone(), ); @@ -120,7 +120,8 @@ mod tests { use { super::*, crate::sources::balancer_v2::graph_api::Token, - ethcontract::{H160, H256}, + alloy::primitives::Address, + ethcontract::H256, }; #[test] @@ -128,17 +129,17 @@ mod tests { let pool = PoolData { pool_type: PoolType::Weighted, id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: None, }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: None, }, diff --git a/crates/shared/src/sources/balancer_v2/pools/stable.rs b/crates/shared/src/sources/balancer_v2/pools/stable.rs index b60f8b96df..a236bdfa0b 100644 --- a/crates/shared/src/sources/balancer_v2/pools/stable.rs +++ b/crates/shared/src/sources/balancer_v2/pools/stable.rs @@ -9,9 +9,10 @@ use { swap::fixed_point::Bfp, }, }, + alloy::primitives::Address, anyhow::{Result, ensure}, contracts::alloy::{BalancerV2StablePool, BalancerV2StablePoolFactoryV2}, - ethcontract::{BlockId, H160, U256}, + ethcontract::{BlockId, U256}, ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::{FutureExt as _, future::BoxFuture}, num::BigRational, @@ -37,7 +38,7 @@ impl PoolIndexing for PoolInfo { #[derive(Clone, Debug, Eq, PartialEq)] pub struct PoolState { - pub tokens: BTreeMap, + pub tokens: BTreeMap, pub swap_fee: Bfp, pub amplification_parameter: AmplificationParameter, } @@ -93,10 +94,8 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { common_pool_state: BoxFuture<'static, common::PoolState>, block: BlockId, ) -> BoxFuture<'static, Result>> { - let pool_contract = BalancerV2StablePool::Instance::new( - pool_info.common.address.into_alloy(), - self.provider().clone(), - ); + let pool_contract = + BalancerV2StablePool::Instance::new(pool_info.common.address, self.provider().clone()); let fetch_common = common_pool_state.map(Result::Ok); let fetch_amplification_parameter = async move { @@ -130,28 +129,24 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { #[cfg(test)] mod tests { - use { - super::*, - crate::sources::balancer_v2::graph_api::Token, - ethcontract::{H160, H256}, - }; + use {super::*, crate::sources::balancer_v2::graph_api::Token, ethcontract::H256}; #[test] fn errors_when_converting_wrong_pool_type() { let pool = PoolData { pool_type: PoolType::Weighted, id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: None, }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: None, }, diff --git a/crates/shared/src/sources/balancer_v2/pools/weighted.rs b/crates/shared/src/sources/balancer_v2/pools/weighted.rs index ff1c34f42d..c6b8757abd 100644 --- a/crates/shared/src/sources/balancer_v2/pools/weighted.rs +++ b/crates/shared/src/sources/balancer_v2/pools/weighted.rs @@ -6,14 +6,15 @@ use { graph_api::{PoolData, PoolType}, swap::fixed_point::Bfp, }, + alloy::primitives::Address, anyhow::{Result, anyhow}, contracts::alloy::{ BalancerV2WeightedPool, BalancerV2WeightedPoolFactory, BalancerV2WeightedPoolFactoryV3, }, - ethcontract::{BlockId, H160}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethcontract::BlockId, + ethrpc::alloy::conversions::IntoLegacy, futures::{FutureExt as _, future::BoxFuture}, std::collections::BTreeMap, }; @@ -26,7 +27,7 @@ pub struct PoolInfo { #[derive(Clone, Debug, Eq, PartialEq)] pub struct PoolState { - pub tokens: BTreeMap, + pub tokens: BTreeMap, pub swap_fee: Bfp, pub version: Version, } @@ -71,10 +72,8 @@ impl FactoryIndexing for BalancerV2WeightedPoolFactory::Instance { type PoolState = PoolState; async fn specialize_pool_info(&self, pool: common::PoolInfo) -> Result { - let pool_contract = BalancerV2WeightedPool::Instance::new( - pool.address.into_alloy(), - self.provider().clone(), - ); + let pool_contract = + BalancerV2WeightedPool::Instance::new(pool.address, self.provider().clone()); let weights = pool_contract .getNormalizedWeights() .call() @@ -154,8 +153,9 @@ mod tests { providers::{Provider, ProviderBuilder, mock::Asserter}, sol_types::SolCall, }, - ethcontract::{H160, H256}, + ethcontract::H256, ethcontract_mock::Mock, + ethrpc::alloy::conversions::IntoAlloy, futures::future, maplit::btreemap, }; @@ -165,17 +165,17 @@ mod tests { let pool = PoolData { pool_type: PoolType::Weighted, id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: Some(bfp!("1.337")), }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: Some(bfp!("4.2")), }, @@ -187,8 +187,8 @@ mod tests { PoolInfo { common: common::PoolInfo { id: H256([2; 32]), - address: H160([1; 20]), - tokens: vec![H160([0x11; 20]), H160([0x22; 20])], + address: Address::repeat_byte(1), + tokens: vec![Address::repeat_byte(0x11), Address::repeat_byte(0x22)], scaling_factors: vec![Bfp::exp10(17), Bfp::exp10(16)], block_created: 42, }, @@ -205,17 +205,17 @@ mod tests { let pool = PoolData { pool_type: PoolType::Stable, id: H256([2; 32]), - address: H160([1; 20]), - factory: H160([0xfa; 20]), + address: Address::repeat_byte(1), + factory: Address::repeat_byte(0xfa), swap_enabled: true, tokens: vec![ Token { - address: H160([0x11; 20]), + address: Address::repeat_byte(0x11), decimals: 1, weight: Some(bfp!("1.337")), }, Token { - address: H160([0x22; 20]), + address: Address::repeat_byte(0x22), decimals: 2, weight: Some(bfp!("4.2")), }, @@ -251,8 +251,12 @@ mod tests { let pool = factory .specialize_pool_info(common::PoolInfo { id: H256([0x90; 32]), - tokens: vec![H160([1; 20]), H160([2; 20]), H160([3; 20])], - address: pool.address().into_legacy(), + tokens: vec![ + Address::repeat_byte(1), + Address::repeat_byte(2), + Address::repeat_byte(3), + ], + address: *pool.address(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(0)], block_created: 42, }) @@ -265,11 +269,11 @@ mod tests { #[tokio::test] async fn fetch_pool_state() { let tokens = btreemap! { - H160([1; 20]) => common::TokenState { + Address::repeat_byte(1) => common::TokenState { balance: bfp!("1000.0").as_uint256(), scaling_factor: Bfp::exp10(0), }, - H160([2; 20]) => common::TokenState { + Address::repeat_byte(2) => common::TokenState { balance: 10_000_000.into(), scaling_factor: Bfp::exp10(12), }, @@ -287,7 +291,7 @@ mod tests { let pool_info = PoolInfo { common: common::PoolInfo { id: H256([0x90; 32]), - address: H160([0x90; 20]), + address: Address::repeat_byte(0x90), tokens: tokens.keys().copied().collect(), scaling_factors: tokens.values().map(|token| token.scaling_factor).collect(), block_created: 1337, diff --git a/crates/shared/src/sources/balancer_v2/swap/mod.rs b/crates/shared/src/sources/balancer_v2/swap/mod.rs index a5db8727b0..d535b7e999 100644 --- a/crates/shared/src/sources/balancer_v2/swap/mod.rs +++ b/crates/shared/src/sources/balancer_v2/swap/mod.rs @@ -11,8 +11,9 @@ use { WeightedTokenState, }, }, + alloy::primitives::Address, error::Error, - ethcontract::{H160, U256}, + ethcontract::U256, fixed_point::Bfp, std::collections::BTreeMap, }; @@ -73,7 +74,7 @@ impl TokenState { /// amounts. #[derive(Debug)] pub struct WeightedPoolRef<'a> { - pub reserves: &'a BTreeMap, + pub reserves: &'a BTreeMap, pub swap_fee: Bfp, pub version: WeightedPoolVersion, } @@ -81,9 +82,9 @@ pub struct WeightedPoolRef<'a> { impl WeightedPoolRef<'_> { fn get_amount_out_inner( &self, - out_token: H160, + out_token: Address, in_amount: U256, - in_token: H160, + in_token: Address, ) -> Option { // Note that the output of this function does not depend on the pool // specialization. All contract branches compute this amount with: @@ -112,16 +113,16 @@ impl WeightedPoolRef<'_> { impl BaselineSolvable for WeightedPoolRef<'_> { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { self.get_amount_out_inner(out_token, in_amount, in_token) } async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { // Note that the output of this function does not depend on the pool // specialization. All contract branches compute this amount with: @@ -157,8 +158,8 @@ impl BaselineSolvable for WeightedPoolRef<'_> { /// Stable pool data as a reference used for computing input and output amounts. #[derive(Debug)] pub struct StablePoolRef<'a> { - pub address: H160, - pub reserves: &'a BTreeMap, + pub address: Address, + pub reserves: &'a BTreeMap, pub swap_fee: Bfp, pub amplification_parameter: AmplificationParameter, } @@ -180,7 +181,9 @@ impl<'a> StablePoolRef<'a> { /// swaps. /// /// - pub fn reserves_without_bpt(&self) -> impl Iterator + 'a + use<'a> { + pub fn reserves_without_bpt( + &self, + ) -> impl Iterator + 'a + use<'a> { let bpt = self.address; self.reserves .iter() @@ -190,8 +193,8 @@ impl<'a> StablePoolRef<'a> { fn upscale_balances_with_token_indices( &self, - in_token: &H160, - out_token: &H160, + in_token: &Address, + out_token: &Address, ) -> Result { let mut balances = vec![]; let (mut token_index_in, mut token_index_out) = (0, 0); @@ -221,8 +224,8 @@ impl<'a> StablePoolRef<'a> { /// https://etherscan.io/address/0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F#code#F2#L270 fn regular_swap_given_in( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { let in_reserves = self.reserves.get(&in_token)?; let out_reserves = self.reserves.get(&out_token)?; @@ -249,8 +252,8 @@ impl<'a> StablePoolRef<'a> { /// https://etherscan.io/address/0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F#code#F2#L270 fn regular_swap_given_out( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { let in_reserves = self.reserves.get(&in_token)?; let out_reserves = self.reserves.get(&out_token)?; @@ -285,9 +288,9 @@ impl<'a> StablePoolRef<'a> { impl StablePoolRef<'_> { fn get_amount_out_inner( &self, - out_token: H160, + out_token: Address, in_amount: U256, - in_token: H160, + in_token: Address, ) -> Option { if in_token == self.address || out_token == self.address { self.swap_with_bpt() @@ -300,16 +303,16 @@ impl StablePoolRef<'_> { impl BaselineSolvable for StablePoolRef<'_> { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { self.get_amount_out_inner(out_token, in_amount, in_token) } async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { if in_token == self.address || out_token == self.address { self.swap_with_bpt() @@ -372,11 +375,11 @@ impl WeightedPool { } impl BaselineSolvable for WeightedPool { - async fn get_amount_out(&self, out_token: H160, input: (U256, H160)) -> Option { + async fn get_amount_out(&self, out_token: Address, input: (U256, Address)) -> Option { self.as_pool_ref().get_amount_out(out_token, input).await } - async fn get_amount_in(&self, in_token: H160, output: (U256, H160)) -> Option { + async fn get_amount_in(&self, in_token: Address, output: (U256, Address)) -> Option { self.as_pool_ref().get_amount_in(in_token, output).await } @@ -396,17 +399,17 @@ impl StablePool { } /// See [`StablePoolRef::reserves_without_bpt`]. - pub fn reserves_without_bpt(&self) -> impl Iterator + '_ { + pub fn reserves_without_bpt(&self) -> impl Iterator + '_ { self.as_pool_ref().reserves_without_bpt() } } impl BaselineSolvable for StablePool { - async fn get_amount_out(&self, out_token: H160, input: (U256, H160)) -> Option { + async fn get_amount_out(&self, out_token: Address, input: (U256, Address)) -> Option { self.as_pool_ref().get_amount_out(out_token, input).await } - async fn get_amount_in(&self, in_token: H160, output: (U256, H160)) -> Option { + async fn get_amount_in(&self, in_token: Address, output: (U256, Address)) -> Option { self.as_pool_ref().get_amount_in(in_token, output).await } @@ -420,10 +423,11 @@ mod tests { use { super::*, crate::sources::balancer_v2::pool_fetching::{AmplificationParameter, CommonPoolState}, + alloy::primitives::Address, }; fn create_weighted_pool_with( - tokens: Vec, + tokens: Vec
, balances: Vec, weights: Vec, scaling_factors: Vec, @@ -447,7 +451,7 @@ mod tests { WeightedPool { common: CommonPoolState { id: Default::default(), - address: H160::zero(), + address: Address::ZERO, swap_fee: Bfp::from_wei(swap_fee), paused: true, }, @@ -457,7 +461,7 @@ mod tests { } fn create_stable_pool_with( - tokens: Vec, + tokens: Vec
, balances: Vec, amplification_parameter: AmplificationParameter, scaling_factors: Vec, @@ -477,7 +481,7 @@ mod tests { StablePool { common: CommonPoolState { id: Default::default(), - address: H160::zero(), + address: Address::ZERO, swap_fee: Bfp::from_wei(swap_fee), paused: true, }, @@ -507,8 +511,8 @@ mod tests { async fn weighted_get_amount_out() { // Values obtained from this transaction: // https://dashboard.tenderly.co/tx/main/0xa9f571c9bfd4289bd4bd270465d73e1b7e010622ed089d54d81ec63a0365ec22/debugger - let crv = H160::repeat_byte(21); - let sdvecrv_dao = H160::repeat_byte(42); + let crv = ::alloy::primitives::Address::repeat_byte(21); + let sdvecrv_dao = ::alloy::primitives::Address::repeat_byte(42); let b = create_weighted_pool_with( vec![crv, sdvecrv_dao], vec![ @@ -532,8 +536,8 @@ mod tests { async fn weighted_get_amount_in() { // Values obtained from this transaction: // https://dashboard.tenderly.co/tx/main/0xafc3dd6a636a85d9c1976dfa5aee33f78e6ee902f285c9d4cf80a0014aa2a052/debugger - let weth = H160::repeat_byte(21); - let tusd = H160::repeat_byte(42); + let weth = ::alloy::primitives::Address::repeat_byte(21); + let tusd = ::alloy::primitives::Address::repeat_byte(42); let b = create_weighted_pool_with( vec![weth, tusd], vec![60_000_000_000_000_000_i128.into(), 250_000_000_i128.into()], @@ -552,7 +556,7 @@ mod tests { #[test] fn construct_balances_and_token_indices() { - let tokens: Vec<_> = (1..=3).map(H160::from_low_u64_be).collect(); + let tokens: Vec<_> = (1..=3).map(Address::with_last_byte).collect(); let balances = (1..=3).map(|n| n.into()).collect(); let pool = create_stable_pool_with( tokens.clone(), @@ -593,9 +597,9 @@ mod tests { // Test based on actual swap. // https://dashboard.tenderly.co/tx/main/0x75be93fff064ad46b423b9e20cee09b0ae7f741087f43e4187d4f4cf59f54229/debugger // Token addresses are irrelevant for computation. - let dai = H160::from_low_u64_be(1); - let usdc = H160::from_low_u64_be(2); - let tusd = H160::from_low_u64_be(3); + let dai = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); + let tusd = Address::with_last_byte(3); let tokens = vec![dai, usdc, tusd]; let scaling_exps = vec![Bfp::exp10(0), Bfp::exp10(12), Bfp::exp10(12)]; let amplification_parameter = @@ -626,9 +630,9 @@ mod tests { // Test based on actual swap. // https://dashboard.tenderly.co/tx/main/0x38487122158eef6b63570b5d3754ddc223c63af5c049d7b80acacb9e8ca89a63/debugger // Token addresses are irrelevant for computation. - let dai = H160::from_low_u64_be(1); - let usdc = H160::from_low_u64_be(2); - let tusd = H160::from_low_u64_be(3); + let dai = Address::with_last_byte(1); + let usdc = Address::with_last_byte(2); + let tusd = Address::with_last_byte(3); let tokens = vec![dai, usdc, tusd]; let scaling_exps = vec![Bfp::exp10(0), Bfp::exp10(12), Bfp::exp10(12)]; let amplification_parameter = diff --git a/crates/shared/src/sources/swapr.rs b/crates/shared/src/sources/swapr.rs index a9342e7242..28ecc7e4ca 100644 --- a/crates/shared/src/sources/swapr.rs +++ b/crates/shared/src/sources/swapr.rs @@ -26,8 +26,7 @@ impl PoolReading for SwaprPoolReader { let fetch_pool = self.0.read_state(pair, block); async move { - let pair_contract = - ISwaprPair::Instance::new(pair_address.into_alloy(), self.0.web3.alloy.clone()); + let pair_contract = ISwaprPair::Instance::new(pair_address, self.0.web3.alloy.clone()); let fetch_fee = pair_contract.swapFee().block(block.into_alloy()); let (pool, fee) = futures::join!(fetch_pool, fetch_fee.call().into_future()); @@ -60,7 +59,6 @@ mod tests { sources::{BaselineSource, uniswap_v2}, }, alloy::primitives::{Address, address}, - ethcontract::H160, ethrpc::alloy::errors::testing_alloy_contract_error, maplit::hashset, }; @@ -69,7 +67,7 @@ mod tests { fn sets_fee() { let tokens = TokenPair::new(Address::from_slice(&[1; 20]), Address::from_slice(&[2; 20])).unwrap(); - let address = H160::from_low_u64_be(1); + let address = Address::with_last_byte(1); assert_eq!( handle_results( Ok(Some(Pool { @@ -95,7 +93,7 @@ mod tests { fn ignores_contract_errors_when_reading_fee() { let tokens = TokenPair::new(Address::from_slice(&[1; 20]), Address::from_slice(&[2; 20])).unwrap(); - let address = H160::from_low_u64_be(1); + let address = Address::with_last_byte(1); assert!( handle_results( Ok(Some(Pool::uniswap(address, tokens, (0, 0)))), diff --git a/crates/shared/src/sources/uniswap_v2/mod.rs b/crates/shared/src/sources/uniswap_v2/mod.rs index ef0514ba11..6636f19ac5 100644 --- a/crates/shared/src/sources/uniswap_v2/mod.rs +++ b/crates/shared/src/sources/uniswap_v2/mod.rs @@ -116,7 +116,7 @@ impl UniV2BaselineSourceParameters { ); let factory = router.factory().call().await.context("factory")?; let pair_provider = pair_provider::PairProvider { - factory: factory.into_legacy(), + factory, init_code_digest: self.init_code_digest.0, }; let pool_reader = DefaultPoolReader::new(web3.clone(), pair_provider); @@ -181,7 +181,6 @@ mod tests { primitives::{Address, address}, providers::Provider, }, - ethrpc::alloy::conversions::IntoAlloy, maplit::hashset, model::TokenPair, }; @@ -213,9 +212,9 @@ mod tests { web3: &Web3, version: &str, source: BaselineSource, - token0: H160, - token1: H160, - expected_pool_address: H160, + token0: Address, + token1: Address, + expected_pool_address: Address, ) { let version_ = web3.eth().chain_id().await.unwrap().to_string(); assert_eq!(version_, version, "wrong node for test"); @@ -224,7 +223,7 @@ mod tests { .into_source(web3) .await .unwrap(); - let pair = TokenPair::new(token0.into_alloy(), token1.into_alloy()).unwrap(); + let pair = TokenPair::new(token0, token1).unwrap(); let pool = source.pair_provider.pair_address(&pair); assert_eq!(pool, expected_pool_address); } @@ -241,23 +240,23 @@ mod tests { test( BaselineSource::UniswapV2, - testlib::tokens::GNO.into_legacy(), - testlib::tokens::WETH.into_legacy(), - addr!("3e8468f66d30fc99f745481d4b383f89861702c6"), + testlib::tokens::GNO, + testlib::tokens::WETH, + address!("3e8468f66d30fc99f745481d4b383f89861702c6"), ) .await; test( BaselineSource::SushiSwap, - testlib::tokens::GNO.into_legacy(), - testlib::tokens::WETH.into_legacy(), - addr!("41328fdba556c8c969418ccccb077b7b8d932aa5"), + testlib::tokens::GNO, + testlib::tokens::WETH, + address!("41328fdba556c8c969418ccccb077b7b8d932aa5"), ) .await; test( BaselineSource::Swapr, - addr!("a1d65E8fB6e87b60FECCBc582F7f97804B725521"), - testlib::tokens::WETH.into_legacy(), - addr!("b0Dc4B36e0B4d2e3566D2328F6806EA0B76b4F13"), + address!("a1d65E8fB6e87b60FECCBc582F7f97804B725521"), + testlib::tokens::WETH, + address!("b0Dc4B36e0B4d2e3566D2328F6806EA0B76b4F13"), ) .await; } @@ -275,9 +274,9 @@ mod tests { // https://sepolia.etherscan.io/tx/0x4d31daa9e74b96a5c9a780cf8839b115ac25127b17226ecb1ad6e7f244fd1c8f test( BaselineSource::TestnetUniswapV2, - addr!("fff9976782d46cc05630d1f6ebab18b2324d6b14"), - addr!("7c43482436624585c27cc9f804e53463d5a37aba"), - addr!("84A1CE0e56500D51a6a6e2559567007E26dc8a7C"), + address!("fff9976782d46cc05630d1f6ebab18b2324d6b14"), + address!("7c43482436624585c27cc9f804e53463d5a37aba"), + address!("84A1CE0e56500D51a6a6e2559567007E26dc8a7C"), ) .await; } @@ -294,16 +293,16 @@ mod tests { test( BaselineSource::Baoswap, - addr!("7f7440c5098462f833e123b44b8a03e1d9785bab"), - addr!("e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"), - addr!("8746355882e10aae144d3709889dfaa39ff2a692"), + address!("7f7440c5098462f833e123b44b8a03e1d9785bab"), + address!("e91D153E0b41518A2Ce8Dd3D7944Fa863463a97d"), + address!("8746355882e10aae144d3709889dfaa39ff2a692"), ) .await; test( BaselineSource::Honeyswap, - addr!("71850b7e9ee3f13ab46d67167341e4bdc905eef9"), - addr!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), - addr!("4505b262dc053998c10685dc5f9098af8ae5c8ad"), + address!("71850b7e9ee3f13ab46d67167341e4bdc905eef9"), + address!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"), + address!("4505b262dc053998c10685dc5f9098af8ae5c8ad"), ) .await; } @@ -342,7 +341,7 @@ mod tests { println!("WETH <> wxDAI pool: {pool:#?}"); assert_eq!( - pool.address.into_alloy(), + pool.address, address!("8c36f7ca02d50bf8e705f582328b873acbe9438d") ); } @@ -380,7 +379,7 @@ mod tests { println!("WETH <> wxDAI pool: {pool:#?}"); assert_eq!( - pool.address.into_alloy(), + pool.address, address!("7bea4af5d425f2d4485bdad1859c88617df31a67") ); } diff --git a/crates/shared/src/sources/uniswap_v2/pair_provider.rs b/crates/shared/src/sources/uniswap_v2/pair_provider.rs index 747232e8f3..7788195e69 100644 --- a/crates/shared/src/sources/uniswap_v2/pair_provider.rs +++ b/crates/shared/src/sources/uniswap_v2/pair_provider.rs @@ -1,13 +1,13 @@ -use {ethcontract::H160, model::TokenPair, web3::signing::keccak256}; +use {alloy::primitives::Address, model::TokenPair, web3::signing::keccak256}; #[derive(Clone, Copy, Debug)] pub struct PairProvider { - pub factory: H160, + pub factory: Address, pub init_code_digest: [u8; 32], } impl PairProvider { - pub fn pair_address(&self, pair: &TokenPair) -> H160 { + pub fn pair_address(&self, pair: &TokenPair) -> Address { let (token0, token1) = pair.get(); // https://uniswap.org/docs/v2/javascript-SDK/getting-pair-addresses/ @@ -21,23 +21,27 @@ impl PairProvider { } } -fn create2_target_address(creator: H160, salt: &[u8; 32], init_code_digest: &[u8; 32]) -> H160 { +fn create2_target_address( + creator: Address, + salt: &[u8; 32], + init_code_digest: &[u8; 32], +) -> Address { let mut preimage = [0xff; 85]; - preimage[1..21].copy_from_slice(creator.as_fixed_bytes()); + preimage[1..21].copy_from_slice(creator.as_slice()); preimage[21..53].copy_from_slice(salt); preimage[53..85].copy_from_slice(init_code_digest); - H160::from_slice(&keccak256(&preimage)[12..]) + Address::from_slice(&keccak256(&preimage)[12..]) } #[cfg(test)] mod tests { - use {super::*, hex_literal::hex}; + use {super::*, alloy::primitives::address, hex_literal::hex}; #[test] fn test_create2_mainnet() { // https://info.uniswap.org/pair/0x3e8468f66d30fc99f745481d4b383f89861702c6 let provider = PairProvider { - factory: addr!("5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), + factory: address!("5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), init_code_digest: hex!( "96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" ), @@ -45,7 +49,7 @@ mod tests { let pair = TokenPair::new(testlib::tokens::GNO, testlib::tokens::WETH).unwrap(); assert_eq!( provider.pair_address(&pair), - addr!("3e8468f66d30fc99f745481d4b383f89861702c6") + address!("3e8468f66d30fc99f745481d4b383f89861702c6") ); } } diff --git a/crates/shared/src/sources/uniswap_v2/pool_fetching.rs b/crates/shared/src/sources/uniswap_v2/pool_fetching.rs index caedfed96d..76832bc515 100644 --- a/crates/shared/src/sources/uniswap_v2/pool_fetching.rs +++ b/crates/shared/src/sources/uniswap_v2/pool_fetching.rs @@ -1,6 +1,7 @@ use { super::pair_provider::PairProvider, crate::{baseline_solver::BaselineSolvable, ethrpc::Web3, recent_block_cache::Block}, + alloy::primitives::Address, anyhow::Result, cached::{Cached, TimedCache}, contracts::{ @@ -10,11 +11,8 @@ use { }, errors::EthcontractErrorType, }, - ethcontract::{BlockId, H160, U256, errors::MethodError}, - ethrpc::alloy::{ - conversions::{IntoAlloy, IntoLegacy}, - errors::ignore_non_node_error, - }, + ethcontract::{BlockId, U256, errors::MethodError}, + ethrpc::alloy::{conversions::IntoAlloy, errors::ignore_non_node_error}, futures::{ FutureExt as _, future::{self, BoxFuture}, @@ -35,7 +33,7 @@ static POOL_MAX_RESERVES: LazyLock = LazyLock::new(|| U256::from((1u128 << /// This type denotes `(reserve_a, reserve_b, token_b)` where /// `reserve_a` refers to the reserve of the excluded token. -type RelativeReserves = (U256, U256, H160); +type RelativeReserves = (U256, U256, Address); #[async_trait::async_trait] pub trait PoolFetching: Send + Sync { @@ -56,14 +54,14 @@ impl PoolReading for Box { #[derive(Clone, Copy, Eq, Hash, PartialEq, Debug)] pub struct Pool { - pub address: H160, + pub address: Address, pub tokens: TokenPair, pub reserves: (u128, u128), pub fee: Ratio, } impl Pool { - pub fn uniswap(address: H160, tokens: TokenPair, reserves: (u128, u128)) -> Self { + pub fn uniswap(address: Address, tokens: TokenPair, reserves: (u128, u128)) -> Self { Self { address, tokens, @@ -75,7 +73,7 @@ impl Pool { /// Given an input amount and token, returns the maximum output amount and /// address of the other asset. Returns None if operation not possible /// due to arithmetic issues (e.g. over or underflow) - fn get_amount_out(&self, token_in: H160, amount_in: U256) -> Option<(U256, H160)> { + fn get_amount_out(&self, token_in: Address, amount_in: U256) -> Option<(U256, Address)> { let (reserve_in, reserve_out, token_out) = self.get_relative_reserves(token_in); Some(( self.amount_out(amount_in, reserve_in, reserve_out)?, @@ -86,7 +84,7 @@ impl Pool { /// Given an output amount and token, returns a required input amount and /// address of the other asset. Returns None if operation not possible /// due to arithmetic issues (e.g. over or underflow, reserve too small) - fn get_amount_in(&self, token_out: H160, amount_out: U256) -> Option<(U256, H160)> { + fn get_amount_in(&self, token_out: Address, amount_out: U256) -> Option<(U256, Address)> { let (reserve_out, reserve_in, token_in) = self.get_relative_reserves(token_out); Some(( self.amount_in(amount_out, reserve_in, reserve_out)?, @@ -101,24 +99,20 @@ impl Pool { /// - the reserve of the other token /// - the pool's other token This is essentially a helper method for /// shuffling values in `get_amount_in` and `get_amount_out` - fn get_relative_reserves(&self, token: H160) -> RelativeReserves { + fn get_relative_reserves(&self, token: Address) -> RelativeReserves { // https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol#L53 - if token == self.tokens.get().0.into_legacy() { + if token == self.tokens.get().0 { ( U256::from(self.reserves.0), U256::from(self.reserves.1), - self.tokens.get().1.into_legacy(), + self.tokens.get().1, ) } else { - assert_eq!( - token, - self.tokens.get().1.into_legacy(), - "Token not part of pool" - ); + assert_eq!(token, self.tokens.get().1, "Token not part of pool"); ( U256::from(self.reserves.1), U256::from(self.reserves.0), - self.tokens.get().0.into_legacy(), + self.tokens.get().0, ) } } @@ -177,8 +171,8 @@ fn check_final_reserves( impl BaselineSolvable for Pool { async fn get_amount_out( &self, - out_token: H160, - (in_amount, in_token): (U256, H160), + out_token: Address, + (in_amount, in_token): (U256, Address), ) -> Option { self.get_amount_out(in_token, in_amount) .map(|(out_amount, token)| { @@ -189,8 +183,8 @@ impl BaselineSolvable for Pool { async fn get_amount_in( &self, - in_token: H160, - (out_amount, out_token): (U256, H160), + in_token: Address, + (out_amount, out_token): (U256, Address), ) -> Option { self.get_amount_in(out_token, out_amount) .map(|(in_amount, token)| { @@ -286,15 +280,11 @@ impl PoolReading for DefaultPoolReader { let token1 = ERC20::Instance::new(pair.get().1, self.web3.alloy.clone()); async move { - let fetch_token0_balance = token0 - .balanceOf(pair_address.into_alloy()) - .block(block.into_alloy()); - let fetch_token1_balance = token1 - .balanceOf(pair_address.into_alloy()) - .block(block.into_alloy()); + let fetch_token0_balance = token0.balanceOf(pair_address).block(block.into_alloy()); + let fetch_token1_balance = token1.balanceOf(pair_address).block(block.into_alloy()); let pair_contract = - IUniswapLikePair::Instance::new(pair_address.into_alloy(), self.web3.alloy.clone()); + IUniswapLikePair::Instance::new(pair_address, self.web3.alloy.clone()); let fetch_reserves = pair_contract.getReserves().block(block.into_alloy()); let (reserves, token0_balance, token1_balance) = futures::join!( @@ -336,7 +326,7 @@ pub fn handle_contract_error(result: Result) -> Result