balancer_maths_rust/common/
maths.rs1use crate::common::constants::{FOUR_WAD, MAX_POW_RELATIVE_ERROR, TWO_WAD, WAD};
4use crate::common::errors::PoolError;
5use crate::common::log_exp_math;
6use alloy_primitives::U256;
7
8pub fn mul_up_fixed(a: &U256, b: &U256) -> Result<U256, PoolError> {
10 let product = a * b;
11 if product.is_zero() {
12 return Ok(U256::ZERO);
13 }
14 let result = (product - U256::ONE) / WAD + U256::ONE;
15 Ok(result)
16}
17
18pub fn div_up_fixed(a: &U256, b: &U256) -> Result<U256, PoolError> {
20 let result = mul_div_up_fixed(a, &WAD, b)?;
21 Ok(result)
22}
23
24pub fn mul_down_fixed(a: &U256, b: &U256) -> Result<U256, PoolError> {
26 let product = a * b;
27 let result = product / WAD;
28 Ok(result)
29}
30
31pub fn div_down_fixed(a: &U256, b: &U256) -> Result<U256, PoolError> {
33 if a.is_zero() {
34 return Ok(U256::ZERO);
35 }
36 if b.is_zero() {
37 return Err(PoolError::MathOverflow);
38 }
39
40 let a_inflated = a * WAD;
41 let result = a_inflated / b;
42 Ok(result)
43}
44
45pub fn div_up(a: &U256, b: &U256) -> Result<U256, PoolError> {
47 if b.is_zero() {
48 return Ok(U256::ZERO);
49 }
50 let result = U256::ONE + (a - U256::ONE) / b;
51 Ok(result)
52}
53
54pub fn mul_div_up_fixed(a: &U256, b: &U256, c: &U256) -> Result<U256, PoolError> {
56 let product = a * b;
57 if product.is_zero() {
58 return Ok(U256::ZERO);
59 }
60 let result = (product - U256::ONE) / c + U256::ONE;
61 Ok(result)
62}
63
64pub fn pow_down_fixed(base: &U256, exponent: &U256) -> Result<U256, PoolError> {
66 pow_down_fixed_with_version(base, exponent, 0)
67}
68
69pub fn pow_down_fixed_with_version(
71 base: &U256,
72 exponent: &U256,
73 version: u32,
74) -> Result<U256, PoolError> {
75 if *exponent == WAD && version != 1 {
76 return Ok(*base);
77 }
78 if *exponent == TWO_WAD && version != 1 {
79 return mul_up_fixed(base, base);
80 }
81 if *exponent == FOUR_WAD && version != 1 {
82 let square = mul_up_fixed(base, base)?;
83 return mul_up_fixed(&square, &square);
84 }
85
86 let raw = log_exp_math::pow(base, exponent)?;
87 let max_error = mul_up_fixed(&raw, &MAX_POW_RELATIVE_ERROR)? + U256::ONE;
88
89 if raw < max_error {
90 return Ok(U256::ZERO);
91 }
92
93 Ok(raw - max_error)
94}
95
96pub fn pow_up_fixed(base: &U256, exponent: &U256) -> Result<U256, PoolError> {
98 pow_up_fixed_with_version(base, exponent, 0)
99}
100
101pub fn pow_up_fixed_with_version(
103 base: &U256,
104 exponent: &U256,
105 version: u32,
106) -> Result<U256, PoolError> {
107 if *exponent == WAD && version != 1 {
108 return Ok(*base);
109 }
110 if *exponent == TWO_WAD && version != 1 {
111 return mul_up_fixed(base, base);
112 }
113 if *exponent == FOUR_WAD && version != 1 {
114 let square = mul_up_fixed(base, base)?;
115 return mul_up_fixed(&square, &square);
116 }
117
118 let raw = log_exp_math::pow(base, exponent)?;
119 let max_error = mul_up_fixed(&raw, &MAX_POW_RELATIVE_ERROR)? + U256::ONE;
120
121 Ok(raw + max_error)
122}
123
124pub fn complement_fixed(x: &U256) -> Result<U256, PoolError> {
126 if *x < WAD {
127 Ok(WAD - x)
128 } else {
129 Ok(U256::ZERO)
130 }
131}