balancer_maths_rust/common/
utils.rs1use crate::common::errors::PoolError;
4use crate::common::maths::{div_down_fixed, div_up_fixed, mul_down_fixed, mul_up_fixed};
5use crate::common::types::PoolState;
6use alloy_primitives::U256;
7
8pub fn find_case_insensitive_index_in_list(strings: &[String], target: &str) -> Option<usize> {
10 let lowercase_target = target.to_lowercase();
11
12 for (index, string) in strings.iter().enumerate() {
13 if string.to_lowercase() == lowercase_target {
14 return Some(index);
15 }
16 }
17
18 None
19}
20
21pub fn to_scaled_18_apply_rate_round_down(
23 amount: &U256,
24 scaling_factor: &U256,
25 rate: &U256,
26) -> Result<U256, PoolError> {
27 mul_down_fixed(&(amount * scaling_factor), rate)
28}
29
30pub fn to_scaled_18_apply_rate_round_up(
32 amount: &U256,
33 scaling_factor: &U256,
34 rate: &U256,
35) -> Result<U256, PoolError> {
36 mul_up_fixed(&(amount * scaling_factor), rate)
37}
38
39pub fn to_raw_undo_rate_round_down(
44 amount: &U256,
45 scaling_factor: &U256,
46 token_rate: &U256,
47) -> Result<U256, PoolError> {
48 let denominator = scaling_factor * token_rate;
51 let result = div_down_fixed(amount, &denominator)?;
52 Ok(result)
53}
54
55pub fn to_raw_undo_rate_round_up(
60 amount: &U256,
61 scaling_factor: &U256,
62 token_rate: &U256,
63) -> Result<U256, PoolError> {
64 div_up_fixed(amount, &(scaling_factor * token_rate))
67}
68
69pub fn is_same_address(address_one: &str, address_two: &str) -> bool {
71 address_one.to_lowercase() == address_two.to_lowercase()
72}
73
74pub fn copy_to_scaled18_apply_rate_round_down_array(
76 amounts: &[U256],
77 scaling_factors: &[U256],
78 token_rates: &[U256],
79) -> Result<Vec<U256>, PoolError> {
80 let mut scaled_amounts = Vec::with_capacity(amounts.len());
81
82 for (i, amount) in amounts.iter().enumerate() {
83 let scaled_amount =
84 to_scaled_18_apply_rate_round_down(amount, &scaling_factors[i], &token_rates[i])?;
85 scaled_amounts.push(scaled_amount);
86 }
87
88 Ok(scaled_amounts)
89}
90
91pub fn copy_to_scaled18_apply_rate_round_up_array(
93 amounts: &[U256],
94 scaling_factors: &[U256],
95 token_rates: &[U256],
96) -> Result<Vec<U256>, PoolError> {
97 let mut scaled_amounts = Vec::with_capacity(amounts.len());
98
99 for (i, amount) in amounts.iter().enumerate() {
100 let scaled_amount =
101 to_scaled_18_apply_rate_round_up(amount, &scaling_factors[i], &token_rates[i])?;
102 scaled_amounts.push(scaled_amount);
103 }
104
105 Ok(scaled_amounts)
106}
107
108pub fn compute_and_charge_aggregate_swap_fees(
110 swap_fee_amount_scaled18: &U256,
111 aggregate_swap_fee_percentage: &U256,
112 decimal_scaling_factors: &[U256],
113 token_rates: &[U256],
114 index: usize,
115) -> Result<U256, PoolError> {
116 if swap_fee_amount_scaled18 > &U256::ZERO && aggregate_swap_fee_percentage > &U256::ZERO {
117 let total_swap_fee_amount_raw = to_raw_undo_rate_round_down(
121 swap_fee_amount_scaled18,
122 &decimal_scaling_factors[index],
123 &token_rates[index],
124 )?;
125
126 Ok(mul_down_fixed(
127 &total_swap_fee_amount_raw,
128 aggregate_swap_fee_percentage,
129 )?)
130 } else {
131 Ok(U256::ZERO)
132 }
133}
134
135pub fn get_single_input_index(max_amounts_in: &[U256]) -> Result<usize, PoolError> {
137 let length = max_amounts_in.len();
138 let mut input_index = length;
139
140 for (i, amount) in max_amounts_in.iter().enumerate() {
141 if amount != &U256::ZERO {
142 if input_index != length {
143 return Err(PoolError::Custom(
144 "Multiple non-zero inputs for single token add".to_string(),
145 ));
146 }
147 input_index = i;
148 }
149 }
150
151 if input_index >= length {
152 return Err(PoolError::Custom(
153 "All zero inputs for single token add".to_string(),
154 ));
155 }
156
157 Ok(input_index)
158}
159
160pub fn require_unbalanced_liquidity_enabled(pool_state: &PoolState) -> Result<(), PoolError> {
162 if !pool_state.base().supports_unbalanced_liquidity {
163 return Err(PoolError::Custom(
164 "DoesNotSupportUnbalancedLiquidity".to_string(),
165 ));
166 }
167 Ok(())
168}