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
156impl From<i8> for BigInt {
157 fn from(value: i8) -> Self {
158 Self(value.into())
159 }
160}
161
162impl From<i16> for BigInt {
163 fn from(value: i16) -> Self {
164 Self(value.into())
165 }
166}
167
168impl From<i32> for BigInt {
169 fn from(value: i32) -> Self {
170 Self(value.into())
171 }
172}
173
174impl From<i64> for BigInt {
175 fn from(value: i64) -> Self {
176 Self(value.into())
177 }
178}
179
180impl From<u64> for BigInt {
181 fn from(value: u64) -> Self {
182 Self(value.into())
183 }
184}
185
186impl Add for &BigInt {
187 type Output = BigInt;
188
189 fn add(self, rhs: Self) -> Self::Output {
190 self.plus(rhs)
191 }
192}
193
194impl Sub for &BigInt {
195 type Output = BigInt;
196
197 fn sub(self, rhs: Self) -> Self::Output {
198 self.minus(rhs)
199 }
200}
201
202impl Mul for &BigInt {
203 type Output = BigInt;
204
205 fn mul(self, rhs: Self) -> Self::Output {
206 self.times(rhs)
207 }
208}
209
210impl Div for &BigInt {
211 type Output = BigInt;
212
213 fn div(self, rhs: Self) -> Self::Output {
214 BigInt::div(self, rhs)
215 }
216}
217
218impl Rem for &BigInt {
219 type Output = BigInt;
220
221 fn rem(self, rhs: Self) -> Self::Output {
222 BigInt::r#mod(self, rhs)
223 }
224}
225
226impl Shl<i32> for BigInt {
227 type Output = BigInt;
228
229 fn shl(self, rhs: i32) -> Self::Output {
230 Self::clamp(self.0 << (rhs as usize))
231 }
232}
233
234impl Shr<i32> for BigInt {
235 type Output = BigInt;
236
237 fn shr(self, rhs: i32) -> Self::Output {
238 Self::clamp(self.0 >> (rhs as usize))
239 }
240}
241
242impl Neg for BigInt {
243 type Output = BigInt;
244
245 fn neg(self) -> Self::Output {
246 Self(-self.0)
247 }
248}
249
250impl PartialOrd for BigInt {
251 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
252 self.0.partial_cmp(&other.0)
253 }
254}
255
256impl fmt::Display for BigInt {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 write!(f, "{}", self.0)
259 }
260}
261
262#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
263pub struct BigDecimal(pub OldBigDecimal);
264
265impl BigDecimal {
266 pub fn zero() -> Self {
267 use old_bigdecimal::Zero;
268
269 Self(OldBigDecimal::zero())
270 }
271
272 fn normalized(self) -> Self {
273 if self == Self::zero() {
274 return Self::zero();
275 }
276
277 let big_decimal = self.0.with_prec(34);
278 let (bigint, exp) = big_decimal.as_bigint_and_exponent();
279 let (sign, mut digits) = bigint.to_radix_be(10);
280 let trailing_count = digits.iter().rev().take_while(|i| **i == 0).count();
281 digits.truncate(digits.len().saturating_sub(trailing_count));
282 let int_val = num_bigint::BigInt::from_radix_be(sign, &digits, 10)
283 .unwrap_or_else(|| num_bigint::BigInt::from(0));
284 let scale = exp - trailing_count as i64;
285
286 Self(OldBigDecimal::new(int_val, scale))
287 }
288
289 pub fn from_str(s: &str) -> Self {
290 match OldBigDecimal::from_str(s) {
291 Ok(v) => Self(v).normalized(),
292 Err(_) => {
293 eprintln!(
294 "[graph-native] WARN: BigDecimal::from_str failed for '{s}', returning zero"
295 );
296 Self::zero()
297 }
298 }
299 }
300
301 pub fn from_bigint(v: &BigInt) -> Self {
302 Self(OldBigDecimal::new(v.0.clone(), 0)).normalized()
303 }
304
305 pub fn plus(&self, other: &BigDecimal) -> BigDecimal {
306 Self(self.0.clone() + other.0.clone()).normalized()
307 }
308
309 pub fn minus(&self, other: &BigDecimal) -> BigDecimal {
310 Self(self.0.clone() - other.0.clone()).normalized()
311 }
312
313 pub fn times(&self, other: &BigDecimal) -> BigDecimal {
314 Self(self.0.clone() * other.0.clone()).normalized()
315 }
316
317 pub fn div(&self, other: &BigDecimal) -> BigDecimal {
318 if other == &Self::zero() {
319 return Self::zero();
320 }
321 Self(self.0.clone() / other.0.clone()).normalized()
322 }
323}
324
325impl PartialOrd for BigDecimal {
326 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
327 self.0.partial_cmp(&other.0)
328 }
329}
330
331impl fmt::Display for BigDecimal {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 write!(f, "{}", self.0)
334 }
335}