Skip to main content

graph_native/
types.rs

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