1use old_bigdecimal::BigDecimal as OldBigDecimal;
2use num_traits::Signed;
3use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub};
6use std::str::FromStr;
7
8pub use num_bigint::Sign as BigIntSign;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct Address(pub [u8; 20]);
13
14impl Address {
15 pub fn zero() -> Self {
16 Self([0u8; 20])
17 }
18
19 pub fn from_string(s: &str) -> Self {
20 let s = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s);
21 let mut bytes = [0u8; 20];
22 if let Ok(decoded) = hex::decode(s) {
23 let len = decoded.len().min(20);
24 bytes[..len].copy_from_slice(&decoded[..len]);
25 }
26 Self(bytes)
27 }
28
29 pub fn from_bytes(bytes: &[u8]) -> Self {
33 assert!(
34 bytes.len() == 20,
35 "Bytes of length {} can not be converted to 20 byte addresses",
36 bytes.len()
37 );
38 let mut arr = [0u8; 20];
39 arr.copy_from_slice(bytes);
40 Self(arr)
41 }
42
43 pub fn to_hex_string(&self) -> String {
44 format!("0x{}", hex::encode(self.0))
45 }
46
47 pub fn to_bytes(&self) -> Vec<u8> {
48 self.0.to_vec()
49 }
50}
51
52impl fmt::Display for Address {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 write!(f, "{}", self.to_hex_string())
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59pub struct BigInt(pub num_bigint::BigInt);
60
61impl BigInt {
62 const MAX_BITS: usize = 435_412;
63
64 fn clamp(value: num_bigint::BigInt) -> Self {
65 let bits = value.bits() + 1;
66 if bits > Self::MAX_BITS {
67 eprintln!(
68 "[graph-native] WARN: BigInt exceeded max bits ({bits}), returning zero"
69 );
70 return Self::zero();
71 }
72 Self(value)
73 }
74
75 pub fn zero() -> Self {
76 Self(num_bigint::BigInt::from(0))
77 }
78
79 pub fn from(v: i32) -> Self {
80 Self(num_bigint::BigInt::from(v))
81 }
82
83 pub fn from_i64(v: i64) -> Self {
84 Self(num_bigint::BigInt::from(v))
85 }
86
87 pub fn from_str(s: &str) -> Self {
88 match num_bigint::BigInt::from_str(s) {
89 Ok(v) => Self::clamp(v),
90 Err(_) => {
91 eprintln!("[graph-native] WARN: BigInt::from_str failed for '{s}', returning zero");
92 Self::zero()
93 }
94 }
95 }
96
97 pub fn from_be_bytes(bytes: &[u8]) -> Self {
98 Self::clamp(num_bigint::BigInt::from_signed_bytes_be(bytes))
99 }
100
101 pub fn from_unsigned_be_bytes(bytes: &[u8]) -> Self {
102 Self::clamp(num_bigint::BigInt::from_bytes_be(BigIntSign::Plus, bytes))
103 }
104
105 pub fn is_zero(&self) -> bool {
106 self.0 == num_bigint::BigInt::from(0)
107 }
108
109 pub fn abs(&self) -> Self {
110 Self(self.0.clone().abs())
111 }
112
113 pub fn pow(&self, exp: u32) -> Self {
114 let mut result = num_bigint::BigInt::from(1);
115 for _ in 0..exp {
116 result *= self.0.clone();
117 }
118 Self::clamp(result)
119 }
120
121 pub fn to_big_decimal(&self) -> BigDecimal {
122 BigDecimal::from_bigint(self)
123 }
124
125 pub fn to_i32(&self) -> i32 {
126 self.0.to_string().parse::<i32>().unwrap_or(0)
127 }
128
129 pub fn plus(&self, other: &BigInt) -> BigInt {
130 Self::clamp(self.0.clone() + other.0.clone())
131 }
132
133 pub fn minus(&self, other: &BigInt) -> BigInt {
134 Self::clamp(self.0.clone() - other.0.clone())
135 }
136
137 pub fn times(&self, other: &BigInt) -> BigInt {
138 Self::clamp(self.0.clone() * other.0.clone())
139 }
140
141 pub fn div(&self, other: &BigInt) -> BigInt {
142 if other.is_zero() {
143 return Self::zero();
144 }
145 Self::clamp(self.0.clone() / other.0.clone())
146 }
147
148 pub fn r#mod(&self, other: &BigInt) -> BigInt {
149 if other.is_zero() {
150 return Self::zero();
151 }
152 Self::clamp(self.0.clone() % other.0.clone())
153 }
154
155 pub fn bit_and(&self, other: &BigInt) -> BigInt {
156 Self::clamp(&self.0 & &other.0)
157 }
158
159 pub fn bit_or(&self, other: &BigInt) -> BigInt {
160 Self::clamp(&self.0 | &other.0)
161 }
162
163 pub fn bit_xor(&self, other: &BigInt) -> BigInt {
164 Self::clamp(&self.0 ^ &other.0)
165 }
166}
167
168impl From<i8> for BigInt {
169 fn from(value: i8) -> Self {
170 Self(value.into())
171 }
172}
173
174impl From<i16> for BigInt {
175 fn from(value: i16) -> Self {
176 Self(value.into())
177 }
178}
179
180impl From<i32> for BigInt {
181 fn from(value: i32) -> Self {
182 Self(value.into())
183 }
184}
185
186impl From<i64> for BigInt {
187 fn from(value: i64) -> Self {
188 Self(value.into())
189 }
190}
191
192impl From<u64> for BigInt {
193 fn from(value: u64) -> Self {
194 Self(value.into())
195 }
196}
197
198impl Add for &BigInt {
199 type Output = BigInt;
200
201 fn add(self, rhs: Self) -> Self::Output {
202 self.plus(rhs)
203 }
204}
205
206impl Sub for &BigInt {
207 type Output = BigInt;
208
209 fn sub(self, rhs: Self) -> Self::Output {
210 self.minus(rhs)
211 }
212}
213
214impl Mul for &BigInt {
215 type Output = BigInt;
216
217 fn mul(self, rhs: Self) -> Self::Output {
218 self.times(rhs)
219 }
220}
221
222impl Div for &BigInt {
223 type Output = BigInt;
224
225 fn div(self, rhs: Self) -> Self::Output {
226 BigInt::div(self, rhs)
227 }
228}
229
230impl Rem for &BigInt {
231 type Output = BigInt;
232
233 fn rem(self, rhs: Self) -> Self::Output {
234 BigInt::r#mod(self, rhs)
235 }
236}
237
238impl Shl<i32> for BigInt {
239 type Output = BigInt;
240
241 fn shl(self, rhs: i32) -> Self::Output {
242 Self::clamp(self.0 << (rhs as usize))
243 }
244}
245
246impl Shr<i32> for BigInt {
247 type Output = BigInt;
248
249 fn shr(self, rhs: i32) -> Self::Output {
250 Self::clamp(self.0 >> (rhs as usize))
251 }
252}
253
254impl Neg for BigInt {
255 type Output = BigInt;
256
257 fn neg(self) -> Self::Output {
258 Self(-self.0)
259 }
260}
261
262impl PartialOrd for BigInt {
263 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
264 self.0.partial_cmp(&other.0)
265 }
266}
267
268impl fmt::Display for BigInt {
269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270 write!(f, "{}", self.0)
271 }
272}
273
274#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
275pub struct BigDecimal(pub OldBigDecimal);
276
277impl BigDecimal {
278 pub fn zero() -> Self {
279 use old_bigdecimal::Zero;
280
281 Self(OldBigDecimal::zero())
282 }
283
284 fn normalized(self) -> Self {
285 if self == Self::zero() {
286 return Self::zero();
287 }
288
289 let big_decimal = self.0.with_prec(34);
290 let (bigint, exp) = big_decimal.as_bigint_and_exponent();
291 let (sign, mut digits) = bigint.to_radix_be(10);
292 let trailing_count = digits.iter().rev().take_while(|i| **i == 0).count();
293 digits.truncate(digits.len().saturating_sub(trailing_count));
294 let int_val = num_bigint::BigInt::from_radix_be(sign, &digits, 10)
295 .unwrap_or_else(|| num_bigint::BigInt::from(0));
296 let scale = exp - trailing_count as i64;
297
298 Self(OldBigDecimal::new(int_val, scale))
299 }
300
301 pub fn from_str(s: &str) -> Self {
302 match OldBigDecimal::from_str(s) {
303 Ok(v) => Self(v).normalized(),
304 Err(_) => {
305 eprintln!(
306 "[graph-native] WARN: BigDecimal::from_str failed for '{s}', returning zero"
307 );
308 Self::zero()
309 }
310 }
311 }
312
313 pub fn from_bigint(v: &BigInt) -> Self {
314 Self(OldBigDecimal::new(v.0.clone(), 0)).normalized()
315 }
316
317 pub fn plus(&self, other: &BigDecimal) -> BigDecimal {
318 Self(self.0.clone() + other.0.clone()).normalized()
319 }
320
321 pub fn minus(&self, other: &BigDecimal) -> BigDecimal {
322 Self(self.0.clone() - other.0.clone()).normalized()
323 }
324
325 pub fn times(&self, other: &BigDecimal) -> BigDecimal {
326 Self(self.0.clone() * other.0.clone()).normalized()
327 }
328
329 pub fn div(&self, other: &BigDecimal) -> BigDecimal {
330 if other == &Self::zero() {
331 return Self::zero();
332 }
333 Self(self.0.clone() / other.0.clone()).normalized()
334 }
335}
336
337impl PartialOrd for BigDecimal {
338 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
339 self.0.partial_cmp(&other.0)
340 }
341}
342
343impl fmt::Display for BigDecimal {
344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345 write!(f, "{}", self.0)
346 }
347}