vertex_sdk/vertex_utils/
math.rs1use ethers::types::{I256, U256};
2use eyre::{eyre, Result};
3
4pub const ONE_X18: i128 = 1000000000000000000;
5pub const ONE_X6: i128 = 1_000_000;
6const UONE: u128 = 1000000000000000000;
7
8fn signed_to_unsigned(x: i128, y: i128) -> (u128, u128, i128) {
9 if x >= 0 && y >= 0 {
10 (x as u128, y as u128, 1)
11 } else if x >= 0 && y < 0 {
12 (x as u128, (-y) as u128, -1)
13 } else if x < 0 && y >= 0 {
14 ((-x) as u128, y as u128, -1)
15 } else {
16 ((-x) as u128, (-y) as u128, 1)
17 }
18}
19
20pub fn mul_x18(x: i128, y: i128) -> i128 {
21 let (mut x, mut y, sign) = signed_to_unsigned(x, y);
22 if x > y {
23 std::mem::swap(&mut x, &mut y);
24 }
25 (if y < UONE {
26 x * y / UONE
27 } else if x < UONE {
28 let (c, d) = (y / UONE, y % UONE);
29 x * c + x * d / UONE
30 } else {
31 let (a, b) = (x / UONE, x % UONE);
32 let (c, d) = (y / UONE, y % UONE);
33 a * c * UONE + a * d + b * c + b * d / UONE
34 } as i128)
35 * sign
36}
37
38pub fn fmul_x18(x: i128, y: i128) -> i128 {
40 ((x as f64 * y as f64) / 1e18) as i128
41}
42
43pub fn div_x18(x: i128, y: i128) -> i128 {
44 let (mut x, y, sign) = signed_to_unsigned(x, y);
45 let mut ret = 0;
46 if x >= y {
47 ret += x / y * UONE;
48 x %= y;
49 }
50 if x <= UONE {
51 ret += x * UONE / y;
52 } else {
53 ret += (U256::from(x) * U256::from(UONE) / U256::from(y)).low_u128()
54 }
55 (ret as i128) * sign
56}
57
58pub fn pow_x18(x: i128, y: i128) -> i128 {
59 let xf = x18_to_f64(x);
60 let yf = x18_to_f64(y);
61 let resultf = xf.powf(yf);
62 let mut result = (resultf.trunc() as i128) * ONE_X18;
63 result += (resultf.fract() * 1e18f64) as i128;
64 result
65}
66
67pub fn sqrt_x18(x: i128) -> i128 {
68 pow_x18(x, ONE_X18 / 2)
69}
70
71pub fn mul_div_x18(x: i128, y: i128, z: i128) -> i128 {
72 (I256::from(x) * I256::from(y) / I256::from(z)).low_i128()
73}
74
75pub fn x18_to_f64_mil(x: i128) -> f64 {
76 let x = x / 1_000_000;
77 x18_to_f64(x)
78}
79
80pub fn x18_to_f64(x: i128) -> f64 {
81 let mut result = (x / ONE_X18) as f64;
82 result += (x % ONE_X18) as f64 / 1e18;
83 result
84}
85
86pub fn f64_to_x18(x: f64) -> i128 {
87 let mut result = (x.trunc() as i128) * ONE_X18;
88 result += (x.fract() * 1e18) as i128;
89 result
90}
91
92pub fn split_i256(x: I256) -> (i128, i128) {
93 let base = I256::from(2).pow(127);
94 ((x / base).as_i128(), (x % base).as_i128())
95}
96
97pub fn merge_i128(x: i128, y: i128) -> I256 {
98 let base = I256::from(2).pow(127);
99 I256::from(x) * base + I256::from(y)
100}
101
102pub fn i256_to_f64(x: I256) -> f64 {
103 let (high, low) = split_i256(x);
104 x18_to_f64(high) * (2.0_f64).powi(127) + x18_to_f64(low)
105}
106
107pub fn to_u128_x18(x: u128) -> u128 {
108 x * (ONE_X18 as u128)
109}
110
111pub fn to_i128_x18(x: i128) -> i128 {
112 x * ONE_X18
113}
114
115pub fn to_i128_fp(x: f64) -> i128 {
116 (x * 10.0_f64.powi(9)) as i128 * 1000000000
117}
118
119pub fn to_i32_fp(x: f64) -> i32 {
120 (x * 10.0_f64.powi(9)) as i32
121}
122
123pub fn to_u128_x6(x: u128) -> u128 {
124 x * 1000000
125}
126
127pub fn to_i128_x6(x: i128) -> i128 {
128 x * 1000000
129}
130
131pub fn fexp_x18(mut x: i128, y: i128) -> i128 {
132 assert!(y >= 0);
133 let mut i = 1;
134 let mut ret = to_i128_x18(1);
135 while i <= y {
136 if i & y != 0 {
137 ret = mul_x18(ret, x);
138 }
139 x = mul_x18(x, x);
140 i <<= 1;
141 }
142 ret
143}
144
145pub fn fexp(mut x: i128, y: i128) -> i128 {
146 assert!(y >= 0);
147 let mut i = 1;
148 let mut ret = 1;
149 while i <= y {
150 if i & y != 0 {
151 ret *= x;
152 }
153 x *= x;
154 i <<= 1;
155 }
156 ret
157}
158
159pub fn check_diff_gt_threshold_x18(left_x18: i128, right_x18: i128, threshold: f64) -> bool {
160 let diff = (left_x18 - right_x18).abs();
161 let percent_diff = div_x18(diff, right_x18);
162 let percent_threshold: f64 = threshold * 1e18f64;
163 percent_diff > percent_threshold as i128
164}
165
166pub fn check_within_range_x18(
167 left_x18: i128,
168 right_x18: i128,
169 threshold_lower: f64,
170 threshold_upper: f64,
171) -> bool {
172 let percent = div_x18(left_x18, right_x18);
173 let percent_threshold_lower: f64 = threshold_lower * 1e18f64;
174 let percent_threshold_upper: f64 = threshold_upper * 1e18f64;
175 (percent > percent_threshold_lower as i128) && (percent < percent_threshold_upper as i128)
176}
177
178pub trait TryMath {
179 fn try_add(self, v: i128) -> Result<i128>;
180 fn try_div(self, v: i128) -> Result<i128>;
181 fn try_mul(self, v: i128) -> Result<i128>;
182 fn try_sub(self, v: i128) -> Result<i128>;
183 fn try_rem(self, v: i128) -> Result<i128>;
184 fn try_mul_x18(self, v: i128) -> Result<i128>;
185 fn try_div_x18(self, v: i128) -> Result<i128>;
186 fn try_sqrt_x18(self) -> Result<i128>;
187}
188
189impl TryMath for i128 {
190 fn try_add(self, v: i128) -> Result<i128> {
191 self.checked_add(v).ok_or(eyre!("Overflow: add"))
192 }
193
194 fn try_div(self, v: i128) -> Result<i128> {
195 self.checked_div(v).ok_or(eyre!("Overflow: div"))
196 }
197
198 fn try_mul(self, v: i128) -> Result<i128> {
199 self.checked_mul(v).ok_or(eyre!("Overflow: mul"))
200 }
201
202 fn try_sub(self, v: i128) -> Result<i128> {
203 self.checked_sub(v).ok_or(eyre!("Overflow: sub"))
204 }
205
206 fn try_rem(self, v: i128) -> Result<i128> {
207 self.checked_rem(v).ok_or(eyre!("Overflow: rem"))
208 }
209
210 fn try_mul_x18(self, v: i128) -> Result<i128> {
211 Ok((I256::from(self) * I256::from(v) / I256::exp10(18)).as_i128())
212 }
213
214 fn try_div_x18(self, v: i128) -> Result<i128> {
215 Ok((I256::from(self) * I256::exp10(18) / I256::from(v)).as_i128())
216 }
217
218 fn try_sqrt_x18(self) -> Result<i128> {
219 let mut hi = 1;
220 while hi.try_mul_x18(hi)? < self {
221 hi = hi.try_mul(2)?;
222 }
223 let mut lo = hi.try_div(2)?;
224 while lo < hi {
225 let mid = lo.try_add(hi)?.try_div(2)?;
226 if mid.try_mul_x18(mid)? < self {
227 lo = mid.try_add(1)?;
228 } else {
229 hi = mid;
230 }
231 }
232 Ok(lo)
233 }
234}
235
236pub fn lp_value(balance: i128, x: i128, y: i128, supply: i128, price: i128) -> i128 {
237 if supply == 0 {
238 0
239 } else {
240 let pool_total_value = mul_x18(x, price) + y;
241 mul_div_x18(balance, pool_total_value, supply)
242 }
243}
244
245pub fn round(value: i128, increment: i128) -> i128 {
246 return value - value % increment;
247}