From 9cc4916beb4d21c2e5fc2d16c060dd53b12fd410 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 20 Nov 2025 11:13:05 +0000 Subject: [PATCH 1/3] refactor(rust): reCLAMM pricing use scaling factors instead of decimals. --- rust/src/pools/reclamm/reclamm_pricing.rs | 13 ++++---- rust/tests/test_reclamm_swap_to_price.rs | 39 +++++------------------ 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/rust/src/pools/reclamm/reclamm_pricing.rs b/rust/src/pools/reclamm/reclamm_pricing.rs index 4df1f3f..5b46b96 100644 --- a/rust/src/pools/reclamm/reclamm_pricing.rs +++ b/rust/src/pools/reclamm/reclamm_pricing.rs @@ -60,13 +60,12 @@ pub fn calculate_reclamm_price( #[allow(clippy::too_many_arguments)] pub fn swap_reclamm_to_price( token_rates: &[U256], + scaling_factors: &[U256], balances_live_scaled_18: &[U256], current_virtual_balances: &[U256], swap_fee_percentage: &U256, _protocol_fee_percentage: &U256, _pool_creator_fee_percentage: &U256, - decimals_a: u8, - decimals_b: u8, target_price_scaled_18: &U256, ) -> Result { // Input validation @@ -88,6 +87,8 @@ pub fn swap_reclamm_to_price( let rate_a = u256_to_f64(&token_rates[0]) / 1e18; let rate_b = u256_to_f64(&token_rates[1]) / 1e18; let target_price = u256_to_f64(target_price_scaled_18) / 1e18; + let scaling_factor_a = u256_to_f64(&scaling_factors[0]) / 1e18; + let scaling_factor_b = u256_to_f64(&scaling_factors[1]) / 1e18; // Validate non-zero values if balance_a + virtual_a == 0.0 || balance_b + virtual_b == 0.0 { @@ -128,10 +129,10 @@ pub fn swap_reclamm_to_price( token_in_index: 1, token_out_index: 0, amount_in_raw: U256::from( - (amount_in_scaled * 10f64.powi(decimals_b as i32) / rate_b).ceil() as u128, + (amount_in_scaled / scaling_factor_b * rate_b).ceil() as u128, ), amount_out_raw: U256::from( - (amount_out_scaled * 10f64.powi(decimals_a as i32) / rate_a).floor() as u128, + (amount_out_scaled / scaling_factor_a * rate_a).floor() as u128, ), }) } else { @@ -157,10 +158,10 @@ pub fn swap_reclamm_to_price( token_in_index: 0, token_out_index: 1, amount_in_raw: U256::from( - (amount_in_scaled * 10f64.powi(decimals_a as i32) / rate_a).ceil() as u128, + (amount_in_scaled / scaling_factor_a * rate_a).ceil() as u128, ), amount_out_raw: U256::from( - (amount_out_scaled * 10f64.powi(decimals_b as i32) / rate_b).floor() as u128, + (amount_out_scaled / scaling_factor_b * rate_b).floor() as u128, ), }) } diff --git a/rust/tests/test_reclamm_swap_to_price.rs b/rust/tests/test_reclamm_swap_to_price.rs index bb30c60..2a97c5f 100644 --- a/rust/tests/test_reclamm_swap_to_price.rs +++ b/rust/tests/test_reclamm_swap_to_price.rs @@ -14,8 +14,6 @@ struct TestPool { // Token information tokens: Vec, token_rates: Vec, - decimals_a: u8, - decimals_b: u8, // Pool balances balances_live_scaled_18: Vec, @@ -62,8 +60,6 @@ impl TestPool { U256::from_str_radix("1000000000000000000", 10).unwrap(), U256::from_str_radix("1000000000000000000", 10).unwrap(), ], - decimals_a: 18, - decimals_b: 18, balances_live_scaled_18: vec![ U256::from_str_radix("122255177411753308470", 10).unwrap(), U256::from_str_radix("13599963412925271409", 10).unwrap(), @@ -161,28 +157,14 @@ fn get_swap_tokens( // Helper to apply swap to balances fn update_balances( balances: &mut [U256], + scaling_factors: &[U256], token_in_index: usize, token_out_index: usize, amount_in_raw: U256, amount_out_raw: U256, - decimals_a: u8, - decimals_b: u8, ) { - // Convert raw amounts to scaled18 - let scaling_factor_in = if token_in_index == 0 { - U256::from(10u128.pow((18 - decimals_a) as u32)) - } else { - U256::from(10u128.pow((18 - decimals_b) as u32)) - }; - - let scaling_factor_out = if token_out_index == 0 { - U256::from(10u128.pow((18 - decimals_a) as u32)) - } else { - U256::from(10u128.pow((18 - decimals_b) as u32)) - }; - - let amount_in_scaled = amount_in_raw * scaling_factor_in; - let amount_out_scaled = amount_out_raw * scaling_factor_out; + let amount_in_scaled = amount_in_raw * scaling_factors[token_in_index]; + let amount_out_scaled = amount_out_raw * scaling_factors[token_out_index]; balances[token_in_index] += amount_in_scaled; balances[token_out_index] -= amount_out_scaled; @@ -213,25 +195,23 @@ macro_rules! generate_tests { let result = swap_reclamm_to_price( &test_pool.token_rates, + &test_pool.scaling_factors, &balances_live_scaled_18, &test_pool.current_virtual_balances, &test_pool.swap_fee_percentage, &test_pool.protocol_fee_percentage, &test_pool.pool_creator_fee_percentage, - test_pool.decimals_a, - test_pool.decimals_b, &target_price_scaled_18, ) .unwrap(); update_balances( &mut balances_live_scaled_18, + &test_pool.scaling_factors, result.token_in_index, result.token_out_index, result.amount_in_raw, result.amount_out_raw, - test_pool.decimals_a, - test_pool.decimals_b, ); let new_price_scaled_18 = calculate_reclamm_price(&balances_live_scaled_18, &test_pool.current_virtual_balances); @@ -253,13 +233,12 @@ macro_rules! generate_tests { let price_result = swap_reclamm_to_price( &test_pool.token_rates, + &test_pool.scaling_factors, &test_pool.balances_live_scaled_18, &test_pool.current_virtual_balances, &test_pool.swap_fee_percentage, &test_pool.protocol_fee_percentage, &test_pool.pool_creator_fee_percentage, - test_pool.decimals_a, - test_pool.decimals_b, &target_price_scaled_18 ) .unwrap(); @@ -320,13 +299,12 @@ fn test_amount_out_exceeds_balance_greater() { let result = swap_reclamm_to_price( &test_pool.token_rates, + &test_pool.scaling_factors, &test_pool.balances_live_scaled_18, &test_pool.current_virtual_balances, &test_pool.swap_fee_percentage, &test_pool.protocol_fee_percentage, &test_pool.pool_creator_fee_percentage, - test_pool.decimals_a, - test_pool.decimals_b, &target_price_scaled_18, ); @@ -359,13 +337,12 @@ fn test_amount_out_exceeds_balance_less() { let result = swap_reclamm_to_price( &test_pool.token_rates, + &test_pool.scaling_factors, &test_pool.balances_live_scaled_18, &test_pool.current_virtual_balances, &test_pool.swap_fee_percentage, &test_pool.protocol_fee_percentage, &test_pool.pool_creator_fee_percentage, - test_pool.decimals_a, - test_pool.decimals_b, &target_price_scaled_18, ); From bdfd85cfbed69acbca5b5a90fd9d08f6e6c2eb8d Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 20 Nov 2025 11:14:48 +0000 Subject: [PATCH 2/3] refactor(rust): Fix formatting. --- rust/src/pools/reclamm/reclamm_pricing.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/rust/src/pools/reclamm/reclamm_pricing.rs b/rust/src/pools/reclamm/reclamm_pricing.rs index 5b46b96..4b013bf 100644 --- a/rust/src/pools/reclamm/reclamm_pricing.rs +++ b/rust/src/pools/reclamm/reclamm_pricing.rs @@ -128,11 +128,9 @@ pub fn swap_reclamm_to_price( Ok(SwapToTargetPriceResult { token_in_index: 1, token_out_index: 0, - amount_in_raw: U256::from( - (amount_in_scaled / scaling_factor_b * rate_b).ceil() as u128, - ), + amount_in_raw: U256::from((amount_in_scaled / scaling_factor_b * rate_b).ceil() as u128), amount_out_raw: U256::from( - (amount_out_scaled / scaling_factor_a * rate_a).floor() as u128, + (amount_out_scaled / scaling_factor_a * rate_a).floor() as u128 ), }) } else { @@ -157,11 +155,9 @@ pub fn swap_reclamm_to_price( Ok(SwapToTargetPriceResult { token_in_index: 0, token_out_index: 1, - amount_in_raw: U256::from( - (amount_in_scaled / scaling_factor_a * rate_a).ceil() as u128, - ), + amount_in_raw: U256::from((amount_in_scaled / scaling_factor_a * rate_a).ceil() as u128), amount_out_raw: U256::from( - (amount_out_scaled / scaling_factor_b * rate_b).floor() as u128, + (amount_out_scaled / scaling_factor_b * rate_b).floor() as u128 ), }) } From 54e4beb321d8cb13221ce5a7dacadfe67ea41a1b Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 20 Nov 2025 11:16:14 +0000 Subject: [PATCH 3/3] Release v0.4.2. --- rust/CHANGELOG.md | 5 +++++ rust/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rust/CHANGELOG.md b/rust/CHANGELOG.md index 032d99b..66a5350 100644 --- a/rust/CHANGELOG.md +++ b/rust/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## [0.4.1] - 2025-11-20 + +### Changed +- Update reCLAMM pricing functions to use scaling factors instead of decimals. + ## [0.4.1] - 2025-11-13 ### Changed diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 5a27be6..88c72e3 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "balancer-maths-rust" -version = "0.4.1" +version = "0.4.2" edition = "2021" description = "Balancer V3 mathematics library in Rust" license = "MIT"