From 45cdd00a5290fd843493f828714ce4b73a39100a Mon Sep 17 00:00:00 2001 From: Aryan Godara Date: Mon, 22 Dec 2025 12:40:54 +0800 Subject: [PATCH 1/5] Remove IntoAlloy/IntoLegacy conversions for Balancer V2 pools Removes unnecessary type conversions between ethcontract and alloy types in Balancer V2 pool code. The conversions are no longer needed as the codebase migrates to native alloy types. Updates affected areas: - Remove IntoAlloy/IntoLegacy trait usage for U256, addresses, and pool data - Convert ethcontract::U256 to alloy::primitives::U256 in tests and implementations - Simplify type conversions in stable, weighted, composable stable, and liquidity bootstrapping pools Signed-off-by: Aryan Godara --- .../boundary/liquidity/balancer/v2/stable.rs | 11 +- .../liquidity/balancer/v2/weighted.rs | 9 +- .../src/sources/balancer_v2/graph_api.rs | 17 ++- .../balancer_v2/pool_fetching/pool_storage.rs | 21 ++-- .../src/sources/balancer_v2/pools/common.rs | 69 +++++------ .../balancer_v2/pools/composable_stable.rs | 8 +- .../pools/liquidity_bootstrapping.rs | 4 +- .../src/sources/balancer_v2/pools/stable.rs | 21 ++-- .../src/sources/balancer_v2/pools/weighted.rs | 15 ++- .../sources/balancer_v2/swap/fixed_point.rs | 111 +++++++++-------- .../swap/fixed_point/logexpmath.rs | 112 ++++++++++-------- .../src/sources/balancer_v2/swap/math.rs | 34 +++--- .../src/sources/balancer_v2/swap/mod.rs | 85 +++++++------ .../sources/balancer_v2/swap/stable_math.rs | 55 +++++---- .../sources/balancer_v2/swap/weighted_math.rs | 79 ++++++------ crates/solver/src/liquidity/balancer_v2.rs | 17 +-- .../solvers/src/boundary/liquidity/stable.rs | 11 +- .../boundary/liquidity/weighted_product.rs | 7 +- 18 files changed, 363 insertions(+), 323 deletions(-) diff --git a/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs b/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs index 03b21b48f4..cee05abfff 100644 --- a/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs +++ b/crates/driver/src/boundary/liquidity/balancer/v2/stable.rs @@ -6,7 +6,6 @@ use { liquidity::{self, balancer}, }, }, - ethrpc::alloy::conversions::IntoAlloy, solver::liquidity::{StablePoolOrder, balancer_v2}, }; @@ -28,20 +27,20 @@ pub fn to_domain(id: liquidity::Id, pool: StablePoolOrder) -> Result>()?, )?, amplification_parameter: balancer::v2::stable::AmplificationParameter::new( - pool.amplification_parameter.factor().into_alloy(), - pool.amplification_parameter.precision().into_alloy(), + pool.amplification_parameter.factor(), + pool.amplification_parameter.precision(), )?, - fee: balancer::v2::Fee::from_raw(pool.fee.as_uint256().into_alloy()), + fee: balancer::v2::Fee::from_raw(pool.fee.as_uint256()), }), }) } diff --git a/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs b/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs index 4ddba4063c..f64fc7f2fa 100644 --- a/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs +++ b/crates/driver/src/boundary/liquidity/balancer/v2/weighted.rs @@ -6,7 +6,6 @@ use { liquidity::{self, balancer}, }, }, - ethrpc::alloy::conversions::IntoAlloy, shared::sources::balancer_v2::pool_fetching::WeightedPoolVersion, solver::liquidity::{WeightedProductOrder, balancer_v2}, }; @@ -29,19 +28,19 @@ pub fn to_domain(id: liquidity::Id, pool: WeightedProductOrder) -> Result>()?, )?, - fee: balancer::v2::Fee::from_raw(pool.fee.as_uint256().into_alloy()), + fee: balancer::v2::Fee::from_raw(pool.fee.as_uint256()), version: match pool.version { WeightedPoolVersion::V0 => balancer::v2::weighted::Version::V0, WeightedPoolVersion::V3Plus => balancer::v2::weighted::Version::V3Plus, diff --git a/crates/shared/src/sources/balancer_v2/graph_api.rs b/crates/shared/src/sources/balancer_v2/graph_api.rs index bd2f133a85..faf32d7160 100644 --- a/crates/shared/src/sources/balancer_v2/graph_api.rs +++ b/crates/shared/src/sources/balancer_v2/graph_api.rs @@ -245,6 +245,7 @@ mod tests { use { super::*, crate::sources::balancer_v2::swap::fixed_point::Bfp, + alloy::primitives::U256, ethcontract::H256, maplit::hashmap, }; @@ -343,12 +344,16 @@ mod tests { Token { address: Address::repeat_byte(0x33), decimals: 3, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, Token { address: Address::repeat_byte(0x44), decimals: 4, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, ], }, @@ -381,12 +386,16 @@ mod tests { Token { address: Address::repeat_byte(0x33), decimals: 3, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, Token { address: Address::repeat_byte(0x44), decimals: 4, - weight: Some(Bfp::from_wei(500_000_000_000_000_000u128.into())), + weight: Some(Bfp::from_wei(U256::from( + 500_000_000_000_000_000_u128 + ))), }, ], }, 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 a986bbe877..122c23b834 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 @@ -233,6 +233,7 @@ mod tests { pools::{MockFactoryIndexing, common::MockPoolInfoFetching, weighted}, swap::fixed_point::Bfp, }, + alloy::primitives::U256, maplit::{hashmap, hashset}, mockall::predicate::eq, }; @@ -256,7 +257,9 @@ mod tests { 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 weights: Vec = (start..=end + 1) + .map(|i| Bfp::from_wei(U256::from(i))) + .collect(); let creation_events: Vec<(PoolCreated, u64)> = (start..=end) .map(|i| { ( @@ -284,8 +287,8 @@ mod tests { block_created: 0, }, weights: vec![ - Bfp::from_wei(500_000_000_000_000_000u128.into()), - Bfp::from_wei(500_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), ], }, weighted::PoolInfo { @@ -301,9 +304,9 @@ mod tests { block_created: 0, }, weights: vec![ - Bfp::from_wei(500_000_000_000_000_000u128.into()), - Bfp::from_wei(250_000_000_000_000_000u128.into()), - Bfp::from_wei(250_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(250_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(250_000_000_000_000_000_u128)), ], }, weighted::PoolInfo { @@ -315,8 +318,8 @@ mod tests { block_created: 0, }, weights: vec![ - Bfp::from_wei(500_000_000_000_000_000u128.into()), - Bfp::from_wei(500_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(500_000_000_000_000_000_u128)), ], }, ], @@ -444,7 +447,7 @@ mod tests { scaling_factors: vec![Bfp::exp10(0)], block_created: 3, }, - weights: vec![Bfp::from_wei(1337.into())], + weights: vec![Bfp::from_wei(U256::from(1337u64))], }; let new_creation = PoolCreated { pool: new_pool.common.address, diff --git a/crates/shared/src/sources/balancer_v2/pools/common.rs b/crates/shared/src/sources/balancer_v2/pools/common.rs index 559e23b05b..a37affaa24 100644 --- a/crates/shared/src/sources/balancer_v2/pools/common.rs +++ b/crates/shared/src/sources/balancer_v2/pools/common.rs @@ -9,11 +9,10 @@ use { }, token_info::TokenInfoFetching, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, anyhow::{Context, Result, anyhow, ensure}, contracts::alloy::{BalancerV2BasePool, BalancerV2Vault}, - ethcontract::{BlockId, H256, U256}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethcontract::{BlockId, H256}, futures::{FutureExt as _, future::BoxFuture}, std::{collections::BTreeMap, future::Future, sync::Arc}, tokio::sync::oneshot, @@ -89,7 +88,7 @@ impl PoolInfoFetcher { ) -> Result { let pool = self.base_pool_at(pool_address); - let pool_id = pool.getPoolId().call().await?.into_legacy(); + let pool_id = pool.getPoolId().call().await?; let tokens = self .vault .getPoolTokens(pool_id.0.into()) @@ -99,7 +98,7 @@ impl PoolInfoFetcher { let scaling_factors = self.scaling_factors(&tokens).await?; Ok(PoolInfo { - id: pool_id, + id: H256(pool_id.0), address: pool_address, tokens, scaling_factors, @@ -112,7 +111,7 @@ impl PoolInfoFetcher { pool: &PoolInfo, block: BlockId, ) -> BoxFuture<'static, Result> { - let block = block.into_alloy(); + let block = ethrpc::alloy::conversions::IntoAlloy::into_alloy(block); let pool_address = pool.address; let pool_id = pool.id; let vault = self.vault.clone(); @@ -150,7 +149,7 @@ impl PoolInfoFetcher { async move { let (paused, swap_fee, pool_tokens) = futures::try_join!(fetch_paused, fetch_swap_fee, pool_tokens)?; - let swap_fee = Bfp::from_wei(swap_fee.into_legacy()); + let swap_fee = Bfp::from_wei(swap_fee); let balances = pool_tokens.balances; let tokens = pool_tokens.tokens.into_iter().collect::>(); @@ -160,7 +159,7 @@ impl PoolInfoFetcher { ( address, TokenState { - balance: balance.into_legacy(), + balance, scaling_factor, }, ) @@ -371,7 +370,6 @@ mod tests { }, anyhow::bail, contracts::alloy::BalancerV2Vault, - ethcontract::U256, maplit::{btreemap, hashmap}, mockall::predicate, std::future, @@ -401,7 +399,7 @@ mod tests { &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { tokens: tokens.to_vec(), balances: vec![], - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -431,7 +429,7 @@ mod tests { assert_eq!( pool_info, PoolInfo { - id: pool_id.into_legacy(), + id: H256(pool_id.0), address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)], @@ -463,14 +461,14 @@ mod tests { BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &bfp!("0.003").as_uint256().into_alloy(), + &bfp!("0.003").as_uint256(), ); asserter.push_success(&get_swap_fee_percentage_response); @@ -478,11 +476,8 @@ mod tests { BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { tokens: tokens.to_vec(), - balances: balances - .iter() - .map(|b| b.as_uint256().into_alloy()) - .collect(), - lastChangeBlock: U256::zero().into_alloy(), + balances: balances.iter().map(|b| b.as_uint256()).collect(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -554,15 +549,15 @@ mod tests { BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &U256::zero().into_alloy(), + &U256::ZERO, ); asserter.push_success(&get_swap_fee_percentage_response); @@ -570,8 +565,8 @@ mod tests { BalancerV2Vault::BalancerV2Vault::getPoolTokensCall::abi_encode_returns( &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { 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(), + balances: vec![U256::ZERO, U256::ZERO], + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -619,14 +614,14 @@ mod tests { BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &swap_fee.as_uint256().into_alloy(), + &swap_fee.as_uint256(), ); asserter.push_success(&get_swap_fee_percentage_response); @@ -679,9 +674,9 @@ mod tests { balances: pool_state .tokens .values() - .map(|token| token.common.balance.into_alloy()) + .map(|token| token.common.balance) .collect(), - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -734,15 +729,15 @@ mod tests { BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: true, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &U256::zero().into_alloy(), + &U256::ZERO, ); asserter.push_success(&get_swap_fee_percentage_response); @@ -751,7 +746,7 @@ mod tests { &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { tokens: vec![], balances: vec![], - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); @@ -813,15 +808,15 @@ mod tests { BalancerV2BasePool::BalancerV2BasePool::getPausedStateCall::abi_encode_returns( &BalancerV2BasePool::BalancerV2BasePool::getPausedStateReturn { paused: false, - pauseWindowEndTime: U256::zero().into_alloy(), - bufferPeriodEndTime: U256::zero().into_alloy(), + pauseWindowEndTime: U256::ZERO, + bufferPeriodEndTime: U256::ZERO, }, ); asserter.push_success(&get_paused_state_response); let get_swap_fee_percentage_response = BalancerV2BasePool::BalancerV2BasePool::getSwapFeePercentageCall::abi_encode_returns( - &U256::zero().into_alloy(), + &U256::ZERO, ); asserter.push_success(&get_swap_fee_percentage_response); @@ -830,7 +825,7 @@ mod tests { &BalancerV2Vault::BalancerV2Vault::getPoolTokensReturn { tokens: vec![], balances: vec![], - lastChangeBlock: U256::zero().into_alloy(), + lastChangeBlock: U256::ZERO, }, ); asserter.push_success(&get_pool_tokens_response); 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 68eeb33f00..a5573bd220 100644 --- a/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs +++ b/crates/shared/src/sources/balancer_v2/pools/composable_stable.rs @@ -9,7 +9,7 @@ use { anyhow::Result, contracts::alloy::{BalancerV2ComposableStablePool, BalancerV2ComposableStablePoolFactory}, ethcontract::BlockId, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethrpc::alloy::conversions::IntoAlloy, futures::{FutureExt as _, future::BoxFuture}, }; @@ -81,8 +81,8 @@ impl FactoryIndexing for BalancerV2ComposableStablePoolFactory::Instance { )?; let amplification_parameter = { AmplificationParameter::try_new( - amplification_parameter.value.into_legacy(), - amplification_parameter.precision.into_legacy(), + amplification_parameter.value, + amplification_parameter.precision, )? }; @@ -95,7 +95,7 @@ impl FactoryIndexing for BalancerV2ComposableStablePoolFactory::Instance { ( address, common::TokenState { - scaling_factor: Bfp::from_wei(scaling_factor.into_legacy()), + scaling_factor: Bfp::from_wei(scaling_factor), ..token }, ) 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 8e83f29872..b2b8229f5d 100644 --- a/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs +++ b/crates/shared/src/sources/balancer_v2/pools/liquidity_bootstrapping.rs @@ -12,7 +12,7 @@ use { BalancerV2LiquidityBootstrappingPoolFactory, }, ethcontract::BlockId, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethrpc::alloy::conversions::IntoAlloy, futures::{FutureExt as _, future::BoxFuture}, }; @@ -98,7 +98,7 @@ impl FactoryIndexing for BalancerV2LiquidityBootstrappingPoolFactory::Instance { address, TokenState { common, - weight: Bfp::from_wei(weight.into_legacy()), + weight: Bfp::from_wei(weight), }, ) }) diff --git a/crates/shared/src/sources/balancer_v2/pools/stable.rs b/crates/shared/src/sources/balancer_v2/pools/stable.rs index a236bdfa0b..dd37d543fb 100644 --- a/crates/shared/src/sources/balancer_v2/pools/stable.rs +++ b/crates/shared/src/sources/balancer_v2/pools/stable.rs @@ -9,11 +9,10 @@ use { swap::fixed_point::Bfp, }, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, anyhow::{Result, ensure}, contracts::alloy::{BalancerV2StablePool, BalancerV2StablePoolFactoryV2}, - ethcontract::{BlockId, U256}, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, + ethcontract::BlockId, futures::{FutureExt as _, future::BoxFuture}, num::BigRational, std::collections::BTreeMap, @@ -101,7 +100,7 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { let fetch_amplification_parameter = async move { pool_contract .getAmplificationParameter() - .block(block.into_alloy()) + .block(ethrpc::alloy::conversions::IntoAlloy::into_alloy(block)) .call() .await .map_err(anyhow::Error::from) @@ -112,8 +111,8 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { futures::try_join!(fetch_common, fetch_amplification_parameter)?; let amplification_parameter = { AmplificationParameter::try_new( - amplification_parameter.value.into_legacy(), - amplification_parameter.precision.into_legacy(), + amplification_parameter.value, + amplification_parameter.precision, )? }; @@ -159,21 +158,21 @@ mod tests { #[test] fn amplification_parameter_conversions() { assert_eq!( - AmplificationParameter::try_new(2.into(), 3.into()) + AmplificationParameter::try_new(U256::from(2u64), U256::from(3u64)) .unwrap() - .with_base(1000.into()) + .with_base(U256::from(1000u64)) .unwrap(), - 666.into() + U256::from(666u64) ); assert_eq!( - AmplificationParameter::try_new(7.into(), 8.into()) + AmplificationParameter::try_new(U256::from(7u64), U256::from(8u64)) .unwrap() .as_big_rational(), BigRational::new(7.into(), 8.into()) ); assert_eq!( - AmplificationParameter::try_new(1.into(), 0.into()) + AmplificationParameter::try_new(U256::from(1u64), U256::from(0u64)) .unwrap_err() .to_string(), "Zero precision not allowed" diff --git a/crates/shared/src/sources/balancer_v2/pools/weighted.rs b/crates/shared/src/sources/balancer_v2/pools/weighted.rs index 5420d4dd8f..08dcb73a01 100644 --- a/crates/shared/src/sources/balancer_v2/pools/weighted.rs +++ b/crates/shared/src/sources/balancer_v2/pools/weighted.rs @@ -14,7 +14,6 @@ use { BalancerV2WeightedPoolFactoryV3, }, ethcontract::BlockId, - ethrpc::alloy::conversions::IntoLegacy, futures::{FutureExt as _, future::BoxFuture}, std::collections::BTreeMap, }; @@ -79,7 +78,7 @@ impl FactoryIndexing for BalancerV2WeightedPoolFactory::Instance { .call() .await? .into_iter() - .map(|weight| Bfp::from_wei(weight.into_legacy())) + .map(|weight| Bfp::from_wei(weight)) .collect(); Ok(PoolInfo { @@ -149,12 +148,12 @@ mod tests { super::*, crate::sources::balancer_v2::graph_api::Token, alloy::{ - primitives::Address, + primitives::{Address, U256}, providers::{Provider, ProviderBuilder, mock::Asserter}, sol_types::SolCall, }, ethcontract::H256, - ethrpc::{Web3, alloy::conversions::IntoAlloy, mock::MockTransport}, + ethrpc::{Web3, mock::MockTransport}, futures::future, maplit::btreemap, }; @@ -192,8 +191,8 @@ mod tests { block_created: 42, }, weights: vec![ - Bfp::from_wei(1_337_000_000_000_000_000u128.into()), - Bfp::from_wei(4_200_000_000_000_000_000u128.into()), + Bfp::from_wei(U256::from(1_337_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(4_200_000_000_000_000_000_u128)), ], }, ); @@ -242,7 +241,7 @@ mod tests { let get_normalized_weights_response = BalancerV2WeightedPool::BalancerV2WeightedPool::getNormalizedWeightsCall::abi_encode_returns( &weights.iter() - .map(|w| w.as_uint256().into_alloy()) + .map(|w| w.as_uint256()) .collect() ); asserter.push_success(&get_normalized_weights_response); @@ -273,7 +272,7 @@ mod tests { scaling_factor: Bfp::exp10(0), }, Address::repeat_byte(2) => common::TokenState { - balance: 10_000_000.into(), + balance: U256::from(10_000_000u64), scaling_factor: Bfp::exp10(12), }, }; diff --git a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs b/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs index 44209a0be4..4fd157ef6f 100644 --- a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs +++ b/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs @@ -5,10 +5,10 @@ use { super::error::Error, + alloy::primitives::U256, anyhow::{Context, Result, bail, ensure}, - ethcontract::U256, num::{BigInt, BigRational}, - number::conversions::{big_int_to_u256, u256_to_big_int}, + number::conversions::alloy::{big_int_to_u256, u256_to_big_int}, std::{ convert::TryFrom, fmt::{self, Debug, Formatter}, @@ -27,13 +27,17 @@ mod logexpmath; /// including error codes, from which the name (Balancer Fixed Point). pub struct Bfp(U256); -static ONE_18: LazyLock = LazyLock::new(|| U256::exp10(18)); +fn exp10(n: u8) -> U256 { + U256::from(10u64).pow(U256::from(n)) +} + +static ONE_18: LazyLock = LazyLock::new(|| exp10(18)); static ONE_18_BIGINT: LazyLock = LazyLock::new(|| u256_to_big_int(&ONE_18)); -static ZERO: LazyLock = LazyLock::new(|| Bfp(U256::zero())); +static ZERO: LazyLock = LazyLock::new(|| Bfp(U256::ZERO)); static ONE: LazyLock = LazyLock::new(|| Bfp(*ONE_18)); -static TWO: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * 2)); -static FOUR: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * 4)); -static MAX_POW_RELATIVE_ERROR: LazyLock = LazyLock::new(|| Bfp(10000_usize.into())); +static TWO: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * U256::from(2u64))); +static FOUR: LazyLock = LazyLock::new(|| Bfp(*ONE_18 * U256::from(4u64))); +static MAX_POW_RELATIVE_ERROR: LazyLock = LazyLock::new(|| Bfp(U256::from(10000u64))); impl From for Bfp { fn from(num: usize) -> Self { @@ -72,9 +76,9 @@ impl FromStr for Bfp { if units.is_empty() || decimals.is_empty() || decimals.len() > 18 { bail!("Invalid decimal representation"); } - Ok(Bfp(U256::from_dec_str(&format!("{decimals:0<18}"))? + Ok(Bfp(U256::from_str_radix(&format!("{decimals:0<18}"), 10)? .checked_add( - U256::from_dec_str(units)? + U256::from_str_radix(units, 10)? .checked_mul(*ONE_18) .context("Too large number")?, ) @@ -84,19 +88,18 @@ impl FromStr for Bfp { impl Debug for Bfp { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - write!( - formatter, - "{}.{:0>18}", - self.0 / *ONE_18, - (self.0 % *ONE_18).as_u128() - ) + let remainder = self.0 % *ONE_18; + let low: u128 = remainder.try_into().unwrap_or(0); + write!(formatter, "{}.{:0>18}", self.0 / *ONE_18, low) } } impl Bfp { #[cfg(test)] pub fn to_f64_lossy(self) -> f64 { - self.as_uint256().to_f64_lossy() / 1e18 + // Convert U256 to f64 by taking the high bits + let val: u128 = self.as_uint256().try_into().unwrap_or(u128::MAX); + (val as f64) / 1e18 } pub fn as_uint256(self) -> U256 { @@ -121,7 +124,7 @@ impl Bfp { return Self::zero(); } - Self(U256::exp10(exp as _)) + Self(U256::from(10u64).pow(U256::from(exp as u32))) } pub fn from_wei(num: U256) -> Self { @@ -154,7 +157,7 @@ impl Bfp { Ok(if product.is_zero() { Bfp::zero() } else { - Bfp(((product - 1) / *ONE_18) + 1) + Bfp(((product - U256::from(1u64)) / *ONE_18) + U256::from(1u64)) }) } @@ -177,7 +180,9 @@ impl Bfp { } else { let a_inflated = self.0.checked_mul(*ONE_18).ok_or(Error::DivInternal)?; - Ok(Self(((a_inflated - 1) / other.0) + 1)) + Ok(Self( + ((a_inflated - U256::from(1u64)) / other.0) + U256::from(1u64), + )) } } @@ -191,7 +196,9 @@ impl Bfp { pub fn pow_up(self, exp: Self) -> Result { let raw = Bfp(logexpmath::pow(self.0, exp.0)?); - let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(1.into()))?; + let max_error = raw + .mul_up(*MAX_POW_RELATIVE_ERROR)? + .add(Bfp(U256::from(1u64)))?; raw.add(max_error) } @@ -206,7 +213,9 @@ impl Bfp { square.mul_up(square) } else { let raw = Bfp(logexpmath::pow(self.0, exp.0)?); - let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(1.into()))?; + let max_error = raw + .mul_up(*MAX_POW_RELATIVE_ERROR)? + .add(Bfp(U256::from(1u64)))?; raw.add(max_error) } @@ -220,22 +229,23 @@ mod tests { num::{BigInt, One, Zero}, }; - static EPSILON: LazyLock = LazyLock::new(|| Bfp(U256::one())); + fn test_exp10(n: u8) -> U256 { + U256::from(10u64).pow(U256::from(n)) + } + + static EPSILON: LazyLock = LazyLock::new(|| Bfp(U256::from(1u64))); #[test] fn parsing() { assert_eq!("1".parse::().unwrap(), Bfp::one()); - assert_eq!( - "0.1".parse::().unwrap(), - Bfp::from_wei(U256::exp10(17)) - ); + assert_eq!("0.1".parse::().unwrap(), Bfp::from_wei(test_exp10(17))); assert_eq!( "1.01".parse::().unwrap(), - Bfp::from_wei(U256::exp10(18) + U256::exp10(16)) + Bfp::from_wei(test_exp10(18) + test_exp10(16)) ); assert_eq!( "10.000000000000000001".parse::().unwrap(), - Bfp::from_wei(U256::exp10(19) + U256::one()) + Bfp::from_wei(test_exp10(19) + U256::from(1u64)) ); assert!("10.0000000000000000001".parse::().is_err()); assert!("1.0.1".parse::().is_err()); @@ -246,7 +256,7 @@ mod tests { #[test] fn add() { - assert_eq!(Bfp::from(40).add(2.into()).unwrap(), 42.into()); + assert_eq!(Bfp::from(40).add(Bfp::from(2)).unwrap(), Bfp::from(42)); assert_eq!( Bfp(U256::MAX).add(*EPSILON).unwrap_err(), @@ -256,29 +266,29 @@ mod tests { #[test] fn sub() { - assert_eq!(Bfp::from(50).sub(8.into()).unwrap(), 42.into()); + assert_eq!(Bfp::from(50).sub(Bfp::from(8)).unwrap(), Bfp::from(42)); assert_eq!( - Bfp::one().sub(Bfp(*ONE_18 + 1)).unwrap_err(), + Bfp::one().sub(Bfp(*ONE_18 + U256::from(1u64))).unwrap_err(), Error::SubOverflow ); } macro_rules! test_mul { ($fn_name:ident) => { - assert_eq!(Bfp::from(6).$fn_name(7.into()).unwrap(), 42.into()); + assert_eq!(Bfp::from(6).$fn_name(Bfp::from(7)).unwrap(), Bfp::from(42)); assert_eq!(Bfp::zero().$fn_name(Bfp::one()).unwrap(), Bfp::zero()); assert_eq!(Bfp::one().$fn_name(Bfp::zero()).unwrap(), Bfp::zero()); assert_eq!( Bfp::one() - .$fn_name(Bfp(U256::MAX / U256::exp10(18))) + .$fn_name(Bfp(U256::MAX / test_exp10(18))) .unwrap(), - Bfp(U256::MAX / U256::exp10(18)) + Bfp(U256::MAX / test_exp10(18)) ); assert_eq!( Bfp::one() - .$fn_name(Bfp(U256::MAX / U256::exp10(18) + 1)) + .$fn_name(Bfp(U256::MAX / test_exp10(18) + U256::from(1u64))) .unwrap_err(), Error::MulOverflow, ); @@ -290,14 +300,14 @@ mod tests { test_mul!(mul_down); test_mul!(mul_up); - let one_half = Bfp((5 * 10_u128.pow(17)).into()); + let one_half = Bfp(U256::from(5u64) * U256::from(10u64).pow(U256::from(17u64))); assert_eq!(EPSILON.mul_down(one_half).unwrap(), Bfp::zero()); assert_eq!(EPSILON.mul_up(one_half).unwrap(), *EPSILON); // values used in proof: // shared/src/sources/balancer/swap/weighted_math.rs#L28-L33 - let max_in_ratio = Bfp::from_wei(U256::exp10(17).checked_mul(3_u32.into()).unwrap()); - let balance_in = Bfp::from_wei(U256::MAX / (U256::exp10(17) * U256::from(3))); + let max_in_ratio = Bfp::from_wei(test_exp10(17).checked_mul(U256::from(3u64)).unwrap()); + let balance_in = Bfp::from_wei(U256::MAX / (test_exp10(17) * U256::from(3u64))); assert!(balance_in.mul_down(max_in_ratio).is_ok()); assert!( (balance_in.add(Bfp::one())) @@ -309,15 +319,15 @@ mod tests { macro_rules! test_div { ($fn_name:ident) => { - assert_eq!(Bfp::from(42).div_down(7.into()).unwrap(), 6.into()); - assert_eq!(Bfp::zero().div_down(Bfp::one()).unwrap(), 0.into()); + assert_eq!(Bfp::from(42).div_down(Bfp::from(7)).unwrap(), Bfp::from(6)); + assert_eq!(Bfp::zero().div_down(Bfp::one()).unwrap(), Bfp::from(0)); assert_eq!( Bfp::one().$fn_name(Bfp::zero()).unwrap_err(), Error::ZeroDivision ); assert_eq!( - Bfp(U256::MAX / U256::exp10(18) + 1) + Bfp(U256::MAX / test_exp10(18) + U256::from(1u64)) .$fn_name(Bfp::one()) .unwrap_err(), Error::DivInternal, @@ -330,24 +340,24 @@ mod tests { test_div!(div_down); test_div!(div_up); - assert_eq!(EPSILON.div_down(2.into()).unwrap(), Bfp::zero()); - assert_eq!(EPSILON.div_up(2.into()).unwrap(), *EPSILON); - assert_eq!(Bfp::zero().div_up(1.into()).unwrap(), Bfp::zero()); + assert_eq!(EPSILON.div_down(Bfp::from(2)).unwrap(), Bfp::zero()); + assert_eq!(EPSILON.div_up(Bfp::from(2)).unwrap(), *EPSILON); + assert_eq!(Bfp::zero().div_up(Bfp::from(1)).unwrap(), Bfp::zero()); } #[test] fn pow_up() { assert_eq!( - Bfp::from(2).pow_up(3.into()).unwrap(), + Bfp::from(2).pow_up(Bfp::from(3)).unwrap(), Bfp(U256::from(8_000_000_000_000_079_990_u128)) ); // powDown: 7999999999999919988 assert_eq!( - Bfp::from(2).pow_up(0.into()).unwrap(), + Bfp::from(2).pow_up(Bfp::from(0)).unwrap(), Bfp(U256::from(1_000_000_000_000_010_001_u128)) ); // powDown: 999999999999989999 assert_eq!( Bfp::zero().pow_up(Bfp::one()).unwrap(), - Bfp(U256::from(1_u128)) + Bfp(U256::from(1u64)) ); // powDown: 0 assert_eq!( @@ -356,8 +366,9 @@ mod tests { ); // note: the values were chosen to get a large value from `pow` assert_eq!( - Bfp(U256::from_dec_str( - "287200000000000000000000000000000000000000000000000000000000000000000000000" + Bfp(U256::from_str_radix( + "287200000000000000000000000000000000000000000000000000000000000000000000000", + 10 ) .unwrap()) .pow_up(Bfp::one()) @@ -460,7 +471,7 @@ mod tests { ) .unwrap_err() .to_string(), - "the number is too large for the type" + "the value is too large to fit the target type" ); assert_eq!( Bfp::from_str( diff --git a/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs b/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs index 15375bca70..b320c48995 100644 --- a/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs +++ b/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs @@ -4,7 +4,7 @@ use { super::super::error::Error, - ethcontract::{I256, U256}, + alloy::primitives::{I256, U256}, std::{convert::TryFrom, sync::LazyLock}, }; @@ -12,27 +12,32 @@ use { /// decimal digits. type Ufixed256x18 = U256; -static ONE_18: LazyLock = LazyLock::new(|| I256::exp10(18)); -static ONE_20: LazyLock = LazyLock::new(|| I256::exp10(20)); -static ONE_36: LazyLock = LazyLock::new(|| I256::exp10(36)); +fn i256_exp10(n: u8) -> I256 { + I256::try_from(U256::from(10u64).pow(U256::from(n))).unwrap() +} + +static ONE_18: LazyLock = LazyLock::new(|| i256_exp10(18)); +static ONE_20: LazyLock = LazyLock::new(|| i256_exp10(20)); +static ONE_36: LazyLock = LazyLock::new(|| i256_exp10(36)); static UFIXED256X18_ONE: LazyLock = LazyLock::new(|| U256::try_from(*ONE_18).unwrap()); static MAX_NATURAL_EXPONENT: LazyLock = - LazyLock::new(|| ONE_18.checked_mul(I256::from(130_i128)).unwrap()); + LazyLock::new(|| ONE_18.checked_mul(I256::try_from(130i64).unwrap()).unwrap()); static MIN_NATURAL_EXPONENT: LazyLock = - LazyLock::new(|| ONE_18.checked_mul(I256::from(-41_i128)).unwrap()); + LazyLock::new(|| ONE_18.checked_mul(I256::try_from(-41i64).unwrap()).unwrap()); static LN_36_LOWER_BOUND: LazyLock = - LazyLock::new(|| ONE_18.checked_sub(I256::exp10(17)).unwrap()); + LazyLock::new(|| ONE_18.checked_sub(i256_exp10(17)).unwrap()); static LN_36_UPPER_BOUND: LazyLock = - LazyLock::new(|| ONE_18.checked_add(I256::exp10(17)).unwrap()); + LazyLock::new(|| ONE_18.checked_add(i256_exp10(17)).unwrap()); static MILD_EXPONENT_BOUND: LazyLock = LazyLock::new(|| { - (U256::one() << 254_u32) + let shifted: U256 = U256::from(1u64) << 254; + shifted .checked_div(U256::try_from(*ONE_20).unwrap()) .unwrap() }); fn constant_x_20(i: u32) -> I256 { - match i { + I256::try_from(match i { 2 => 3_200_000_000_000_000_000_000_i128, 3 => 1_600_000_000_000_000_000_000_i128, 4 => 800_000_000_000_000_000_000_i128, @@ -44,19 +49,19 @@ fn constant_x_20(i: u32) -> I256 { 10 => 12_500_000_000_000_000_000_i128, 11 => 6_250_000_000_000_000_000_i128, _ => panic!("Constant not provided"), - } - .into() + }) + .unwrap() } fn constant_x_18(i: u32) -> I256 { - match i { + I256::try_from(match i { 0 => 128_000_000_000_000_000_000_i128, 1 => 64_000_000_000_000_000_000_i128, _ => panic!("Constant not provided"), - } - .into() + }) + .unwrap() } fn constant_a_20(i: u32) -> I256 { - match i { + I256::try_from(match i { 2 => 7_896_296_018_268_069_516_100_000_000_000_000_i128, 3 => 888_611_052_050_787_263_676_000_000_i128, 4 => 298_095_798_704_172_827_474_000_i128, @@ -68,25 +73,33 @@ fn constant_a_20(i: u32) -> I256 { 10 => 113_314_845_306_682_631_683_i128, 11 => 106_449_445_891_785_942_956_i128, _ => panic!("Constant not provided"), - } - .into() + }) + .unwrap() } fn constant_a_18(i: u32) -> I256 { match i { 0 => { - I256::from_dec_str("38877084059945950922200000000000000000000000000000000000").unwrap() + // 38877084059945950922200000000000000000000000000000000000 + I256::try_from( + U256::from_str_radix( + "38877084059945950922200000000000000000000000000000000000", + 10, + ) + .unwrap(), + ) + .unwrap() } - 1 => 6_235_149_080_811_616_882_910_000_000_i128.into(), + 1 => I256::try_from(6_235_149_080_811_616_882_910_000_000_i128).unwrap(), _ => panic!("Constant not provided"), } } pub fn pow(x: Ufixed256x18, y: Ufixed256x18) -> Result { - if y == U256::zero() { + if y == U256::ZERO { return Ok(*UFIXED256X18_ONE); } - if x == U256::zero() { - return Ok(U256::zero()); + if x == U256::ZERO { + return Ok(U256::ZERO); } let x_int256 = match I256::try_from(x) { @@ -120,7 +133,7 @@ fn exp(mut x: I256) -> Result { return Err(Error::InvalidExponent); } - if x < I256::zero() { + if x < I256::ZERO { return Ok((*ONE_18 * *ONE_18) / exp(-x)?); } @@ -132,10 +145,10 @@ fn exp(mut x: I256) -> Result { x -= constant_x_18(1); first_an = constant_a_18(1); } else { - first_an = 1.into(); + first_an = I256::try_from(1i64).unwrap(); } - x *= 100.into(); + x *= I256::try_from(100i64).unwrap(); let mut product = *ONE_20; for i in 2..=9 { @@ -150,11 +163,11 @@ fn exp(mut x: I256) -> Result { series_sum += term; for i in 2..=12 { - term = ((term * x) / *ONE_20) / i.into(); + term = ((term * x) / *ONE_20) / I256::try_from(i).unwrap(); series_sum += term; } - Ok((((product * series_sum) / *ONE_20) * first_an) / 100.into()) + Ok((((product * series_sum) / *ONE_20) * first_an) / I256::try_from(100i64).unwrap()) } fn _ln(mut a: I256) -> I256 { @@ -162,7 +175,7 @@ fn _ln(mut a: I256) -> I256 { return -_ln((*ONE_18 * *ONE_18) / a); } - let mut sum = I256::zero(); + let mut sum = I256::ZERO; for i in 0..=1 { if a >= constant_a_18(i) * *ONE_18 { a /= constant_a_18(i); @@ -170,8 +183,8 @@ fn _ln(mut a: I256) -> I256 { } } - sum *= 100.into(); - a *= 100.into(); + sum *= I256::try_from(100i64).unwrap(); + a *= I256::try_from(100i64).unwrap(); for i in 2..=11 { if a >= constant_a_20(i) { @@ -188,12 +201,12 @@ fn _ln(mut a: I256) -> I256 { for i in (3..=11).step_by(2) { num = (num * z_squared) / *ONE_20; - series_sum += num / i.into(); + series_sum += num / I256::try_from(i).unwrap(); } - series_sum *= 2.into(); + series_sum *= I256::try_from(2i64).unwrap(); - (sum + series_sum) / 100.into() + (sum + series_sum) / I256::try_from(100i64).unwrap() } fn _ln_36(mut x: I256) -> I256 { @@ -207,10 +220,10 @@ fn _ln_36(mut x: I256) -> I256 { for i in (3..=15).step_by(2) { num = (num * z_squared) / *ONE_36; - series_sum += num / i.into(); + series_sum += num / I256::try_from(i).unwrap(); } - series_sum * 2.into() + series_sum * I256::try_from(2i64).unwrap() } #[cfg(test)] @@ -465,11 +478,11 @@ mod tests { for (i, &o) in input.iter().zip(output.iter()) { assert_eq!( pow( - U256::from_dec_str(i[0]).unwrap(), - U256::from_dec_str(i[1]).unwrap() + U256::from_str_radix(i[0], 10).unwrap(), + U256::from_str_radix(i[1], 10).unwrap() ) .unwrap_err(), - o.into() + Error::from(o) ); } } @@ -513,11 +526,11 @@ mod tests { for (i, &o) in input.iter().zip(output.iter()) { assert_eq!( pow( - U256::from_dec_str(i[0]).unwrap(), - U256::from_dec_str(i[1]).unwrap() + U256::from_str_radix(i[0], 10).unwrap(), + U256::from_str_radix(i[1], 10).unwrap() ) .unwrap(), - U256::from_dec_str(o).unwrap() + U256::from_str_radix(o, 10).unwrap() ); } } @@ -550,18 +563,21 @@ mod tests { fn pow_alternate_routes() { assert_eq!( pow( - U256::from_dec_str("0").unwrap(), - U256::from_dec_str("0").unwrap() + U256::from_str_radix("0", 10).unwrap(), + U256::from_str_radix("0", 10).unwrap() ), Ok(*UFIXED256X18_ONE) ); assert_eq!( pow( - U256::from_dec_str("0").unwrap(), - U256::from_dec_str("1").unwrap() + U256::from_str_radix("0", 10).unwrap(), + U256::from_str_radix("1", 10).unwrap() ), - Ok(U256::zero()) + Ok(U256::ZERO) + ); + assert_eq!( + pow(U256::from(10u64).pow(U256::from(18u64)), U256::from(1u64)), + Ok(*UFIXED256X18_ONE) ); - assert_eq!(pow(U256::exp10(18), U256::one()), Ok(*UFIXED256X18_ONE)); } } diff --git a/crates/shared/src/sources/balancer_v2/swap/math.rs b/crates/shared/src/sources/balancer_v2/swap/math.rs index 5c8ee800d9..3a6fc2cc66 100644 --- a/crates/shared/src/sources/balancer_v2/swap/math.rs +++ b/crates/shared/src/sources/balancer_v2/swap/math.rs @@ -1,4 +1,4 @@ -use {super::error::Error, ethcontract::U256}; +use {super::error::Error, alloy::primitives::U256}; pub trait BalU256: Sized { fn bmul(self, other: Self) -> Result; @@ -33,9 +33,9 @@ impl BalU256 for U256 { return Err(Error::ZeroDivision); } if self.is_zero() { - return Ok(U256::zero()); + return Ok(U256::ZERO); } - let one = U256::one(); + let one = U256::from(1u64); Ok(one + (self - one) / other) } } @@ -46,8 +46,8 @@ mod tests { #[test] fn bmul_tests() { - let zero = U256::zero(); - let one = U256::one(); + let zero = U256::ZERO; + let one = U256::from(1u64); let max = U256::MAX; assert_eq!(zero.bmul(one).unwrap(), zero); assert_eq!(one.bmul(one).unwrap(), one); @@ -60,9 +60,9 @@ mod tests { #[test] fn badd_tests() { - let zero = U256::zero(); - let one = U256::one(); - let two = U256::from(2); + let zero = U256::ZERO; + let one = U256::from(1u64); + let two = U256::from(2u64); let max = U256::MAX; assert_eq!(zero.badd(one).unwrap(), one); assert_eq!(one.badd(one).unwrap(), two); @@ -75,9 +75,9 @@ mod tests { #[test] fn bsub_tests() { - let zero = U256::zero(); - let one = U256::one(); - let two = U256::from(2); + let zero = U256::ZERO; + let one = U256::from(1u64); + let two = U256::from(2u64); assert_eq!(two.bsub(zero).unwrap(), two); assert_eq!(two.bsub(one).unwrap(), one); assert_eq!(two.bsub(two).unwrap(), zero); @@ -89,9 +89,9 @@ mod tests { #[test] fn div_down_tests() { - let zero = U256::zero(); - let one = U256::one(); - let two = U256::from(2); + let zero = U256::ZERO; + let one = U256::from(1u64); + let two = U256::from(2u64); assert_eq!(zero.bdiv_down(one).unwrap(), zero); assert_eq!(two.bdiv_down(one).unwrap(), two); assert_eq!(two.bdiv_down(two).unwrap(), one); @@ -104,9 +104,9 @@ mod tests { #[test] fn div_up_tests() { - let zero = U256::zero(); - let one = U256::one(); - let two = U256::from(2); + let zero = U256::ZERO; + let one = U256::from(1u64); + let two = U256::from(2u64); assert_eq!(zero.bdiv_up(one).unwrap(), zero); assert_eq!(two.bdiv_up(one).unwrap(), two); assert_eq!(two.bdiv_up(two).unwrap(), one); diff --git a/crates/shared/src/sources/balancer_v2/swap/mod.rs b/crates/shared/src/sources/balancer_v2/swap/mod.rs index 8e1490bd58..21115da39e 100644 --- a/crates/shared/src/sources/balancer_v2/swap/mod.rs +++ b/crates/shared/src/sources/balancer_v2/swap/mod.rs @@ -11,10 +11,8 @@ use { WeightedTokenState, }, }, - alloy::primitives::Address, + alloy::primitives::{Address, U256}, error::Error, - ethcontract::U256, - ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, fixed_point::Bfp, std::collections::BTreeMap, }; @@ -117,8 +115,7 @@ impl BaselineSolvable for WeightedPoolRef<'_> { out_token: Address, (in_amount, in_token): (alloy::primitives::U256, Address), ) -> Option { - self.get_amount_out_inner(out_token, in_amount.into_legacy(), in_token) - .map(IntoAlloy::into_alloy) + self.get_amount_out_inner(out_token, in_amount, in_token) } async fn get_amount_in( @@ -141,16 +138,15 @@ impl BaselineSolvable for WeightedPoolRef<'_> { in_reserves.weight, out_reserves.common.upscaled_balance().ok()?, out_reserves.weight, - out_reserves.common.upscale(out_amount.into_legacy()).ok()?, + out_reserves.common.upscale(out_amount).ok()?, ) .ok()?; let amount_in_before_fee = in_reserves.common.downscale_up(in_amount).ok()?; let in_amount = add_swap_fee_amount(amount_in_before_fee, self.swap_fee).ok()?; - converge_in_amount(in_amount, out_amount.into_legacy(), |x| { + converge_in_amount(in_amount, out_amount, |x| { self.get_amount_out_inner(out_token, x, in_token) }) - .map(IntoAlloy::into_alloy) } async fn gas_cost(&self) -> usize { @@ -298,8 +294,7 @@ impl StablePoolRef<'_> { if in_token == self.address || out_token == self.address { self.swap_with_bpt() } else { - self.regular_swap_given_in(out_token, (in_amount.into_legacy(), in_token)) - .map(IntoAlloy::into_alloy) + self.regular_swap_given_in(out_token, (in_amount, in_token)) } } } @@ -321,13 +316,10 @@ impl BaselineSolvable for StablePoolRef<'_> { if in_token == self.address || out_token == self.address { self.swap_with_bpt() } else { - let in_amount = - self.regular_swap_given_out(in_token, (out_amount.into_legacy(), out_token))?; - converge_in_amount(in_amount, out_amount.into_legacy(), |x| { - self.get_amount_out_inner(out_token, x.into_alloy(), in_token) - .map(IntoLegacy::into_legacy) + let in_amount = self.regular_swap_given_out(in_token, (out_amount, out_token))?; + converge_in_amount(in_amount, out_amount, |x| { + self.get_amount_out_inner(out_token, x, in_token) }) - .map(IntoAlloy::into_alloy) } } @@ -355,8 +347,8 @@ fn converge_in_amount( // trading price and multiply the amount to bump by 10 for each iteration. let mut bump = (exact_out_amount - out_amount) .checked_mul(in_amount)? - .ceil_div(&out_amount.max(U256::one())) - .max(U256::one()); + .ceil_div(&out_amount.max(U256::from(1u64))) + .max(U256::from(1u64)); for _ in 0..6 { let bumped_in_amount = in_amount.checked_add(bump)?; @@ -365,7 +357,7 @@ fn converge_in_amount( return Some(bumped_in_amount); } - bump *= 10; + bump *= U256::from(10u64); } None @@ -519,7 +511,7 @@ mod tests { balance: Default::default(), scaling_factor: Bfp::exp10(12), }; - let input = Bfp::from_wei(900_546_079_866_630_330_575_i128.into()); + let input = Bfp::from_wei(U256::from(900_546_079_866_630_330_575_u128)); assert_eq!( token_state.downscale_up(input).unwrap(), U256::from(900_546_080_u128) @@ -539,25 +531,25 @@ mod tests { let b = create_weighted_pool_with( vec![crv, sdvecrv_dao], vec![ - 1_850_304_144_768_426_873_445_489_i128.into(), - 95_671_347_892_391_047_965_654_i128.into(), + U256::from(1_850_304_144_768_426_873_445_489_u128), + U256::from(95_671_347_892_391_047_965_654_u128), ], vec![bfp!("0.9"), bfp!("0.1")], vec![Bfp::exp10(0), Bfp::exp10(0)], - 2_000_000_000_000_000_i128.into(), + U256::from(2_000_000_000_000_000_u128), ); assert_eq!( b.get_amount_out( crv, ( - alloy::primitives::U256::from(227_937_106_828_652_254_870_i128), + alloy::primitives::U256::from(227_937_106_828_652_254_870_u128), sdvecrv_dao ) ) .await .unwrap(), - alloy::primitives::U256::from(488_192_591_864_344_551_330_i128) + alloy::primitives::U256::from(488_192_591_864_344_551_330_u128) ); } @@ -569,30 +561,33 @@ mod tests { 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()], + vec![ + U256::from(60_000_000_000_000_000_u128), + U256::from(250_000_000_u128), + ], vec![bfp!("0.5"), bfp!("0.5")], vec![Bfp::exp10(0), Bfp::exp10(12)], - 1_000_000_000_000_000_i128.into(), + U256::from(1_000_000_000_000_000_u128), ); assert_eq!( - b.get_amount_in(weth, (alloy::primitives::U256::from(5_000_000_i128), tusd)) + b.get_amount_in(weth, (alloy::primitives::U256::from(5_000_000_u128), tusd)) .await .unwrap(), - alloy::primitives::U256::from(1_225_715_511_430_411_i128) + alloy::primitives::U256::from(1_225_715_511_430_411_u128) ); } #[test] fn construct_balances_and_token_indices() { let tokens: Vec<_> = (1..=3).map(Address::with_last_byte).collect(); - let balances = (1..=3).map(|n| n.into()).collect(); + let balances = (1..=3).map(|n| U256::from(n)).collect(); let pool = create_stable_pool_with( tokens.clone(), balances, - AmplificationParameter::try_new(1.into(), 1.into()).unwrap(), + AmplificationParameter::try_new(U256::from(1u64), U256::from(1u64)).unwrap(), vec![Bfp::exp10(18), Bfp::exp10(18), Bfp::exp10(18)], - 1.into(), + U256::from(1u64), ); for token_i in tokens.iter() { @@ -632,13 +627,13 @@ mod tests { let tokens = vec![dai, usdc, tusd]; let scaling_exps = vec![Bfp::exp10(0), Bfp::exp10(12), Bfp::exp10(12)]; let amplification_parameter = - AmplificationParameter::try_new(570000.into(), 1000.into()).unwrap(); + AmplificationParameter::try_new(U256::from(570000u64), U256::from(1000u64)).unwrap(); let balances = vec![ - 40_927_687_702_846_622_465_144_342_i128.into(), - 59_448_574_675_062_i128.into(), - 55_199_308_926_456_i128.into(), + U256::from(40_927_687_702_846_622_465_144_342_u128), + U256::from(59_448_574_675_062_u128), + U256::from(55_199_308_926_456_u128), ]; - let swap_fee_percentage = 300_000_000_000_000u128.into(); + let swap_fee_percentage = U256::from(300_000_000_000_000_u128); let pool = create_stable_pool_with( tokens, balances, @@ -648,8 +643,8 @@ mod tests { ); // Etherscan for amount verification: // https://etherscan.io/tx/0x75be93fff064ad46b423b9e20cee09b0ae7f741087f43e4187d4f4cf59f54229 - let amount_in = alloy::primitives::U256::from(1_886_982_823_746_269_817_650_i128); - let amount_out = 1_887_770_905_i128; + let amount_in = alloy::primitives::U256::from(1_886_982_823_746_269_817_650_u128); + let amount_out = U256::from(1_887_770_905_u128); let res_out = pool.get_amount_out(usdc, (amount_in, dai)).await; assert_eq!(res_out.unwrap(), amount_out); } @@ -665,13 +660,13 @@ mod tests { let tokens = vec![dai, usdc, tusd]; let scaling_exps = vec![Bfp::exp10(0), Bfp::exp10(12), Bfp::exp10(12)]; let amplification_parameter = - AmplificationParameter::try_new(570000.into(), 1000.into()).unwrap(); + AmplificationParameter::try_new(U256::from(570000u64), U256::from(1000u64)).unwrap(); let balances = vec![ - 34_869_494_603_218_073_631_628_580_i128.into(), - 48_176_005_970_419_i128.into(), - 44_564_350_355_030_i128.into(), + U256::from(34_869_494_603_218_073_631_628_580_u128), + U256::from(48_176_005_970_419_u128), + U256::from(44_564_350_355_030_u128), ]; - let swap_fee_percentage = 300_000_000_000_000u128.into(); + let swap_fee_percentage = U256::from(300_000_000_000_000_u128); let pool = create_stable_pool_with( tokens, balances, @@ -681,7 +676,7 @@ mod tests { ); // Etherscan for amount verification: // https://etherscan.io/tx/0x38487122158eef6b63570b5d3754ddc223c63af5c049d7b80acacb9e8ca89a63 - let amount_in = 900_816_325_i128; + let amount_in = U256::from(900_816_325_u128); let amount_out = alloy::primitives::U256::from(900_000_000_000_000_000_000_u128); let res_out = pool.get_amount_in(usdc, (amount_out, dai)).await; assert_eq!(res_out.unwrap(), amount_in); diff --git a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs index f1860b0459..fda346fcc6 100644 --- a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs +++ b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs @@ -5,15 +5,15 @@ use { super::error::Error, crate::sources::balancer_v2::swap::{fixed_point::Bfp, math::BalU256}, - ethcontract::U256, + alloy::primitives::U256, std::sync::LazyLock, }; -pub static AMP_PRECISION: LazyLock = LazyLock::new(|| U256::from(1000)); +pub static AMP_PRECISION: LazyLock = LazyLock::new(|| U256::from(1000u64)); /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/9eb7e44a4e9ebbadfe3c6242a086118298cadc9f/pkg/pool-stable-phantom/contracts/StableMath.sol#L57-L119 fn calculate_invariant(amplification_parameter: U256, balances: &[Bfp]) -> Result { - let mut sum = U256::zero(); + let mut sum = U256::ZERO; let num_tokens_usize = balances.len(); for balance_i in balances.iter() { sum = sum.badd(balance_i.as_uint256())?; @@ -48,7 +48,7 @@ fn calculate_invariant(amplification_parameter: U256, balances: &[Bfp]) -> Resul .bsub(*AMP_PRECISION)? .bmul(invariant)? .bdiv_down(*AMP_PRECISION)? - .badd(num_tokens.badd(1.into())?.bmul(d_p)?)?; + .badd(num_tokens.badd(U256::from(1u64))?.bmul(d_p)?)?; invariant = numerator.bdiv_down(denominator)?; match convergence_criteria(invariant, prev_invariant) { None => continue, @@ -89,7 +89,7 @@ pub fn calc_out_given_in( balances[token_index_out] .sub(final_balance_out)? - .sub(Bfp::from_wei(1.into())) + .sub(Bfp::from_wei(U256::from(1u64))) } /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/ad1442113b26ec22081c2047e2ec95355a7f12ba/pkg/pool-stable/contracts/StableMath.sol#L152-L190 @@ -124,7 +124,7 @@ pub fn calc_in_given_out( final_balance_in .sub(balances[token_index_in])? - .add(Bfp::from_wei(1.into())) + .add(Bfp::from_wei(U256::from(1u64))) } /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/ad1442113b26ec22081c2047e2ec95355a7f12ba/pkg/pool-stable/contracts/StableMath.sol#L465-L516 @@ -177,10 +177,12 @@ fn get_token_balance_given_invariant_and_all_other_balances( // Math.mul(tokenBalance, tokenBalance).add(c), // Math.mul(tokenBalance, 2).add(b).sub(invariant) // ); - token_balance = token_balance - .bmul(token_balance)? - .badd(c)? - .bdiv_up(token_balance.bmul(2.into())?.badd(b)?.bsub(invariant)?)?; + token_balance = token_balance.bmul(token_balance)?.badd(c)?.bdiv_up( + token_balance + .bmul(U256::from(2u64))? + .badd(b)? + .bsub(invariant)?, + )?; match convergence_criteria(token_balance, prev_token_balance) { None => continue, Some(token_balance) => return Ok(Bfp::from_wei(token_balance)), @@ -190,7 +192,7 @@ fn get_token_balance_given_invariant_and_all_other_balances( } fn convergence_criteria(curr_value: U256, prev_value: U256) -> Option { - let one = U256::one(); + let one = U256::from(1u64); if curr_value > prev_value { if curr_value .bsub(prev_value) @@ -222,10 +224,19 @@ mod tests { use { super::*, crate::sources::balancer_v2::swap::fixed_point::Bfp, - ethcontract::U256, + alloy::primitives::U256, std::str::FromStr, }; + fn u256_from_f64_lossy(val: f64) -> U256 { + U256::from(val as u64) + } + + fn u256_to_f64_lossy(val: U256) -> f64 { + let v: u128 = val.try_into().unwrap_or(u128::MAX); + v as f64 + } + // interpreted from // https://github.com/balancer-labs/balancer-v2-monorepo/blob/stable-deployment/pvt/helpers/src/models/pools/stable/math.ts#L53 fn calculate_analytic_invariant_two_tokens( @@ -341,7 +352,7 @@ mod tests { #[test] fn invariant_two_tokens_ok() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12)]; let max_relative_error = 0.001; let expected = calculate_analytic_invariant_two_tokens( @@ -351,7 +362,7 @@ mod tests { ); let result = calculate_invariant(amplification_parameter, &balances).unwrap(); assert!( - (result.to_f64_lossy() / 1e18 - expected) + (u256_to_f64_lossy(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -364,13 +375,13 @@ mod tests { .iter() .map(|x| Bfp::from_str(x).unwrap()) .collect(); - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); let result = calculate_invariant(amplification_parameter, balances.as_slice()).unwrap(); let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); let max_relative_error = 0.001; assert!( - (result.to_f64_lossy() / 1e18 - expected) + (u256_to_f64_lossy(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -379,14 +390,14 @@ mod tests { #[test] fn invariant_three_tokens_ok() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); let max_relative_error = 0.001; let result = calculate_invariant(amplification_parameter, &balances).unwrap(); assert!( - (result.to_f64_lossy() / 1e18 - expected) + (u256_to_f64_lossy(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -395,7 +406,7 @@ mod tests { #[test] fn in_given_out_two_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -427,7 +438,7 @@ mod tests { #[test] fn in_given_out_three_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -459,7 +470,7 @@ mod tests { #[test] fn out_given_in_two_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -491,7 +502,7 @@ mod tests { #[test] fn out_given_in_three_tokens() { let amp = 100.; - let amplification_parameter = U256::from_f64_lossy(amp * AMP_PRECISION.to_f64_lossy()); + let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; diff --git a/crates/shared/src/sources/balancer_v2/swap/weighted_math.rs b/crates/shared/src/sources/balancer_v2/swap/weighted_math.rs index f978eab496..658f3025cb 100644 --- a/crates/shared/src/sources/balancer_v2/swap/weighted_math.rs +++ b/crates/shared/src/sources/balancer_v2/swap/weighted_math.rs @@ -4,15 +4,19 @@ use { super::{error::Error, fixed_point::Bfp}, - ethcontract::U256, + alloy::primitives::U256, std::sync::LazyLock, }; +fn exp10(n: u8) -> U256 { + U256::from(10u64).pow(U256::from(n)) +} + // https://github.com/balancer-labs/balancer-v2-monorepo/blob/6c9e24e22d0c46cca6dd15861d3d33da61a60b98/pkg/core/contracts/pools/weighted/WeightedMath.sol#L36-L37 static MAX_IN_RATIO: LazyLock = - LazyLock::new(|| Bfp::from_wei(U256::exp10(17).checked_mul(3_u32.into()).unwrap())); + LazyLock::new(|| Bfp::from_wei(exp10(17).checked_mul(U256::from(3u64)).unwrap())); static MAX_OUT_RATIO: LazyLock = - LazyLock::new(|| Bfp::from_wei(U256::exp10(17).checked_mul(3_u32.into()).unwrap())); + LazyLock::new(|| Bfp::from_wei(exp10(17).checked_mul(U256::from(3u64)).unwrap())); /// https://github.com/balancer-labs/balancer-v2-monorepo/blob/6c9e24e22d0c46cca6dd15861d3d33da61a60b98/pkg/core/contracts/pools/weighted/WeightedMath.sol#L69-L100 /// It is not possible for the following addition balance_in.add(amount_in) to @@ -143,17 +147,17 @@ mod tests { fn calc_out_given_in_ok() { assert_eq!( calc_out_given_in( - Bfp::from_wei(100_000_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(300_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(700_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_u128.into()), + Bfp::from_wei(U256::from(100_000_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(300_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(700_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_u128)), ) .unwrap(), // (await weightedMath["_calcOutGivenIn"]("100000000000000000000000", // "300000000000000", "10000000000000000000", "700000000000000", // "10000000000000000")).toString() - Bfp::from_wei(428_571_297_950_u128.into()), + Bfp::from_wei(U256::from(428_571_297_950_u128)), ); } @@ -161,28 +165,28 @@ mod tests { fn calc_in_given_out_ok() { assert_eq!( calc_in_given_out( - Bfp::from_wei(100_000_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(300_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_000_u128.into()), - Bfp::from_wei(700_000_000_000_000_u128.into()), - Bfp::from_wei(10_000_000_000_000_000_u128.into()), + Bfp::from_wei(U256::from(100_000_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(300_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_000_u128)), + Bfp::from_wei(U256::from(700_000_000_000_000_u128)), + Bfp::from_wei(U256::from(10_000_000_000_000_000_u128)), ) .unwrap(), // (await weightedMath["_calcInGivenOut"]("100000000000000000000000", // "300000000000000", "10000000000000000000", "700000000000000", // "10000000000000000")).toString() - Bfp::from_wei(233_722_784_701_541_000_000_u128.into()), + Bfp::from_wei(U256::from(233_722_784_701_541_000_000_u128)), ); } #[test] fn calc_out_given_in_err() { - let zero = Bfp::from_wei(0.into()); - let one = Bfp::from_wei(1.into()); - let two = Bfp::from_wei(2.into()); + let zero = Bfp::from_wei(U256::from(0u64)); + let one = Bfp::from_wei(U256::from(1u64)); + let two = Bfp::from_wei(U256::from(2u64)); let max_u256 = Bfp::from_wei(U256::MAX); - let max_balance_in = Bfp::from_wei(U256::MAX / (U256::exp10(17) * U256::from(3))); - let mid_u256 = Bfp::from_wei(u128::MAX.into()); + let max_balance_in = Bfp::from_wei(U256::MAX / (exp10(17) * U256::from(3u64))); + let mid_u256 = Bfp::from_wei(U256::from(u128::MAX)); assert_eq!( calc_out_given_in(max_u256, zero, zero, zero, two) .unwrap_err() @@ -234,12 +238,12 @@ mod tests { #[test] fn calc_in_given_out_err() { - let zero = Bfp::from_wei(0.into()); - let one = Bfp::from_wei(1.into()); - let two = Bfp::from_wei(2.into()); + let zero = Bfp::from_wei(U256::from(0u64)); + let one = Bfp::from_wei(U256::from(1u64)); + let two = Bfp::from_wei(U256::from(2u64)); let max_u256 = Bfp::from_wei(U256::MAX); - let max_balance = Bfp::from_wei(U256::MAX / (U256::exp10(17) * U256::from(3))); - let mid_u256 = Bfp::from_wei(u128::MAX.into()); + let max_balance = Bfp::from_wei(U256::MAX / (exp10(17) * U256::from(3u64))); + let mid_u256 = Bfp::from_wei(U256::from(u128::MAX)); assert_eq!( calc_in_given_out(one, zero, max_u256, zero, two) .unwrap_err() @@ -299,10 +303,10 @@ mod tests { macro_rules! calc_with_default_pool { ($fn_name:ident, $amount: expr_2021) => { $fn_name( - Bfp::from_wei(deposit_in.into()), - Bfp::from_wei(500_000_000_000_000_u128.into()), - Bfp::from_wei(deposit_out.into()), - Bfp::from_wei(500_000_000_000_000_u128.into()), + Bfp::from_wei(U256::from(deposit_in)), + Bfp::from_wei(U256::from(500_000_000_000_000_u128)), + Bfp::from_wei(U256::from(deposit_out)), + Bfp::from_wei(U256::from(500_000_000_000_000_u128)), Bfp::from_wei($amount), ) }; @@ -314,26 +318,27 @@ mod tests { let largest_amount_in = deposit_in * 3 / 10; assert_eq!( - calc_with_default_pool!(calc_out_given_in, largest_amount_in.into()).unwrap(), + calc_with_default_pool!(calc_out_given_in, U256::from(largest_amount_in)).unwrap(), // > await calc_with_default_pool("_calcOutGivenIn", "6000000000000000000000") - Bfp::from_wei(2_307_692_307_692_230_750_000_u128.into()) + Bfp::from_wei(U256::from(2_307_692_307_692_230_750_000_u128)) ); assert_eq!( - calc_with_default_pool!(calc_out_given_in, (largest_amount_in + 1).into()).unwrap_err(), + calc_with_default_pool!(calc_out_given_in, U256::from(largest_amount_in + 1)) + .unwrap_err(), // > await calc_with_default_pool("_calcOutGivenIn", "6000000000000000000001") - "304".into() + Error::MaxInRatio ); let largest_amount_out = deposit_out * 3 / 10; assert_eq!( - calc_with_default_pool!(calc_in_given_out, largest_amount_out.into()).unwrap(), + calc_with_default_pool!(calc_in_given_out, U256::from(largest_amount_out)).unwrap(), // > await calc_with_default_pool("_calcInGivenOut", "3000000000000000000000") - Bfp::from_wei(8_571_428_571_428_857_160_000_u128.into()) + Bfp::from_wei(U256::from(8_571_428_571_428_857_160_000_u128)) ); assert_eq!( - calc_with_default_pool!(calc_in_given_out, (largest_amount_out + 1).into()) + calc_with_default_pool!(calc_in_given_out, U256::from(largest_amount_out + 1)) .unwrap_err(), // > await calc_with_default_pool("_calcInGivenOut", "3000000000000000000001") - "305".into() + Error::MaxOutRatio ); } } diff --git a/crates/solver/src/liquidity/balancer_v2.rs b/crates/solver/src/liquidity/balancer_v2.rs index d0f3a66c48..b81d0ee9a7 100644 --- a/crates/solver/src/liquidity/balancer_v2.rs +++ b/crates/solver/src/liquidity/balancer_v2.rs @@ -285,21 +285,21 @@ mod tests { reserves: btreemap! { Address::repeat_byte(0x70) => WeightedTokenState { common: TokenState { - balance: 100.into(), + balance: U256::from(100), scaling_factor: Bfp::exp10(16), }, weight: "0.25".parse().unwrap(), }, Address::repeat_byte(0x71) => WeightedTokenState { common: TokenState { - balance: 1_000_000.into(), + balance: U256::from(1_000_000), scaling_factor: Bfp::exp10(12), }, weight: "0.25".parse().unwrap(), }, Address::repeat_byte(0xb0) => WeightedTokenState { common: TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, weight: "0.5".parse().unwrap(), @@ -317,14 +317,14 @@ mod tests { reserves: btreemap! { Address::repeat_byte(0x73) => WeightedTokenState { common: TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, weight: "0.5".parse().unwrap(), }, Address::repeat_byte(0xb0) => WeightedTokenState { common: TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, weight: "0.5".parse().unwrap(), @@ -341,14 +341,15 @@ mod tests { swap_fee: "0.002".parse().unwrap(), paused: true, }, - amplification_parameter: AmplificationParameter::try_new(1.into(), 1.into()).unwrap(), + amplification_parameter: AmplificationParameter::try_new(U256::from(1), U256::from(1)) + .unwrap(), reserves: btreemap! { Address::repeat_byte(0x73) => TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), }, Address::repeat_byte(0xb0) => TokenState { - balance: 1_000_000_000_000_000_000u128.into(), + balance: U256::from(1_000_000_000_000_000_000u128), scaling_factor: Bfp::exp10(0), } }, diff --git a/crates/solvers/src/boundary/liquidity/stable.rs b/crates/solvers/src/boundary/liquidity/stable.rs index 5cc9ecddd0..ab10f26db6 100644 --- a/crates/solvers/src/boundary/liquidity/stable.rs +++ b/crates/solvers/src/boundary/liquidity/stable.rs @@ -2,7 +2,6 @@ pub use shared::sources::balancer_v2::pool_fetching::StablePool as Pool; use { crate::domain::{eth, liquidity}, alloy::primitives::{Address, B256, U256}, - ethrpc::alloy::conversions::IntoLegacy, shared::sources::balancer_v2::{ pool_fetching::{AmplificationParameter, CommonPoolState, TokenState}, swap::fixed_point::Bfp, @@ -26,21 +25,21 @@ pub fn to_boundary_pool(address: Address, pool: &liquidity::stable::Pool) -> Opt Some(( reserve.asset.token.0, TokenState { - balance: reserve.asset.amount.into_legacy(), + balance: reserve.asset.amount, scaling_factor: to_fixed_point(&reserve.scale.get())?, }, )) }) .collect::>()?; let amplification_parameter = AmplificationParameter::try_new( - pool.amplification_parameter.numer().into_legacy(), - pool.amplification_parameter.denom().into_legacy(), + *pool.amplification_parameter.numer(), + *pool.amplification_parameter.denom(), ) .ok()?; Some(Pool { common: CommonPoolState { - id: id.into_legacy(), + id: ethrpc::alloy::conversions::IntoLegacy::into_legacy(id), address, swap_fee, paused: false, @@ -57,5 +56,5 @@ fn to_fixed_point(ratio: ð::Rational) -> Option { // this format. let base = U256::from(10).pow(U256::from(18)); let wei = ratio.numer().checked_mul(base)? / ratio.denom(); - Some(Bfp::from_wei(wei.into_legacy())) + Some(Bfp::from_wei(wei)) } diff --git a/crates/solvers/src/boundary/liquidity/weighted_product.rs b/crates/solvers/src/boundary/liquidity/weighted_product.rs index 20839258ac..8d4facf5e7 100644 --- a/crates/solvers/src/boundary/liquidity/weighted_product.rs +++ b/crates/solvers/src/boundary/liquidity/weighted_product.rs @@ -2,7 +2,6 @@ pub use shared::sources::balancer_v2::pool_fetching::WeightedPool as Pool; use { crate::domain::{eth, liquidity}, alloy::primitives::{Address, B256, U256}, - ethrpc::alloy::conversions::IntoLegacy, shared::sources::balancer_v2::{ pool_fetching::{CommonPoolState, TokenState, WeightedPoolVersion, WeightedTokenState}, swap::fixed_point::Bfp, @@ -30,7 +29,7 @@ pub fn to_boundary_pool( reserve.asset.token.0, WeightedTokenState { common: TokenState { - balance: reserve.asset.amount.into_legacy(), + balance: reserve.asset.amount, scaling_factor: to_fixed_point(&reserve.scale.get())?, }, weight: to_fixed_point(&reserve.weight)?, @@ -41,7 +40,7 @@ pub fn to_boundary_pool( Some(Pool { common: CommonPoolState { - id: id.into_legacy(), + id: ethrpc::alloy::conversions::IntoLegacy::into_legacy(id), address, swap_fee, paused: false, @@ -61,5 +60,5 @@ fn to_fixed_point(ratio: ð::Rational) -> Option { // this format. let base = U256::from(10).pow(U256::from(18)); let wei = ratio.numer().checked_mul(base)? / ratio.denom(); - Some(Bfp::from_wei(wei.into_legacy())) + Some(Bfp::from_wei(wei)) } From 0a8f1ec719c8eed4a9d3db8151f6d8413bf51b8e Mon Sep 17 00:00:00 2001 From: Aryan Godara Date: Tue, 6 Jan 2026 15:54:54 +0530 Subject: [PATCH 2/5] chore: remove unnecessary closure, fix clippy warning --- crates/shared/src/sources/balancer_v2/pools/weighted.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/shared/src/sources/balancer_v2/pools/weighted.rs b/crates/shared/src/sources/balancer_v2/pools/weighted.rs index 08dcb73a01..1a7f31e231 100644 --- a/crates/shared/src/sources/balancer_v2/pools/weighted.rs +++ b/crates/shared/src/sources/balancer_v2/pools/weighted.rs @@ -78,7 +78,7 @@ impl FactoryIndexing for BalancerV2WeightedPoolFactory::Instance { .call() .await? .into_iter() - .map(|weight| Bfp::from_wei(weight)) + .map(Bfp::from_wei) .collect(); Ok(PoolInfo { From 89828679766f255b307f293ff589c02b920b757e Mon Sep 17 00:00:00 2001 From: Aryan Godara Date: Tue, 6 Jan 2026 18:23:05 +0530 Subject: [PATCH 3/5] Improve numeric conversions in Balancer V2 fixed point math - Replace lossy unwrap_or fallbacks with direct unwrap() in Bfp Debug impl - Fix to_f64_lossy() to use string parsing for accurate large value conversion - Update test helper functions to use string-based U256/f64 conversions instead of lossy casts - Simplify into_legacy() calls by using method syntax instead of fully qualified paths --- .../src/sources/balancer_v2/swap/fixed_point.rs | 13 +++++++++---- .../src/sources/balancer_v2/swap/stable_math.rs | 5 ++--- crates/solvers/src/boundary/liquidity/stable.rs | 3 ++- .../src/boundary/liquidity/weighted_product.rs | 3 ++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs b/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs index 4fd157ef6f..f40f67205c 100644 --- a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs +++ b/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs @@ -89,7 +89,7 @@ impl FromStr for Bfp { impl Debug for Bfp { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { let remainder = self.0 % *ONE_18; - let low: u128 = remainder.try_into().unwrap_or(0); + let low: u128 = remainder.try_into().unwrap(); write!(formatter, "{}.{:0>18}", self.0 / *ONE_18, low) } } @@ -97,9 +97,14 @@ impl Debug for Bfp { impl Bfp { #[cfg(test)] pub fn to_f64_lossy(self) -> f64 { - // Convert U256 to f64 by taking the high bits - let val: u128 = self.as_uint256().try_into().unwrap_or(u128::MAX); - (val as f64) / 1e18 + // NOTE: This conversion is lossy and may not be accurate for large values. + // It is only intended for use in tests. + let val: f64 = self + .as_uint256() + .to_string() + .parse() + .unwrap_or(f64::INFINITY); + val / 1e18 } pub fn as_uint256(self) -> U256 { diff --git a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs index fda346fcc6..63160c17b9 100644 --- a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs +++ b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs @@ -229,12 +229,11 @@ mod tests { }; fn u256_from_f64_lossy(val: f64) -> U256 { - U256::from(val as u64) + U256::from_str_radix(&val.round().to_string(), 10).unwrap_or(U256::MAX) } fn u256_to_f64_lossy(val: U256) -> f64 { - let v: u128 = val.try_into().unwrap_or(u128::MAX); - v as f64 + val.to_string().parse().unwrap_or(f64::INFINITY) } // interpreted from diff --git a/crates/solvers/src/boundary/liquidity/stable.rs b/crates/solvers/src/boundary/liquidity/stable.rs index ab10f26db6..a0479aa4f3 100644 --- a/crates/solvers/src/boundary/liquidity/stable.rs +++ b/crates/solvers/src/boundary/liquidity/stable.rs @@ -2,6 +2,7 @@ pub use shared::sources::balancer_v2::pool_fetching::StablePool as Pool; use { crate::domain::{eth, liquidity}, alloy::primitives::{Address, B256, U256}, + ethrpc::alloy::conversions::IntoLegacy, shared::sources::balancer_v2::{ pool_fetching::{AmplificationParameter, CommonPoolState, TokenState}, swap::fixed_point::Bfp, @@ -39,7 +40,7 @@ pub fn to_boundary_pool(address: Address, pool: &liquidity::stable::Pool) -> Opt Some(Pool { common: CommonPoolState { - id: ethrpc::alloy::conversions::IntoLegacy::into_legacy(id), + id: id.into_legacy(), address, swap_fee, paused: false, diff --git a/crates/solvers/src/boundary/liquidity/weighted_product.rs b/crates/solvers/src/boundary/liquidity/weighted_product.rs index 8d4facf5e7..d96cc1faa8 100644 --- a/crates/solvers/src/boundary/liquidity/weighted_product.rs +++ b/crates/solvers/src/boundary/liquidity/weighted_product.rs @@ -2,6 +2,7 @@ pub use shared::sources::balancer_v2::pool_fetching::WeightedPool as Pool; use { crate::domain::{eth, liquidity}, alloy::primitives::{Address, B256, U256}, + ethrpc::alloy::conversions::IntoLegacy, shared::sources::balancer_v2::{ pool_fetching::{CommonPoolState, TokenState, WeightedPoolVersion, WeightedTokenState}, swap::fixed_point::Bfp, @@ -40,7 +41,7 @@ pub fn to_boundary_pool( Some(Pool { common: CommonPoolState { - id: ethrpc::alloy::conversions::IntoLegacy::into_legacy(id), + id: id.into_legacy(), address, swap_fee, paused: false, From 2d3185db2a07f0dc311fb8959cecc05fbff3497d Mon Sep 17 00:00:00 2001 From: Aryan Godara Date: Wed, 7 Jan 2026 17:17:55 +0530 Subject: [PATCH 4/5] address PR comments --- .../src/sources/balancer_v2/pools/common.rs | 7 +- .../src/sources/balancer_v2/pools/stable.rs | 3 +- .../sources/balancer_v2/swap/fixed_point.rs | 41 +++------ .../swap/fixed_point/logexpmath.rs | 91 ++++++++++--------- .../sources/balancer_v2/swap/stable_math.rs | 24 ++--- 5 files changed, 76 insertions(+), 90 deletions(-) diff --git a/crates/shared/src/sources/balancer_v2/pools/common.rs b/crates/shared/src/sources/balancer_v2/pools/common.rs index a37affaa24..12e056b88f 100644 --- a/crates/shared/src/sources/balancer_v2/pools/common.rs +++ b/crates/shared/src/sources/balancer_v2/pools/common.rs @@ -13,6 +13,7 @@ use { anyhow::{Context, Result, anyhow, ensure}, contracts::alloy::{BalancerV2BasePool, BalancerV2Vault}, ethcontract::{BlockId, H256}, + ethrpc::alloy::conversions::{IntoAlloy, IntoLegacy}, futures::{FutureExt as _, future::BoxFuture}, std::{collections::BTreeMap, future::Future, sync::Arc}, tokio::sync::oneshot, @@ -98,7 +99,7 @@ impl PoolInfoFetcher { let scaling_factors = self.scaling_factors(&tokens).await?; Ok(PoolInfo { - id: H256(pool_id.0), + id: pool_id.into_legacy(), address: pool_address, tokens, scaling_factors, @@ -111,7 +112,7 @@ impl PoolInfoFetcher { pool: &PoolInfo, block: BlockId, ) -> BoxFuture<'static, Result> { - let block = ethrpc::alloy::conversions::IntoAlloy::into_alloy(block); + let block = block.into_alloy(); let pool_address = pool.address; let pool_id = pool.id; let vault = self.vault.clone(); @@ -429,7 +430,7 @@ mod tests { assert_eq!( pool_info, PoolInfo { - id: H256(pool_id.0), + id: pool_id.into_legacy(), address: *pool.address(), tokens: tokens.to_vec(), scaling_factors: vec![Bfp::exp10(0), Bfp::exp10(0), Bfp::exp10(12)], diff --git a/crates/shared/src/sources/balancer_v2/pools/stable.rs b/crates/shared/src/sources/balancer_v2/pools/stable.rs index dd37d543fb..be9f1f262a 100644 --- a/crates/shared/src/sources/balancer_v2/pools/stable.rs +++ b/crates/shared/src/sources/balancer_v2/pools/stable.rs @@ -13,6 +13,7 @@ use { anyhow::{Result, ensure}, contracts::alloy::{BalancerV2StablePool, BalancerV2StablePoolFactoryV2}, ethcontract::BlockId, + ethrpc::alloy::conversions::IntoAlloy, futures::{FutureExt as _, future::BoxFuture}, num::BigRational, std::collections::BTreeMap, @@ -100,7 +101,7 @@ impl FactoryIndexing for BalancerV2StablePoolFactoryV2::Instance { let fetch_amplification_parameter = async move { pool_contract .getAmplificationParameter() - .block(ethrpc::alloy::conversions::IntoAlloy::into_alloy(block)) + .block(block.into_alloy()) .call() .await .map_err(anyhow::Error::from) diff --git a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs b/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs index f40f67205c..80e43e0860 100644 --- a/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs +++ b/crates/shared/src/sources/balancer_v2/swap/fixed_point.rs @@ -88,8 +88,7 @@ impl FromStr for Bfp { impl Debug for Bfp { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - let remainder = self.0 % *ONE_18; - let low: u128 = remainder.try_into().unwrap(); + let low: u128 = u128::try_from(self.0 % *ONE_18).unwrap(); write!(formatter, "{}.{:0>18}", self.0 / *ONE_18, low) } } @@ -97,14 +96,7 @@ impl Debug for Bfp { impl Bfp { #[cfg(test)] pub fn to_f64_lossy(self) -> f64 { - // NOTE: This conversion is lossy and may not be accurate for large values. - // It is only intended for use in tests. - let val: f64 = self - .as_uint256() - .to_string() - .parse() - .unwrap_or(f64::INFINITY); - val / 1e18 + f64::from(self.as_uint256()) / 1e18 } pub fn as_uint256(self) -> U256 { @@ -129,7 +121,7 @@ impl Bfp { return Self::zero(); } - Self(U256::from(10u64).pow(U256::from(exp as u32))) + Self(U256::from(10u64).pow(U256::from(exp))) } pub fn from_wei(num: U256) -> Self { @@ -162,7 +154,7 @@ impl Bfp { Ok(if product.is_zero() { Bfp::zero() } else { - Bfp(((product - U256::from(1u64)) / *ONE_18) + U256::from(1u64)) + Bfp(((product - U256::ONE) / *ONE_18) + U256::ONE) }) } @@ -185,9 +177,7 @@ impl Bfp { } else { let a_inflated = self.0.checked_mul(*ONE_18).ok_or(Error::DivInternal)?; - Ok(Self( - ((a_inflated - U256::from(1u64)) / other.0) + U256::from(1u64), - )) + Ok(Self(((a_inflated - U256::ONE) / other.0) + U256::ONE)) } } @@ -201,9 +191,7 @@ impl Bfp { pub fn pow_up(self, exp: Self) -> Result { let raw = Bfp(logexpmath::pow(self.0, exp.0)?); - let max_error = raw - .mul_up(*MAX_POW_RELATIVE_ERROR)? - .add(Bfp(U256::from(1u64)))?; + let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(U256::ONE))?; raw.add(max_error) } @@ -218,9 +206,7 @@ impl Bfp { square.mul_up(square) } else { let raw = Bfp(logexpmath::pow(self.0, exp.0)?); - let max_error = raw - .mul_up(*MAX_POW_RELATIVE_ERROR)? - .add(Bfp(U256::from(1u64)))?; + let max_error = raw.mul_up(*MAX_POW_RELATIVE_ERROR)?.add(Bfp(U256::ONE))?; raw.add(max_error) } @@ -250,7 +236,7 @@ mod tests { ); assert_eq!( "10.000000000000000001".parse::().unwrap(), - Bfp::from_wei(test_exp10(19) + U256::from(1u64)) + Bfp::from_wei(test_exp10(19) + U256::ONE) ); assert!("10.0000000000000000001".parse::().is_err()); assert!("1.0.1".parse::().is_err()); @@ -274,7 +260,7 @@ mod tests { assert_eq!(Bfp::from(50).sub(Bfp::from(8)).unwrap(), Bfp::from(42)); assert_eq!( - Bfp::one().sub(Bfp(*ONE_18 + U256::from(1u64))).unwrap_err(), + Bfp::one().sub(Bfp(*ONE_18 + U256::ONE)).unwrap_err(), Error::SubOverflow ); } @@ -293,7 +279,7 @@ mod tests { assert_eq!( Bfp::one() - .$fn_name(Bfp(U256::MAX / test_exp10(18) + U256::from(1u64))) + .$fn_name(Bfp(U256::MAX / test_exp10(18) + U256::ONE)) .unwrap_err(), Error::MulOverflow, ); @@ -332,7 +318,7 @@ mod tests { Error::ZeroDivision ); assert_eq!( - Bfp(U256::MAX / test_exp10(18) + U256::from(1u64)) + Bfp(U256::MAX / test_exp10(18) + U256::ONE) .$fn_name(Bfp::one()) .unwrap_err(), Error::DivInternal, @@ -360,10 +346,7 @@ mod tests { Bfp::from(2).pow_up(Bfp::from(0)).unwrap(), Bfp(U256::from(1_000_000_000_000_010_001_u128)) ); // powDown: 999999999999989999 - assert_eq!( - Bfp::zero().pow_up(Bfp::one()).unwrap(), - Bfp(U256::from(1u64)) - ); // powDown: 0 + assert_eq!(Bfp::zero().pow_up(Bfp::one()).unwrap(), Bfp(U256::ONE)); // powDown: 0 assert_eq!( Bfp(U256::MAX).pow_up(Bfp::one()).unwrap_err(), diff --git a/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs b/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs index b320c48995..24447a2fae 100644 --- a/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs +++ b/crates/shared/src/sources/balancer_v2/swap/fixed_point/logexpmath.rs @@ -13,27 +13,39 @@ use { type Ufixed256x18 = U256; fn i256_exp10(n: u8) -> I256 { - I256::try_from(U256::from(10u64).pow(U256::from(n))).unwrap() + I256::try_from(U256::from(10u64).pow(U256::from(n))).expect("10^n for n <= 255 fits in I256") } static ONE_18: LazyLock = LazyLock::new(|| i256_exp10(18)); static ONE_20: LazyLock = LazyLock::new(|| i256_exp10(20)); static ONE_36: LazyLock = LazyLock::new(|| i256_exp10(36)); static UFIXED256X18_ONE: LazyLock = - LazyLock::new(|| U256::try_from(*ONE_18).unwrap()); -static MAX_NATURAL_EXPONENT: LazyLock = - LazyLock::new(|| ONE_18.checked_mul(I256::try_from(130i64).unwrap()).unwrap()); -static MIN_NATURAL_EXPONENT: LazyLock = - LazyLock::new(|| ONE_18.checked_mul(I256::try_from(-41i64).unwrap()).unwrap()); -static LN_36_LOWER_BOUND: LazyLock = - LazyLock::new(|| ONE_18.checked_sub(i256_exp10(17)).unwrap()); -static LN_36_UPPER_BOUND: LazyLock = - LazyLock::new(|| ONE_18.checked_add(i256_exp10(17)).unwrap()); + LazyLock::new(|| U256::try_from(*ONE_18).expect("ONE_18 is positive and fits in U256")); +static MAX_NATURAL_EXPONENT: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_mul(I256::try_from(130i64).expect("130 fits in I256")) + .expect("ONE_18 * 130 does not overflow") +}); +static MIN_NATURAL_EXPONENT: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_mul(I256::try_from(-41i64).expect("-41 fits in I256")) + .expect("ONE_18 * -41 does not overflow") +}); +static LN_36_LOWER_BOUND: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_sub(i256_exp10(17)) + .expect("ONE_18 - 10^17 does not underflow") +}); +static LN_36_UPPER_BOUND: LazyLock = LazyLock::new(|| { + ONE_18 + .checked_add(i256_exp10(17)) + .expect("ONE_18 + 10^17 does not overflow") +}); static MILD_EXPONENT_BOUND: LazyLock = LazyLock::new(|| { let shifted: U256 = U256::from(1u64) << 254; shifted - .checked_div(U256::try_from(*ONE_20).unwrap()) - .unwrap() + .checked_div(U256::try_from(*ONE_20).expect("ONE_20 is positive and fits in U256")) + .expect("division by non-zero ONE_20 does not fail") }); fn constant_x_20(i: u32) -> I256 { @@ -50,7 +62,7 @@ fn constant_x_20(i: u32) -> I256 { 11 => 6_250_000_000_000_000_000_i128, _ => panic!("Constant not provided"), }) - .unwrap() + .expect("constant x_20 values fit in I256") } fn constant_x_18(i: u32) -> I256 { I256::try_from(match i { @@ -58,7 +70,7 @@ fn constant_x_18(i: u32) -> I256 { 1 => 64_000_000_000_000_000_000_i128, _ => panic!("Constant not provided"), }) - .unwrap() + .expect("constant x_18 values fit in I256") } fn constant_a_20(i: u32) -> I256 { I256::try_from(match i { @@ -74,31 +86,23 @@ fn constant_a_20(i: u32) -> I256 { 11 => 106_449_445_891_785_942_956_i128, _ => panic!("Constant not provided"), }) - .unwrap() + .expect("constant a_20 values fit in I256") } fn constant_a_18(i: u32) -> I256 { match i { - 0 => { - // 38877084059945950922200000000000000000000000000000000000 - I256::try_from( - U256::from_str_radix( - "38877084059945950922200000000000000000000000000000000000", - 10, - ) - .unwrap(), - ) - .unwrap() - } - 1 => I256::try_from(6_235_149_080_811_616_882_910_000_000_i128).unwrap(), + 0 => I256::from_dec_str("38877084059945950922200000000000000000000000000000000000") + .expect("constant a_18[0] is a valid decimal string that fits in I256"), + 1 => I256::try_from(6_235_149_080_811_616_882_910_000_000_i128) + .expect("constant a_18[1] fits in I256"), _ => panic!("Constant not provided"), } } pub fn pow(x: Ufixed256x18, y: Ufixed256x18) -> Result { - if y == U256::ZERO { + if y.is_zero() { return Ok(*UFIXED256X18_ONE); } - if x == U256::ZERO { + if x.is_zero() { return Ok(U256::ZERO); } @@ -108,7 +112,7 @@ pub fn pow(x: Ufixed256x18, y: Ufixed256x18) -> Result { }; let y_int256 = if y < *MILD_EXPONENT_BOUND { - I256::try_from(y).unwrap() + I256::try_from(y).expect("y < MILD_EXPONENT_BOUND guarantees it fits in I256") } else { return Err(Error::YOutOfBounds); }; @@ -133,7 +137,7 @@ fn exp(mut x: I256) -> Result { return Err(Error::InvalidExponent); } - if x < I256::ZERO { + if x.is_negative() { return Ok((*ONE_18 * *ONE_18) / exp(-x)?); } @@ -145,10 +149,10 @@ fn exp(mut x: I256) -> Result { x -= constant_x_18(1); first_an = constant_a_18(1); } else { - first_an = I256::try_from(1i64).unwrap(); + first_an = I256::try_from(1i64).expect("1 fits in I256"); } - x *= I256::try_from(100i64).unwrap(); + x *= I256::try_from(100i64).expect("100 fits in I256"); let mut product = *ONE_20; for i in 2..=9 { @@ -163,11 +167,12 @@ fn exp(mut x: I256) -> Result { series_sum += term; for i in 2..=12 { - term = ((term * x) / *ONE_20) / I256::try_from(i).unwrap(); + term = ((term * x) / *ONE_20) / I256::try_from(i).expect("loop index fits in I256"); series_sum += term; } - Ok((((product * series_sum) / *ONE_20) * first_an) / I256::try_from(100i64).unwrap()) + Ok((((product * series_sum) / *ONE_20) * first_an) + / I256::try_from(100i64).expect("100 fits in I256")) } fn _ln(mut a: I256) -> I256 { @@ -183,8 +188,8 @@ fn _ln(mut a: I256) -> I256 { } } - sum *= I256::try_from(100i64).unwrap(); - a *= I256::try_from(100i64).unwrap(); + sum *= I256::try_from(100i64).expect("100 fits in I256"); + a *= I256::try_from(100i64).expect("100 fits in I256"); for i in 2..=11 { if a >= constant_a_20(i) { @@ -201,12 +206,12 @@ fn _ln(mut a: I256) -> I256 { for i in (3..=11).step_by(2) { num = (num * z_squared) / *ONE_20; - series_sum += num / I256::try_from(i).unwrap(); + series_sum += num / I256::try_from(i).expect("loop index fits in I256"); } - series_sum *= I256::try_from(2i64).unwrap(); + series_sum *= I256::try_from(2i64).expect("2 fits in I256"); - (sum + series_sum) / I256::try_from(100i64).unwrap() + (sum + series_sum) / I256::try_from(100i64).expect("100 fits in I256") } fn _ln_36(mut x: I256) -> I256 { @@ -220,10 +225,10 @@ fn _ln_36(mut x: I256) -> I256 { for i in (3..=15).step_by(2) { num = (num * z_squared) / *ONE_36; - series_sum += num / I256::try_from(i).unwrap(); + series_sum += num / I256::try_from(i).expect("loop index fits in I256"); } - series_sum * I256::try_from(2i64).unwrap() + series_sum * I256::try_from(2i64).expect("2 fits in I256") } #[cfg(test)] @@ -482,7 +487,7 @@ mod tests { U256::from_str_radix(i[1], 10).unwrap() ) .unwrap_err(), - Error::from(o) + o.into() ); } } diff --git a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs index 63160c17b9..289d569276 100644 --- a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs +++ b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs @@ -232,10 +232,6 @@ mod tests { U256::from_str_radix(&val.round().to_string(), 10).unwrap_or(U256::MAX) } - fn u256_to_f64_lossy(val: U256) -> f64 { - val.to_string().parse().unwrap_or(f64::INFINITY) - } - // interpreted from // https://github.com/balancer-labs/balancer-v2-monorepo/blob/stable-deployment/pvt/helpers/src/models/pools/stable/math.ts#L53 fn calculate_analytic_invariant_two_tokens( @@ -351,7 +347,7 @@ mod tests { #[test] fn invariant_two_tokens_ok() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); + let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12)]; let max_relative_error = 0.001; let expected = calculate_analytic_invariant_two_tokens( @@ -361,7 +357,7 @@ mod tests { ); let result = calculate_invariant(amplification_parameter, &balances).unwrap(); assert!( - (u256_to_f64_lossy(result) / 1e18 - expected) + (f64::from(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -374,13 +370,13 @@ mod tests { .iter() .map(|x| Bfp::from_str(x).unwrap()) .collect(); - let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); + let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); let result = calculate_invariant(amplification_parameter, balances.as_slice()).unwrap(); let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); let max_relative_error = 0.001; assert!( - (u256_to_f64_lossy(result) / 1e18 - expected) + (f64::from(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -389,14 +385,14 @@ mod tests { #[test] fn invariant_three_tokens_ok() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); + let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); let max_relative_error = 0.001; let result = calculate_invariant(amplification_parameter, &balances).unwrap(); assert!( - (u256_to_f64_lossy(result) / 1e18 - expected) + (f64::from(result) / 1e18 - expected) .abs() .le(&max_relative_error) ); @@ -405,7 +401,7 @@ mod tests { #[test] fn in_given_out_two_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); + let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -437,7 +433,7 @@ mod tests { #[test] fn in_given_out_three_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); + let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -469,7 +465,7 @@ mod tests { #[test] fn out_given_in_two_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); + let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -501,7 +497,7 @@ mod tests { #[test] fn out_given_in_three_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * u256_to_f64_lossy(*AMP_PRECISION)); + let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; From a08aef1e3668e17af00684219f7ef7ec2b8da969 Mon Sep 17 00:00:00 2001 From: Aryan Godara Date: Wed, 7 Jan 2026 18:04:10 +0530 Subject: [PATCH 5/5] Remove u256_from_f64_lossy() helper function that was no longer needed - Replace all calls with direct U256::from() conversions for amplification parameter --- .../sources/balancer_v2/swap/stable_math.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs index 289d569276..0d59421d84 100644 --- a/crates/shared/src/sources/balancer_v2/swap/stable_math.rs +++ b/crates/shared/src/sources/balancer_v2/swap/stable_math.rs @@ -228,10 +228,6 @@ mod tests { std::str::FromStr, }; - fn u256_from_f64_lossy(val: f64) -> U256 { - U256::from_str_radix(&val.round().to_string(), 10).unwrap_or(U256::MAX) - } - // interpreted from // https://github.com/balancer-labs/balancer-v2-monorepo/blob/stable-deployment/pvt/helpers/src/models/pools/stable/math.ts#L53 fn calculate_analytic_invariant_two_tokens( @@ -347,7 +343,7 @@ mod tests { #[test] fn invariant_two_tokens_ok() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12)]; let max_relative_error = 0.001; let expected = calculate_analytic_invariant_two_tokens( @@ -370,7 +366,7 @@ mod tests { .iter() .map(|x| Bfp::from_str(x).unwrap()) .collect(); - let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let result = calculate_invariant(amplification_parameter, balances.as_slice()).unwrap(); let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); @@ -385,7 +381,7 @@ mod tests { #[test] fn invariant_three_tokens_ok() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let balances = vec![Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let expected = calculate_invariant_approx(float_balances, amp); @@ -401,7 +397,7 @@ mod tests { #[test] fn in_given_out_two_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -433,7 +429,7 @@ mod tests { #[test] fn in_given_out_three_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -465,7 +461,7 @@ mod tests { #[test] fn out_given_in_two_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0; @@ -497,7 +493,7 @@ mod tests { #[test] fn out_given_in_three_tokens() { let amp = 100.; - let amplification_parameter = u256_from_f64_lossy(amp * f64::from(*AMP_PRECISION)); + let amplification_parameter = U256::from(amp * f64::from(*AMP_PRECISION)); let mut balances = [Bfp::from(10), Bfp::from(12), Bfp::from(14)]; let float_balances = balances.iter().map(|x| x.to_f64_lossy()).collect(); let token_index_in = 0;