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").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}