1use candid::{CandidType, Nat, types::Serializer, types::Type, types::TypeInner};
4use ethnum::U256 as EthU256;
5use num_bigint::BigUint;
6use serde::{
7 Deserialize, Deserializer, Serialize, Serializer as SerdeSerializer,
8 de::{self, Visitor},
9};
10use std::{fmt, str::FromStr};
11
12use crate::{Decimal, NumericValue};
13
14const MAX_DECIMAL_DIGITS: usize = 78;
15const DECIMAL_CHUNK_BASE: u64 = 100_000_000;
16const DECIMAL_CHUNK_WIDTH: usize = 8;
17const DECIMAL_BUFFER_LEN: usize = 80;
18const U128_LOW_U32_MASK: u128 = 0xffff_ffff;
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub struct ParseU256Error;
24
25impl fmt::Display for ParseU256Error {
26 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
27 formatter.write_str("value is not an unsigned 256-bit integer")
28 }
29}
30
31impl std::error::Error for ParseU256Error {}
32
33#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
39#[repr(transparent)]
40pub struct U256(EthU256);
41
42impl U256 {
43 pub const MIN: Self = Self::ZERO;
45
46 pub const ZERO: Self = Self(EthU256::ZERO);
48
49 pub const ONE: Self = Self(EthU256::ONE);
51
52 pub const MAX: Self = Self(EthU256::MAX);
54
55 #[must_use]
57 pub const fn from_words(high: u128, low: u128) -> Self {
58 Self(EthU256::from_words(high, low))
59 }
60
61 #[must_use]
63 pub const fn into_words(self) -> (u128, u128) {
64 self.0.into_words()
65 }
66
67 #[must_use]
69 pub fn from_be_bytes(bytes: [u8; 32]) -> Self {
70 Self(EthU256::from_be_bytes(bytes))
71 }
72
73 #[must_use]
75 pub fn to_be_bytes(self) -> [u8; 32] {
76 self.0.to_be_bytes()
77 }
78
79 #[must_use]
81 pub const fn to_u128(self) -> Option<u128> {
82 let (high, low) = self.into_words();
83 if high == 0 { Some(low) } else { None }
84 }
85
86 #[must_use]
88 pub fn checked_add(self, rhs: Self) -> Option<Self> {
89 self.0.checked_add(rhs.0).map(Self)
90 }
91
92 #[must_use]
94 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
95 self.0.checked_sub(rhs.0).map(Self)
96 }
97
98 #[must_use]
100 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
101 self.0.checked_mul(rhs.0).map(Self)
102 }
103
104 #[must_use]
106 pub fn checked_div(self, rhs: Self) -> Option<Self> {
107 self.0.checked_div(rhs.0).map(Self)
108 }
109
110 #[must_use]
112 pub fn checked_rem(self, rhs: Self) -> Option<Self> {
113 self.0.checked_rem(rhs.0).map(Self)
114 }
115
116 fn from_little_endian_magnitude(bytes: &[u8]) -> Result<Self, ParseU256Error> {
117 if bytes.len() > 32 {
118 return Err(ParseU256Error);
119 }
120 let mut fixed = [0_u8; 32];
121 for (destination, source) in fixed.iter_mut().rev().zip(bytes) {
122 *destination = *source;
123 }
124 Ok(Self::from_be_bytes(fixed))
125 }
126
127 fn to_candid_nat(self) -> Nat {
128 Nat(BigUint::from_bytes_be(&self.to_be_bytes()))
129 }
130
131 fn decimal_text(self) -> DecimalText {
132 let (high, low) = self.into_words();
133 let mut limbs = [
134 low_u32_from_u128(high >> 96),
135 low_u32_from_u128(high >> 64),
136 low_u32_from_u128(high >> 32),
137 low_u32_from_u128(high),
138 low_u32_from_u128(low >> 96),
139 low_u32_from_u128(low >> 64),
140 low_u32_from_u128(low >> 32),
141 low_u32_from_u128(low),
142 ];
143 let mut bytes = [0_u8; DECIMAL_BUFFER_LEN];
144 let mut start = bytes.len();
145
146 loop {
147 let mut remainder = 0_u64;
148 let mut quotient_is_zero = true;
149 for limb in &mut limbs {
150 let dividend = (remainder << 32) | u64::from(*limb);
151 let quotient = dividend / DECIMAL_CHUNK_BASE;
152 remainder = dividend % DECIMAL_CHUNK_BASE;
153 *limb = u32::try_from(quotient).unwrap_or_default();
155 quotient_is_zero &= quotient == 0;
156 }
157
158 let mut chunk = u32::try_from(remainder).unwrap_or_default();
160 for _ in 0..DECIMAL_CHUNK_WIDTH {
161 start -= 1;
162 bytes[start] = b'0' + u8::try_from(chunk % 10).unwrap_or_default();
163 chunk /= 10;
164 }
165 if quotient_is_zero {
166 break;
167 }
168 }
169 while start + 1 < bytes.len() && bytes[start] == b'0' {
170 start += 1;
171 }
172
173 DecimalText { bytes, start }
174 }
175}
176
177fn low_u32_from_u128(value: u128) -> u32 {
178 u32::try_from(value & U128_LOW_U32_MASK).unwrap_or_default()
179}
180
181struct DecimalText {
182 bytes: [u8; DECIMAL_BUFFER_LEN],
183 start: usize,
184}
185
186impl DecimalText {
187 fn as_str(&self) -> &str {
188 std::str::from_utf8(&self.bytes[self.start..]).unwrap_or_default()
189 }
190}
191
192impl CandidType for U256 {
193 fn ty() -> Type {
194 TypeInner::Nat.into()
195 }
196
197 fn _ty() -> Type {
198 TypeInner::Nat.into()
199 }
200
201 fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
202 where
203 S: Serializer,
204 {
205 serializer.serialize_nat(&self.to_candid_nat())
206 }
207}
208
209impl fmt::Debug for U256 {
210 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
211 fmt::Display::fmt(self, formatter)
212 }
213}
214
215impl fmt::Display for U256 {
216 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
217 let text = self.decimal_text();
218 formatter.write_str(text.as_str())
219 }
220}
221
222impl From<u64> for U256 {
223 fn from(value: u64) -> Self {
224 Self(EthU256::from(value))
225 }
226}
227
228impl From<u128> for U256 {
229 fn from(value: u128) -> Self {
230 Self(EthU256::from(value))
231 }
232}
233
234impl FromStr for U256 {
235 type Err = ParseU256Error;
236
237 fn from_str(value: &str) -> Result<Self, Self::Err> {
238 if value.is_empty()
239 || value.len() > MAX_DECIMAL_DIGITS
240 || !value.bytes().all(|byte| byte.is_ascii_digit())
241 {
242 return Err(ParseU256Error);
243 }
244 value
245 .parse::<EthU256>()
246 .map(Self)
247 .map_err(|_| ParseU256Error)
248 }
249}
250
251impl NumericValue for U256 {
252 fn try_to_decimal(&self) -> Option<Decimal> {
253 self.to_u128().and_then(Decimal::from_u128)
254 }
255
256 fn try_from_decimal(value: Decimal) -> Option<Self> {
257 value.to_u128().map(Self::from)
258 }
259}
260
261impl<'de> Deserialize<'de> for U256 {
262 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
263 where
264 D: Deserializer<'de>,
265 {
266 struct U256Visitor;
267
268 impl Visitor<'_> for U256Visitor {
269 type Value = U256;
270
271 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
272 formatter.write_str("an unsigned 256-bit integer")
273 }
274
275 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
276 Ok(U256::from(value))
277 }
278
279 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
280 where
281 E: de::Error,
282 {
283 value.parse().map_err(E::custom)
284 }
285
286 fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Self::Value, E>
287 where
288 E: de::Error,
289 {
290 let Some((&marker, magnitude)) = value.split_first() else {
291 return Err(E::custom(ParseU256Error));
292 };
293 if marker != 1 {
294 return Err(E::custom(ParseU256Error));
295 }
296 U256::from_little_endian_magnitude(magnitude).map_err(E::custom)
297 }
298 }
299
300 deserializer.deserialize_any(U256Visitor)
301 }
302}
303
304impl Serialize for U256 {
305 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
306 where
307 S: SerdeSerializer,
308 {
309 serializer.serialize_str(self.to_string().as_str())
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::U256;
316 use crate::{Decimal, NumericValue};
317 use candid::{CandidType, decode_one, encode_one};
318 use num_bigint::BigUint;
319
320 #[test]
321 fn candid_uses_nat_and_rejects_values_above_maximum() {
322 assert_eq!(U256::ty(), candid::Nat::ty());
323
324 let encoded = encode_one(U256::MAX).expect("U256 should encode");
325 assert_eq!(
326 decode_one::<U256>(&encoded).expect("U256 should decode"),
327 U256::MAX
328 );
329
330 let above = candid::Nat(BigUint::from(1_u8) << 256_usize);
331 let encoded = encode_one(above).expect("Nat should encode");
332 assert!(decode_one::<U256>(&encoded).is_err());
333 }
334
335 #[test]
336 fn fixed_bytes_and_decimal_are_exact() {
337 let value = "57896044618658097711785492504343953926634992332820282019728792003956564819968"
338 .parse::<U256>()
339 .expect("2^255 should parse");
340 assert_eq!(value.to_be_bytes()[0], 0x80);
341 assert_eq!(U256::from_be_bytes(value.to_be_bytes()), value);
342 assert_eq!(
343 value.to_string(),
344 "57896044618658097711785492504343953926634992332820282019728792003956564819968"
345 );
346 assert_eq!(U256::ZERO.to_string(), "0");
347 assert_eq!(U256::ONE.to_string(), "1");
348 assert_eq!(U256::MAX.to_string(), u256_max_decimal());
349 }
350
351 #[test]
352 fn checked_arithmetic_enforces_the_u256_domain() {
353 let two = U256::from(2_u64);
354 let three = U256::from(3_u64);
355
356 assert_eq!(two.checked_add(three), Some(U256::from(5_u64)));
357 assert_eq!(three.checked_sub(two), Some(U256::ONE));
358 assert_eq!(two.checked_mul(three), Some(U256::from(6_u64)));
359 assert_eq!(U256::from(7_u64).checked_div(two), Some(three));
360 assert_eq!(U256::from(7_u64).checked_rem(two), Some(U256::ONE));
361 assert_eq!(U256::MAX.checked_add(U256::ONE), None);
362 assert_eq!(U256::ZERO.checked_sub(U256::ONE), None);
363 assert_eq!(U256::MAX.checked_mul(two), None);
364 assert_eq!(U256::ONE.checked_div(U256::ZERO), None);
365 assert_eq!(U256::ONE.checked_rem(U256::ZERO), None);
366 }
367
368 #[test]
369 fn generic_numeric_conversion_is_fallible_without_widening_the_u256_domain() {
370 let value = U256::from(u128::try_from(i128::MAX).expect("i128::MAX should fit u128"));
371 assert_eq!(
372 value.try_to_decimal().and_then(U256::try_from_decimal),
373 Some(value),
374 );
375 assert_eq!(U256::MAX.try_to_decimal(), None);
376 let negative_one = Decimal::from_i128(-1).expect("-1 should be a valid Decimal");
377 assert_eq!(U256::try_from_decimal(negative_one), None);
378 }
379
380 fn u256_max_decimal() -> &'static str {
381 "115792089237316195423570985008687907853269984665640564039457584007913129639935"
382 }
383}