1#![allow(missing_copy_implementations, missing_debug_implementations)]
10
11use crate::{abi::token::*, private::SolTypeValue, utils, SolType, Word};
12use alloc::{string::String as RustString, vec::Vec};
13use alloy_primitives::{
14 aliases::*, keccak256, Address as RustAddress, Bytes as RustBytes,
15 FixedBytes as RustFixedBytes, Function as RustFunction, I256, U256,
16};
17use core::{borrow::Borrow, fmt::*, hash::Hash, marker::PhantomData, ops::*};
18
19pub struct Bool;
24
25impl SolTypeValue<Bool> for bool {
26 #[inline]
27 fn stv_to_tokens(&self) -> WordToken {
28 WordToken(Word::with_last_byte(*self as u8))
29 }
30
31 #[inline]
32 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
33 out.push(*self as u8);
34 }
35
36 #[inline]
37 fn stv_eip712_data_word(&self) -> Word {
38 SolTypeValue::<Bool>::stv_to_tokens(self).0
39 }
40}
41
42impl SolType for Bool {
43 type RustType = bool;
44 type Token<'a> = WordToken;
45
46 const SOL_NAME: &'static str = "bool";
47 const ENCODED_SIZE: Option<usize> = Some(32);
48 const PACKED_ENCODED_SIZE: Option<usize> = Some(1);
49
50 #[inline]
51 fn valid_token(token: &Self::Token<'_>) -> bool {
52 utils::check_zeroes(&token.0[..31])
53 }
54
55 #[inline]
56 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
57 token.0 != Word::ZERO
58 }
59}
60
61pub struct Int<const BITS: usize>;
63
64impl<T, const BITS: usize> SolTypeValue<Int<BITS>> for T
65where
66 T: Borrow<<IntBitCount<BITS> as SupportedInt>::Int>,
67 IntBitCount<BITS>: SupportedInt,
68{
69 #[inline]
70 fn stv_to_tokens(&self) -> WordToken {
71 IntBitCount::<BITS>::tokenize_int(*self.borrow())
72 }
73
74 #[inline]
75 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
76 IntBitCount::<BITS>::encode_packed_to_int(*self.borrow(), out);
77 }
78
79 #[inline]
80 fn stv_eip712_data_word(&self) -> Word {
81 SolTypeValue::<Int<BITS>>::stv_to_tokens(self).0
82 }
83}
84
85impl<const BITS: usize> SolType for Int<BITS>
86where
87 IntBitCount<BITS>: SupportedInt,
88{
89 type RustType = <IntBitCount<BITS> as SupportedInt>::Int;
90 type Token<'a> = WordToken;
91
92 const SOL_NAME: &'static str = IntBitCount::<BITS>::INT_NAME;
93 const ENCODED_SIZE: Option<usize> = Some(32);
94 const PACKED_ENCODED_SIZE: Option<usize> = Some(BITS / 8);
95
96 #[inline]
97 fn valid_token(token: &Self::Token<'_>) -> bool {
98 if BITS == 256 {
99 return true;
100 }
101
102 let is_negative = token.0[IntBitCount::<BITS>::WORD_MSB] & 0x80 == 0x80;
103 let sign_extension = is_negative as u8 * 0xff;
104
105 token.0[..IntBitCount::<BITS>::WORD_MSB].iter().all(|byte| *byte == sign_extension)
107 }
108
109 #[inline]
110 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
111 IntBitCount::<BITS>::detokenize_int(token)
112 }
113}
114
115pub struct Uint<const BITS: usize>;
117
118impl<const BITS: usize, T> SolTypeValue<Uint<BITS>> for T
119where
120 T: Borrow<<IntBitCount<BITS> as SupportedInt>::Uint>,
121 IntBitCount<BITS>: SupportedInt,
122{
123 #[inline]
124 fn stv_to_tokens(&self) -> WordToken {
125 IntBitCount::<BITS>::tokenize_uint(*self.borrow())
126 }
127
128 #[inline]
129 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
130 IntBitCount::<BITS>::encode_packed_to_uint(*self.borrow(), out);
131 }
132
133 #[inline]
134 fn stv_eip712_data_word(&self) -> Word {
135 SolTypeValue::<Uint<BITS>>::stv_to_tokens(self).0
136 }
137}
138
139impl<const BITS: usize> SolType for Uint<BITS>
140where
141 IntBitCount<BITS>: SupportedInt,
142{
143 type RustType = <IntBitCount<BITS> as SupportedInt>::Uint;
144 type Token<'a> = WordToken;
145
146 const SOL_NAME: &'static str = IntBitCount::<BITS>::UINT_NAME;
147 const ENCODED_SIZE: Option<usize> = Some(32);
148 const PACKED_ENCODED_SIZE: Option<usize> = Some(BITS / 8);
149
150 #[inline]
151 fn valid_token(token: &Self::Token<'_>) -> bool {
152 utils::check_zeroes(&token.0[..<IntBitCount<BITS> as SupportedInt>::WORD_MSB])
153 }
154
155 #[inline]
156 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
157 IntBitCount::<BITS>::detokenize_uint(token)
158 }
159}
160
161#[derive(Clone, Copy, Debug)]
163pub struct FixedBytes<const N: usize>;
164
165impl<T: Borrow<[u8; N]>, const N: usize> SolTypeValue<FixedBytes<N>> for T
166where
167 ByteCount<N>: SupportedFixedBytes,
168{
169 #[inline]
170 fn stv_to_tokens(&self) -> <FixedBytes<N> as SolType>::Token<'_> {
171 let mut word = Word::ZERO;
172 word[..N].copy_from_slice(self.borrow());
173 word.into()
174 }
175
176 #[inline]
177 fn stv_eip712_data_word(&self) -> Word {
178 SolTypeValue::<FixedBytes<N>>::stv_to_tokens(self).0
179 }
180
181 #[inline]
182 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
183 out.extend_from_slice(self.borrow().as_slice());
184 }
185}
186
187impl<const N: usize> SolType for FixedBytes<N>
188where
189 ByteCount<N>: SupportedFixedBytes,
190{
191 type RustType = RustFixedBytes<N>;
192 type Token<'a> = WordToken;
193
194 const SOL_NAME: &'static str = <ByteCount<N>>::NAME;
195 const ENCODED_SIZE: Option<usize> = Some(32);
196 const PACKED_ENCODED_SIZE: Option<usize> = Some(N);
197
198 #[inline]
199 fn valid_token(token: &Self::Token<'_>) -> bool {
200 utils::check_zeroes(&token.0[N..])
201 }
202
203 #[inline]
204 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
205 token.0[..N].try_into().unwrap()
206 }
207}
208
209pub struct Address;
211
212impl<T: Borrow<[u8; 20]>> SolTypeValue<Address> for T {
213 #[inline]
214 fn stv_to_tokens(&self) -> WordToken {
215 WordToken(RustAddress::new(*self.borrow()).into_word())
216 }
217
218 #[inline]
219 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
220 out.extend_from_slice(self.borrow());
221 }
222
223 #[inline]
224 fn stv_eip712_data_word(&self) -> Word {
225 SolTypeValue::<Address>::stv_to_tokens(self).0
226 }
227}
228
229impl SolType for Address {
230 type RustType = RustAddress;
231 type Token<'a> = WordToken;
232
233 const SOL_NAME: &'static str = "address";
234 const ENCODED_SIZE: Option<usize> = Some(32);
235 const PACKED_ENCODED_SIZE: Option<usize> = Some(20);
236
237 #[inline]
238 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
239 RustAddress::from_word(token.0)
240 }
241
242 #[inline]
243 fn valid_token(token: &Self::Token<'_>) -> bool {
244 utils::check_zeroes(&token.0[..12])
245 }
246}
247
248pub struct Function;
250
251impl<T: Borrow<[u8; 24]>> SolTypeValue<Function> for T {
252 #[inline]
253 fn stv_to_tokens(&self) -> WordToken {
254 WordToken(RustFunction::new(*self.borrow()).into_word())
255 }
256
257 #[inline]
258 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
259 out.extend_from_slice(self.borrow());
260 }
261
262 #[inline]
263 fn stv_eip712_data_word(&self) -> Word {
264 SolTypeValue::<Function>::stv_to_tokens(self).0
265 }
266}
267
268impl SolType for Function {
269 type RustType = RustFunction;
270 type Token<'a> = WordToken;
271
272 const SOL_NAME: &'static str = "function";
273 const ENCODED_SIZE: Option<usize> = Some(32);
274 const PACKED_ENCODED_SIZE: Option<usize> = Some(24);
275
276 #[inline]
277 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
278 RustFunction::from_word(token.0)
279 }
280
281 #[inline]
282 fn valid_token(token: &Self::Token<'_>) -> bool {
283 utils::check_zeroes(&token.0[24..])
284 }
285}
286
287pub struct Bytes;
289
290impl<T: ?Sized + AsRef<[u8]>> SolTypeValue<Bytes> for T {
291 #[inline]
292 fn stv_to_tokens(&self) -> PackedSeqToken<'_> {
293 PackedSeqToken(self.as_ref())
294 }
295
296 #[inline]
297 fn stv_abi_encoded_size(&self) -> usize {
298 let s = self.as_ref();
299 if s.is_empty() {
300 64
301 } else {
302 64 + utils::padded_len(s)
303 }
304 }
305
306 #[inline]
307 fn stv_eip712_data_word(&self) -> Word {
308 keccak256(Bytes::abi_encode_packed(self))
309 }
310
311 #[inline]
312 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
313 out.extend_from_slice(self.as_ref());
314 }
315
316 #[inline]
317 fn stv_abi_packed_encoded_size(&self) -> usize {
318 self.as_ref().len()
319 }
320}
321
322impl SolType for Bytes {
323 type RustType = RustBytes;
324 type Token<'a> = PackedSeqToken<'a>;
325
326 const SOL_NAME: &'static str = "bytes";
327 const ENCODED_SIZE: Option<usize> = None;
328 const PACKED_ENCODED_SIZE: Option<usize> = None;
329
330 #[inline]
331 fn valid_token(_token: &Self::Token<'_>) -> bool {
332 true
333 }
334
335 #[inline]
336 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
337 token.into_bytes()
338 }
339}
340
341pub struct String;
343
344impl<T: ?Sized + AsRef<str>> SolTypeValue<String> for T {
345 #[inline]
346 fn stv_to_tokens(&self) -> PackedSeqToken<'_> {
347 PackedSeqToken(self.as_ref().as_bytes())
348 }
349
350 #[inline]
351 fn stv_abi_encoded_size(&self) -> usize {
352 let s = self.as_ref();
353 if s.is_empty() {
354 64
355 } else {
356 64 + utils::padded_len(s.as_bytes())
357 }
358 }
359
360 #[inline]
361 fn stv_eip712_data_word(&self) -> Word {
362 keccak256(String::abi_encode_packed(self))
363 }
364
365 #[inline]
366 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
367 out.extend_from_slice(self.as_ref().as_ref());
368 }
369
370 #[inline]
371 fn stv_abi_packed_encoded_size(&self) -> usize {
372 self.as_ref().len()
373 }
374}
375
376impl SolType for String {
377 type RustType = RustString;
378 type Token<'a> = PackedSeqToken<'a>;
379
380 const SOL_NAME: &'static str = "string";
381 const ENCODED_SIZE: Option<usize> = None;
382 const PACKED_ENCODED_SIZE: Option<usize> = None;
383
384 #[inline]
385 fn valid_token(token: &Self::Token<'_>) -> bool {
386 core::str::from_utf8(token.as_slice()).is_ok()
387 }
388
389 #[inline]
390 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
391 RustString::from_utf8_lossy(token.as_slice()).into_owned()
396 }
397}
398
399pub struct Array<T: SolType>(PhantomData<T>);
401
402impl<T, U> SolTypeValue<Array<U>> for [T]
403where
404 T: SolTypeValue<U>,
405 U: SolType,
406{
407 #[inline]
408 fn stv_to_tokens(&self) -> DynSeqToken<U::Token<'_>> {
409 DynSeqToken(self.iter().map(T::stv_to_tokens).collect())
410 }
411
412 #[inline]
413 fn stv_abi_encoded_size(&self) -> usize {
414 if let Some(size) = Array::<U>::ENCODED_SIZE {
415 return size;
416 }
417
418 64 + self.iter().map(T::stv_abi_encoded_size).sum::<usize>()
419 }
420
421 #[inline]
422 fn stv_eip712_data_word(&self) -> Word {
423 let mut encoded = Vec::new();
424 for item in self {
425 encoded.extend_from_slice(T::stv_eip712_data_word(item).as_slice());
426 }
427 keccak256(encoded)
428 }
429
430 #[inline]
431 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
432 for item in self {
433 if let Some(padding_needed) = 32usize.checked_sub(item.stv_abi_packed_encoded_size()) {
435 out.extend(core::iter::repeat(0).take(padding_needed));
436 }
437 T::stv_abi_encode_packed_to(item, out);
438 }
439 }
440
441 #[inline]
442 fn stv_abi_packed_encoded_size(&self) -> usize {
443 self.iter().map(|item| item.stv_abi_packed_encoded_size().max(32)).sum()
444 }
445}
446
447impl<T, U> SolTypeValue<Array<U>> for &[T]
448where
449 T: SolTypeValue<U>,
450 U: SolType,
451{
452 #[inline]
453 fn stv_to_tokens(&self) -> DynSeqToken<U::Token<'_>> {
454 (**self).stv_to_tokens()
455 }
456
457 #[inline]
458 fn stv_abi_encoded_size(&self) -> usize {
459 (**self).stv_abi_encoded_size()
460 }
461
462 #[inline]
463 fn stv_eip712_data_word(&self) -> Word {
464 (**self).stv_eip712_data_word()
465 }
466
467 #[inline]
468 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
469 (**self).stv_abi_encode_packed_to(out)
470 }
471
472 #[inline]
473 fn stv_abi_packed_encoded_size(&self) -> usize {
474 (**self).stv_abi_packed_encoded_size()
475 }
476}
477
478impl<T, U> SolTypeValue<Array<U>> for &mut [T]
479where
480 T: SolTypeValue<U>,
481 U: SolType,
482{
483 #[inline]
484 fn stv_to_tokens(&self) -> DynSeqToken<U::Token<'_>> {
485 (**self).stv_to_tokens()
486 }
487
488 #[inline]
489 fn stv_abi_encoded_size(&self) -> usize {
490 (**self).stv_abi_encoded_size()
491 }
492
493 #[inline]
494 fn stv_eip712_data_word(&self) -> Word {
495 (**self).stv_eip712_data_word()
496 }
497
498 #[inline]
499 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
500 (**self).stv_abi_encode_packed_to(out)
501 }
502
503 #[inline]
504 fn stv_abi_packed_encoded_size(&self) -> usize {
505 (**self).stv_abi_packed_encoded_size()
506 }
507}
508
509impl<T, U> SolTypeValue<Array<U>> for Vec<T>
510where
511 T: SolTypeValue<U>,
512 U: SolType,
513{
514 #[inline]
515 fn stv_to_tokens(&self) -> DynSeqToken<U::Token<'_>> {
516 <[T] as SolTypeValue<Array<U>>>::stv_to_tokens(self)
517 }
518
519 #[inline]
520 fn stv_abi_encoded_size(&self) -> usize {
521 (**self).stv_abi_encoded_size()
522 }
523
524 #[inline]
525 fn stv_eip712_data_word(&self) -> Word {
526 (**self).stv_eip712_data_word()
527 }
528
529 #[inline]
530 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
531 (**self).stv_abi_encode_packed_to(out)
532 }
533
534 #[inline]
535 fn stv_abi_packed_encoded_size(&self) -> usize {
536 (**self).stv_abi_packed_encoded_size()
537 }
538}
539
540impl<T: SolType> SolType for Array<T> {
541 type RustType = Vec<T::RustType>;
542 type Token<'a> = DynSeqToken<T::Token<'a>>;
543
544 const SOL_NAME: &'static str =
545 NameBuffer::new().write_str(T::SOL_NAME).write_str("[]").as_str();
546 const ENCODED_SIZE: Option<usize> = None;
547 const PACKED_ENCODED_SIZE: Option<usize> = None;
548
549 #[inline]
550 fn valid_token(token: &Self::Token<'_>) -> bool {
551 token.0.iter().all(T::valid_token)
552 }
553
554 #[inline]
555 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
556 token.0.into_iter().map(T::detokenize).collect()
557 }
558}
559
560pub struct FixedArray<T, const N: usize>(PhantomData<T>);
562
563impl<T, U, const N: usize> SolTypeValue<FixedArray<U, N>> for [T; N]
564where
565 T: SolTypeValue<U>,
566 U: SolType,
567{
568 #[inline]
569 fn stv_to_tokens(&self) -> <FixedArray<U, N> as SolType>::Token<'_> {
570 FixedSeqToken(core::array::from_fn(|i| self[i].stv_to_tokens()))
571 }
572
573 #[inline]
574 fn stv_abi_encoded_size(&self) -> usize {
575 if let Some(size) = FixedArray::<U, N>::ENCODED_SIZE {
576 return size;
577 }
578
579 let sum = self.iter().map(T::stv_abi_encoded_size).sum::<usize>();
580 if FixedArray::<U, N>::DYNAMIC {
581 32 + sum
582 } else {
583 sum
584 }
585 }
586
587 #[inline]
588 fn stv_eip712_data_word(&self) -> Word {
589 let encoded = core::array::from_fn::<_, N, _>(|i| self[i].stv_eip712_data_word().0);
590 keccak256(encoded.as_flattened())
591 }
592
593 #[inline]
594 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
595 for item in self {
596 if let Some(padding_needed) = 32usize.checked_sub(item.stv_abi_packed_encoded_size()) {
598 out.extend(core::iter::repeat(0).take(padding_needed));
599 }
600 item.stv_abi_encode_packed_to(out);
601 }
602 }
603
604 #[inline]
605 fn stv_abi_packed_encoded_size(&self) -> usize {
606 self.iter().map(|item| item.stv_abi_packed_encoded_size().max(32)).sum()
607 }
608}
609
610impl<T, U, const N: usize> SolTypeValue<FixedArray<U, N>> for &[T; N]
611where
612 T: SolTypeValue<U>,
613 U: SolType,
614{
615 #[inline]
616 fn stv_to_tokens(&self) -> <FixedArray<U, N> as SolType>::Token<'_> {
617 <[T; N] as SolTypeValue<FixedArray<U, N>>>::stv_to_tokens(&**self)
618 }
619
620 #[inline]
621 fn stv_abi_encoded_size(&self) -> usize {
622 SolTypeValue::<FixedArray<U, N>>::stv_abi_encoded_size(&**self)
623 }
624
625 #[inline]
626 fn stv_eip712_data_word(&self) -> Word {
627 SolTypeValue::<FixedArray<U, N>>::stv_eip712_data_word(&**self)
628 }
629
630 #[inline]
631 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
632 SolTypeValue::<FixedArray<U, N>>::stv_abi_encode_packed_to(&**self, out)
633 }
634
635 #[inline]
636 fn stv_abi_packed_encoded_size(&self) -> usize {
637 SolTypeValue::<FixedArray<U, N>>::stv_abi_packed_encoded_size(&**self)
638 }
639}
640
641impl<T, U, const N: usize> SolTypeValue<FixedArray<U, N>> for &mut [T; N]
642where
643 T: SolTypeValue<U>,
644 U: SolType,
645{
646 #[inline]
647 fn stv_to_tokens(&self) -> <FixedArray<U, N> as SolType>::Token<'_> {
648 <[T; N] as SolTypeValue<FixedArray<U, N>>>::stv_to_tokens(&**self)
649 }
650
651 #[inline]
652 fn stv_abi_encoded_size(&self) -> usize {
653 SolTypeValue::<FixedArray<U, N>>::stv_abi_encoded_size(&**self)
654 }
655
656 #[inline]
657 fn stv_eip712_data_word(&self) -> Word {
658 SolTypeValue::<FixedArray<U, N>>::stv_eip712_data_word(&**self)
659 }
660
661 #[inline]
662 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
663 SolTypeValue::<FixedArray<U, N>>::stv_abi_encode_packed_to(&**self, out)
664 }
665
666 #[inline]
667 fn stv_abi_packed_encoded_size(&self) -> usize {
668 SolTypeValue::<FixedArray<U, N>>::stv_abi_packed_encoded_size(&**self)
669 }
670}
671
672impl<T: SolType, const N: usize> SolType for FixedArray<T, N> {
673 type RustType = [T::RustType; N];
674 type Token<'a> = FixedSeqToken<T::Token<'a>, N>;
675
676 const SOL_NAME: &'static str = NameBuffer::new()
677 .write_str(T::SOL_NAME)
678 .write_byte(b'[')
679 .write_usize(N)
680 .write_byte(b']')
681 .as_str();
682 const ENCODED_SIZE: Option<usize> = match T::ENCODED_SIZE {
683 Some(size) => Some(size * N),
684 None => None,
685 };
686 const PACKED_ENCODED_SIZE: Option<usize> = None;
687
688 #[inline]
689 fn valid_token(token: &Self::Token<'_>) -> bool {
690 token.as_array().iter().all(T::valid_token)
691 }
692
693 #[inline]
694 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
695 token.0.map(T::detokenize)
696 }
697}
698
699macro_rules! tuple_encodable_impls {
700 ($count:literal $(($ty:ident $uty:ident)),+) => {
701 #[allow(non_snake_case)]
702 impl<$($ty: SolTypeValue<$uty>, $uty: SolType),+> SolTypeValue<($($uty,)+)> for ($($ty,)+) {
703 #[inline]
704 fn stv_to_tokens(&self) -> <($($uty,)+) as SolType>::Token<'_> {
705 let ($($ty,)+) = self;
706 ($(SolTypeValue::<$uty>::stv_to_tokens($ty),)+)
707 }
708
709 fn stv_abi_encoded_size(&self) -> usize {
710 if let Some(size) = <($($uty,)+) as SolType>::ENCODED_SIZE {
711 return size
712 }
713
714 let ($($ty,)+) = self;
715 let sum = 0 $( + $ty.stv_abi_encoded_size() )+;
716 if <($($uty,)+) as SolType>::DYNAMIC {
717 32 + sum
718 } else {
719 sum
720 }
721 }
722
723 fn stv_abi_encode_packed_to(&self, out: &mut Vec<u8>) {
724 let ($($ty,)+) = self;
725 $(
726 $ty.stv_abi_encode_packed_to(out);
727 )+
728 }
729
730 fn stv_eip712_data_word(&self) -> Word {
731 let ($($ty,)+) = self;
732 let encoding: [[u8; 32]; $count] = [$(
733 <$uty as SolType>::eip712_data_word($ty).0,
734 )+];
735 let encoding: &[u8] = unsafe { core::slice::from_raw_parts(encoding.as_ptr().cast(), $count * 32) };
737 keccak256(encoding).into()
738 }
739
740 fn stv_abi_packed_encoded_size(&self) -> usize {
741 let ($($ty,)+) = self;
742 0 $(+ $ty.stv_abi_packed_encoded_size())+
743 }
744 }
745 };
746}
747
748macro_rules! tuple_impls {
749 ($count:literal $($ty:ident),+) => {
750 #[allow(non_snake_case)]
751 impl<$($ty: SolType,)+> SolType for ($($ty,)+) {
752 type RustType = ($( $ty::RustType, )+);
753 type Token<'a> = ($( $ty::Token<'a>, )+);
754
755 const SOL_NAME: &'static str = NameBuffer::new()
756 .write_byte(b'(')
757 $(
758 .write_str($ty::SOL_NAME)
759 .write_byte(b',')
760 )+
761 .pop() .write_byte(b')')
763 .as_str();
764 const ENCODED_SIZE: Option<usize> = 'l: {
765 let mut acc = 0;
766 $(
767 match <$ty as SolType>::ENCODED_SIZE {
768 Some(size) => acc += size,
769 None => break 'l None,
770 }
771 )+
772 Some(acc)
773 };
774 const PACKED_ENCODED_SIZE: Option<usize> = 'l: {
775 let mut acc = 0;
776 $(
777 match <$ty as SolType>::PACKED_ENCODED_SIZE {
778 Some(size) => acc += size,
779 None => break 'l None,
780 }
781 )+
782 Some(acc)
783 };
784
785 fn valid_token(token: &Self::Token<'_>) -> bool {
786 let ($($ty,)+) = token;
787 $(<$ty as SolType>::valid_token($ty))&&+
788 }
789
790 fn detokenize(token: Self::Token<'_>) -> Self::RustType {
791 let ($($ty,)+) = token;
792 ($(
793 <$ty as SolType>::detokenize($ty),
794 )+)
795 }
796 }
797 };
798}
799
800impl SolTypeValue<()> for () {
801 #[inline]
802 fn stv_to_tokens(&self) {}
803
804 #[inline]
805 fn stv_eip712_data_word(&self) -> Word {
806 Word::ZERO
807 }
808
809 #[inline]
810 fn stv_abi_encode_packed_to(&self, _out: &mut Vec<u8>) {}
811}
812
813all_the_tuples!(@double tuple_encodable_impls);
814
815impl SolType for () {
816 type RustType = ();
817 type Token<'a> = ();
818
819 const SOL_NAME: &'static str = "()";
820 const ENCODED_SIZE: Option<usize> = Some(0);
821 const PACKED_ENCODED_SIZE: Option<usize> = Some(0);
822
823 #[inline]
824 fn valid_token((): &()) -> bool {
825 true
826 }
827
828 #[inline]
829 fn detokenize((): ()) -> Self::RustType {}
830}
831
832all_the_tuples!(tuple_impls);
833
834#[allow(unknown_lints, unnameable_types)]
835mod sealed {
836 pub trait Sealed {}
837}
838use sealed::Sealed;
839
840pub struct ByteCount<const N: usize>;
842
843impl<const N: usize> Sealed for ByteCount<N> {}
844
845pub trait SupportedFixedBytes: Sealed {
852 const NAME: &'static str;
854}
855
856macro_rules! supported_fixed_bytes {
857 ($($n:literal),+) => {$(
858 impl SupportedFixedBytes for ByteCount<$n> {
859 const NAME: &'static str = concat!("bytes", $n);
860 }
861 )+};
862}
863
864supported_fixed_bytes!(
865 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
866 27, 28, 29, 30, 31, 32
867);
868
869pub struct IntBitCount<const N: usize>;
871
872impl<const N: usize> Sealed for IntBitCount<N> {}
873
874macro_rules! declare_int_types {
878 ($($(#[$attr:meta])* type $name:ident;)*) => {$(
879 $(#[$attr])*
880 type $name: Sized + Copy + PartialOrd + Ord + Eq + Hash
881 + Not + BitAnd + BitOr + BitXor
882 + Add + Sub + Mul + Div + Rem
883 + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign
884 + Debug + Display + LowerHex + UpperHex + Octal + Binary;
885 )*};
886}
887
888pub trait SupportedInt: Sealed {
897 declare_int_types! {
898 type Int;
900
901 type Uint;
903 }
904
905 const INT_NAME: &'static str;
907
908 const UINT_NAME: &'static str;
910
911 const BITS: usize;
915
916 const BYTES: usize = Self::BITS / 8;
918
919 const SKIP_BYTES: usize;
924
925 const WORD_MSB: usize = 32 - Self::BYTES;
929
930 fn tokenize_int(int: Self::Int) -> WordToken;
932 fn detokenize_int(token: WordToken) -> Self::Int;
934 fn encode_packed_to_int(int: Self::Int, out: &mut Vec<u8>);
936
937 fn tokenize_uint(uint: Self::Uint) -> WordToken;
939 fn detokenize_uint(token: WordToken) -> Self::Uint;
941 fn encode_packed_to_uint(uint: Self::Uint, out: &mut Vec<u8>);
943}
944
945macro_rules! supported_int {
946 ($($n:literal => $i:ident, $u:ident;)+) => {$(
947 impl SupportedInt for IntBitCount<$n> {
948 type Int = $i;
949 type Uint = $u;
950
951 const UINT_NAME: &'static str = concat!("uint", $n);
952 const INT_NAME: &'static str = concat!("int", $n);
953
954 const BITS: usize = $n;
955 const SKIP_BYTES: usize = (<$i>::BITS as usize - <Self as SupportedInt>::BITS) / 8;
956
957 int_impls2!($i);
958 uint_impls2!($u);
959 }
960 )+};
961}
962
963macro_rules! int_impls {
964 (@primitive_int $ity:ident) => {
965 #[inline]
966 fn tokenize_int(int: $ity) -> WordToken {
967 let mut word = [int.is_negative() as u8 * 0xff; 32];
968 word[Self::WORD_MSB..].copy_from_slice(&int.to_be_bytes()[Self::SKIP_BYTES..]);
969 WordToken::new(word)
970 }
971
972 #[inline]
973 fn detokenize_int(mut token: WordToken) -> $ity {
974 let is_negative = token.0[Self::WORD_MSB] & 0x80 == 0x80;
976 let sign_extension = is_negative as u8 * 0xff;
977 token.0[Self::WORD_MSB - Self::SKIP_BYTES..Self::WORD_MSB].fill(sign_extension);
978
979 let s = &token.0[Self::WORD_MSB - Self::SKIP_BYTES..];
980 <$ity>::from_be_bytes(s.try_into().unwrap())
981 }
982
983 #[inline]
984 fn encode_packed_to_int(int: $ity, out: &mut Vec<u8>) {
985 out.extend_from_slice(&int.to_be_bytes()[Self::SKIP_BYTES..]);
986 }
987 };
988 (@primitive_uint $uty:ident) => {
989 #[inline]
990 fn tokenize_uint(uint: $uty) -> WordToken {
991 let mut word = Word::ZERO;
992 word[Self::WORD_MSB..].copy_from_slice(&uint.to_be_bytes()[Self::SKIP_BYTES..]);
993 WordToken(word)
994 }
995
996 #[inline]
997 fn detokenize_uint(mut token: WordToken) -> $uty {
998 token.0[Self::WORD_MSB - Self::SKIP_BYTES..Self::WORD_MSB].fill(0);
1002 let s = &token.0[Self::WORD_MSB - Self::SKIP_BYTES..];
1003 <$uty>::from_be_bytes(s.try_into().unwrap())
1004 }
1005
1006 #[inline]
1007 fn encode_packed_to_uint(uint: $uty, out: &mut Vec<u8>) {
1008 out.extend_from_slice(&uint.to_be_bytes()[Self::SKIP_BYTES..]);
1009 }
1010 };
1011
1012 (@big_int $ity:ident) => {
1013 #[inline]
1014 fn tokenize_int(int: $ity) -> WordToken {
1015 let mut word = [int.is_negative() as u8 * 0xff; 32];
1016 word[Self::WORD_MSB..]
1017 .copy_from_slice(&int.to_be_bytes::<{ $ity::BYTES }>()[Self::SKIP_BYTES..]);
1018 WordToken::new(word)
1019 }
1020
1021 #[inline]
1022 fn detokenize_int(mut token: WordToken) -> $ity {
1023 let is_negative = token.0[Self::WORD_MSB] & 0x80 == 0x80;
1025 let sign_extension = is_negative as u8 * 0xff;
1026 token.0[Self::WORD_MSB - Self::SKIP_BYTES..Self::WORD_MSB].fill(sign_extension);
1027
1028 let s = &token.0[Self::WORD_MSB - Self::SKIP_BYTES..];
1029 <$ity>::from_be_bytes::<{ $ity::BYTES }>(s.try_into().unwrap())
1030 }
1031
1032 #[inline]
1033 fn encode_packed_to_int(int: $ity, out: &mut Vec<u8>) {
1034 out.extend_from_slice(&int.to_be_bytes::<{ $ity::BYTES }>()[Self::SKIP_BYTES..]);
1035 }
1036 };
1037 (@big_uint $uty:ident) => {
1038 #[inline]
1039 fn tokenize_uint(uint: $uty) -> WordToken {
1040 let mut word = Word::ZERO;
1041 word[Self::WORD_MSB..]
1042 .copy_from_slice(&uint.to_be_bytes::<{ $uty::BYTES }>()[Self::SKIP_BYTES..]);
1043 WordToken(word)
1044 }
1045
1046 #[inline]
1047 fn detokenize_uint(mut token: WordToken) -> $uty {
1048 token.0[..Self::SKIP_BYTES].fill(0);
1050 let s = &token.0[Self::WORD_MSB - Self::SKIP_BYTES..];
1051 <$uty>::from_be_bytes::<{ $uty::BYTES }>(s.try_into().unwrap())
1052 }
1053
1054 #[inline]
1055 fn encode_packed_to_uint(uint: $uty, out: &mut Vec<u8>) {
1056 out.extend_from_slice(&uint.to_be_bytes::<{ $uty::BYTES }>()[Self::SKIP_BYTES..]);
1057 }
1058 };
1059}
1060
1061#[rustfmt::skip]
1062macro_rules! int_impls2 {
1063 ( i8) => { int_impls! { @primitive_int i8 } };
1064 ( i16) => { int_impls! { @primitive_int i16 } };
1065 ( i32) => { int_impls! { @primitive_int i32 } };
1066 ( i64) => { int_impls! { @primitive_int i64 } };
1067 (i128) => { int_impls! { @primitive_int i128 } };
1068
1069 ($t:ident) => { int_impls! { @big_int $t } };
1070}
1071
1072#[rustfmt::skip]
1073macro_rules! uint_impls2 {
1074 ( u8) => { int_impls! { @primitive_uint u8 } };
1075 ( u16) => { int_impls! { @primitive_uint u16 } };
1076 ( u32) => { int_impls! { @primitive_uint u32 } };
1077 ( u64) => { int_impls! { @primitive_uint u64 } };
1078 (u128) => { int_impls! { @primitive_uint u128 } };
1079
1080 ($t:ident) => { int_impls! { @big_uint $t } };
1081}
1082
1083supported_int!(
1084 8 => i8, u8;
1085 16 => i16, u16;
1086 24 => I24, U24;
1087 32 => i32, u32;
1088 40 => I40, U40;
1089 48 => I48, U48;
1090 56 => I56, U56;
1091 64 => i64, u64;
1092 72 => I72, U72;
1093 80 => I80, U80;
1094 88 => I88, U88;
1095 96 => I96, U96;
1096 104 => I104, U104;
1097 112 => I112, U112;
1098 120 => I120, U120;
1099 128 => i128, u128;
1100 136 => I136, U136;
1101 144 => I144, U144;
1102 152 => I152, U152;
1103 160 => I160, U160;
1104 168 => I168, U168;
1105 176 => I176, U176;
1106 184 => I184, U184;
1107 192 => I192, U192;
1108 200 => I200, U200;
1109 208 => I208, U208;
1110 216 => I216, U216;
1111 224 => I224, U224;
1112 232 => I232, U232;
1113 240 => I240, U240;
1114 248 => I248, U248;
1115 256 => I256, U256;
1116);
1117
1118const NAME_CAP: usize = 256;
1119
1120#[must_use]
1122struct NameBuffer {
1123 buffer: [u8; NAME_CAP],
1124 len: usize,
1125}
1126
1127impl NameBuffer {
1128 const fn new() -> Self {
1129 Self { buffer: [0; NAME_CAP], len: 0 }
1130 }
1131
1132 const fn write_str(self, s: &str) -> Self {
1133 self.write_bytes(s.as_bytes())
1134 }
1135
1136 const fn write_bytes(mut self, s: &[u8]) -> Self {
1137 let mut i = 0;
1138 while i < s.len() {
1139 self.buffer[self.len + i] = s[i];
1140 i += 1;
1141 }
1142 self.len += s.len();
1143 self
1144 }
1145
1146 const fn write_byte(mut self, b: u8) -> Self {
1147 self.buffer[self.len] = b;
1148 self.len += 1;
1149 self
1150 }
1151
1152 const fn write_usize(mut self, number: usize) -> Self {
1153 let Some(digits) = number.checked_ilog10() else {
1154 return self.write_byte(b'0');
1155 };
1156 let digits = digits as usize + 1;
1157
1158 let mut n = number;
1159 let mut i = self.len + digits;
1160 while n > 0 {
1161 i -= 1;
1162 self.buffer[i] = b'0' + (n % 10) as u8;
1163 n /= 10;
1164 }
1165 self.len += digits;
1166
1167 self
1168 }
1169
1170 const fn pop(mut self) -> Self {
1171 self.len -= 1;
1172 self
1173 }
1174
1175 const fn as_bytes(&self) -> &[u8] {
1176 assert!(self.len <= self.buffer.len());
1177 unsafe { core::slice::from_raw_parts(self.buffer.as_ptr(), self.len) }
1178 }
1179
1180 const fn as_str(&self) -> &str {
1181 match core::str::from_utf8(self.as_bytes()) {
1182 Ok(s) => s,
1183 Err(_) => panic!("wrote invalid UTF-8"),
1184 }
1185 }
1186}
1187
1188#[cfg(test)]
1189mod tests {
1190 use super::*;
1191 use crate::{sol, SolValue};
1192 use alloy_primitives::{hex, Signed};
1193
1194 #[test]
1195 fn sol_names() {
1196 macro_rules! assert_name {
1197 ($t:ty, $s:literal) => {
1198 assert_eq!(<$t as SolType>::SOL_NAME, $s);
1199 };
1200 }
1201
1202 assert_name!(Bool, "bool");
1203 assert_name!(Uint<8>, "uint8");
1204 assert_name!(Uint<16>, "uint16");
1205 assert_name!(Uint<32>, "uint32");
1206 assert_name!(Int<8>, "int8");
1207 assert_name!(Int<16>, "int16");
1208 assert_name!(Int<32>, "int32");
1209 assert_name!(FixedBytes<1>, "bytes1");
1210 assert_name!(FixedBytes<16>, "bytes16");
1211 assert_name!(FixedBytes<32>, "bytes32");
1212 assert_name!(Address, "address");
1213 assert_name!(Function, "function");
1214 assert_name!(Bytes, "bytes");
1215 assert_name!(String, "string");
1216
1217 assert_name!(Array<Uint<8>>, "uint8[]");
1218 assert_name!(Array<Bytes>, "bytes[]");
1219 assert_name!(FixedArray<Uint<8>, 0>, "uint8[0]");
1220 assert_name!(FixedArray<Uint<8>, 1>, "uint8[1]");
1221 assert_name!(FixedArray<Uint<8>, 2>, "uint8[2]");
1222 assert_name!((), "()");
1223 assert_name!((Uint<8>,), "(uint8)");
1224 assert_name!((Uint<8>, Bool), "(uint8,bool)");
1225 assert_name!((Uint<8>, Bool, FixedArray<Address, 4>), "(uint8,bool,address[4])");
1226 }
1227
1228 macro_rules! assert_encoded_size {
1229 ($t:ty, $sz:expr) => {
1230 let sz = $sz;
1231 assert_eq!(<$t as SolType>::ENCODED_SIZE, sz);
1232 assert_eq!(<$t as SolType>::DYNAMIC, sz.is_none());
1233 };
1234 }
1235
1236 #[test]
1237 fn primitive_encoded_sizes() {
1238 assert_encoded_size!(Bool, Some(32));
1239
1240 assert_encoded_size!(Uint<8>, Some(32));
1241 assert_encoded_size!(Int<8>, Some(32));
1242 assert_encoded_size!(Uint<16>, Some(32));
1243 assert_encoded_size!(Int<16>, Some(32));
1244 assert_encoded_size!(Uint<32>, Some(32));
1245 assert_encoded_size!(Int<32>, Some(32));
1246 assert_encoded_size!(Uint<64>, Some(32));
1247 assert_encoded_size!(Int<64>, Some(32));
1248 assert_encoded_size!(Uint<128>, Some(32));
1249 assert_encoded_size!(Int<128>, Some(32));
1250 assert_encoded_size!(Uint<256>, Some(32));
1251 assert_encoded_size!(Int<256>, Some(32));
1252
1253 assert_encoded_size!(Address, Some(32));
1254 assert_encoded_size!(Function, Some(32));
1255 assert_encoded_size!(FixedBytes<1>, Some(32));
1256 assert_encoded_size!(FixedBytes<16>, Some(32));
1257 assert_encoded_size!(FixedBytes<32>, Some(32));
1258
1259 assert_encoded_size!(Bytes, None);
1260 assert_encoded_size!(String, None);
1261
1262 assert_encoded_size!(Array<()>, None);
1263 assert_encoded_size!(Array<Uint<8>>, None);
1264 assert_encoded_size!(Array<Bytes>, None);
1265
1266 assert_encoded_size!(FixedArray<(), 0>, Some(0));
1267 assert_encoded_size!(FixedArray<(), 1>, Some(0));
1268 assert_encoded_size!(FixedArray<(), 2>, Some(0));
1269 assert_encoded_size!(FixedArray<Uint<8>, 0>, Some(0));
1270 assert_encoded_size!(FixedArray<Uint<8>, 1>, Some(32));
1271 assert_encoded_size!(FixedArray<Uint<8>, 2>, Some(64));
1272 assert_encoded_size!(FixedArray<Bytes, 0>, None);
1273 assert_encoded_size!(FixedArray<Bytes, 1>, None);
1274 assert_encoded_size!(FixedArray<Bytes, 2>, None);
1275
1276 assert_encoded_size!((), Some(0));
1277 assert_encoded_size!(((),), Some(0));
1278 assert_encoded_size!(((), ()), Some(0));
1279 assert_encoded_size!((Uint<8>,), Some(32));
1280 assert_encoded_size!((Uint<8>, Bool), Some(64));
1281 assert_encoded_size!((Uint<8>, Bool, FixedArray<Address, 4>), Some(6 * 32));
1282 assert_encoded_size!((Bytes,), None);
1283 assert_encoded_size!((Uint<8>, Bytes), None);
1284 }
1285
1286 #[test]
1287 fn udvt_encoded_sizes() {
1288 macro_rules! udvt_and_assert {
1289 ([$($t:tt)*], $e:expr) => {{
1290 type Alias = sol!($($t)*);
1291 sol!(type Udvt is $($t)*;);
1292 assert_encoded_size!(Alias, $e);
1293 assert_encoded_size!(Udvt, $e);
1294 }};
1295 }
1296 udvt_and_assert!([bool], Some(32));
1297
1298 udvt_and_assert!([uint8], Some(32));
1299 udvt_and_assert!([int8], Some(32));
1300 udvt_and_assert!([uint16], Some(32));
1301 udvt_and_assert!([int16], Some(32));
1302 udvt_and_assert!([uint32], Some(32));
1303 udvt_and_assert!([int32], Some(32));
1304 udvt_and_assert!([uint64], Some(32));
1305 udvt_and_assert!([int64], Some(32));
1306 udvt_and_assert!([uint128], Some(32));
1307 udvt_and_assert!([int128], Some(32));
1308 udvt_and_assert!([uint256], Some(32));
1309 udvt_and_assert!([int256], Some(32));
1310
1311 udvt_and_assert!([address], Some(32));
1312 udvt_and_assert!([function()], Some(32));
1313 udvt_and_assert!([bytes1], Some(32));
1314 udvt_and_assert!([bytes16], Some(32));
1315 udvt_and_assert!([bytes32], Some(32));
1316 }
1317
1318 #[test]
1319 fn custom_encoded_sizes() {
1320 macro_rules! custom_and_assert {
1321 ($block:tt, $e:expr) => {{
1322 sol! {
1323 struct Struct $block
1324 }
1325 assert_encoded_size!(Struct, $e);
1326 }};
1327 }
1328 custom_and_assert!({ bool a; }, Some(32));
1329 custom_and_assert!({ bool a; address b; }, Some(64));
1330 custom_and_assert!({ bool a; bytes1[69] b; uint8 c; }, Some(71 * 32));
1331 custom_and_assert!({ bytes a; }, None);
1332 custom_and_assert!({ bytes a; bytes24 b; }, None);
1333 custom_and_assert!({ bool a; bytes2[42] b; uint8 c; bytes d; }, None);
1334 }
1335
1336 #[test]
1337 fn tuple_of_refs() {
1338 let a = (1u8,);
1339 let b = (&1u8,);
1340
1341 type MyTy = (Uint<8>,);
1342
1343 MyTy::tokenize(&a);
1344 MyTy::tokenize(&b);
1345 }
1346
1347 macro_rules! roundtrip {
1348 ($($name:ident($st:ty : $t:ty);)+) => {
1349 proptest::proptest! {$(
1350 #[test]
1351 #[cfg_attr(miri, ignore = "doesn't run in isolation and would take too long")]
1352 fn $name(i: $t) {
1353 let token = <$st>::tokenize(&i);
1354 proptest::prop_assert_eq!(token.total_words() * 32, <$st>::abi_encoded_size(&i));
1355 proptest::prop_assert_eq!(<$st>::detokenize(token), i);
1356 }
1357 )+}
1358 };
1359 }
1360
1361 roundtrip! {
1362 roundtrip_address(Address: RustAddress);
1363 roundtrip_bool(Bool: bool);
1364 roundtrip_bytes(Bytes: Vec<u8>);
1365 roundtrip_string(String: RustString);
1366 roundtrip_fixed_bytes_16(FixedBytes<16>: [u8; 16]);
1367 roundtrip_fixed_bytes_32(FixedBytes<32>: [u8; 32]);
1368
1369 roundtrip_u8(Uint<8>: u8);
1371 roundtrip_i8(Int<8>: i8);
1372 roundtrip_u16(Uint<16>: u16);
1373 roundtrip_i16(Int<16>: i16);
1374 roundtrip_u32(Uint<32>: u32);
1375 roundtrip_i32(Int<32>: i32);
1376 roundtrip_u64(Uint<64>: u64);
1377 roundtrip_i64(Int<64>: i64);
1378 roundtrip_u128(Uint<128>: u128);
1379 roundtrip_i128(Int<128>: i128);
1380 roundtrip_u256(Uint<256>: U256);
1381 roundtrip_i256(Int<256>: I256);
1382 }
1383
1384 #[test]
1385 fn tokenize_uint() {
1386 macro_rules! test {
1387 ($($n:literal: $x:expr => $l:literal),+ $(,)?) => {$(
1388 let uint = <Uint<$n> as SolType>::RustType::try_from($x).unwrap();
1389 let int = <Int<$n> as SolType>::RustType::try_from(uint).unwrap();
1390
1391 assert_eq!(
1392 <Uint<$n>>::tokenize(&uint),
1393 WordToken::new(alloy_primitives::hex!($l))
1394 );
1395 assert_eq!(
1396 <Int<$n>>::tokenize(&int),
1397 WordToken::new(alloy_primitives::hex!($l))
1398 );
1399 )+};
1400 }
1401
1402 let word = core::array::from_fn::<_, 32, _>(|i| i as u8 + 1);
1403
1404 test! {
1405 8: 0x00u8 => "0000000000000000000000000000000000000000000000000000000000000000",
1406 8: 0x01u8 => "0000000000000000000000000000000000000000000000000000000000000001",
1407 24: 0x00020304u32 => "0000000000000000000000000000000000000000000000000000000000020304",
1408 32: 0x01020304u32 => "0000000000000000000000000000000000000000000000000000000001020304",
1409 56: 0x0002030405060708u64 => "0000000000000000000000000000000000000000000000000002030405060708",
1410 64: 0x0102030405060708u64 => "0000000000000000000000000000000000000000000000000102030405060708",
1411
1412 160: U160::from_be_slice(&word[32 - 160/8..]) => "0000000000000000000000000d0e0f101112131415161718191a1b1c1d1e1f20",
1413 200: U200::from_be_slice(&word[32 - 200/8..]) => "0000000000000008090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20",
1414 256: U256::from_be_slice(&word[32 - 256/8..]) => "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20",
1415 }
1416 }
1417
1418 #[test]
1419 fn detokenize_ints() {
1420 let word = core::array::from_fn(|i| i as u8 + 1);
1435 let token = WordToken::new(word);
1436 macro_rules! test {
1437 ($($n:literal => $x:expr),+ $(,)?) => {$(
1438 assert_eq!(<Uint<$n>>::detokenize(token), $x);
1439 assert_eq!(<Int<$n>>::detokenize(token), $x);
1440 )+};
1441 }
1442 #[rustfmt::skip]
1443 test! {
1444 8 => 0x0000000000000000000000000000000000000000000000000000000000000020,
1445 16 => 0x0000000000000000000000000000000000000000000000000000000000001f20,
1446 24 => "0x00000000000000000000000000000000000000000000000000000000001e1f20".parse().unwrap(),
1447 32 => 0x000000000000000000000000000000000000000000000000000000001d1e1f20,
1448 40 => "0x0000000000000000000000000000000000000000000000000000001c1d1e1f20".parse().unwrap(),
1449 48 => "0x00000000000000000000000000000000000000000000000000001b1c1d1e1f20".parse().unwrap(),
1450 56 => "0x000000000000000000000000000000000000000000000000001a1b1c1d1e1f20".parse().unwrap(),
1451 64 => 0x000000000000000000000000000000000000000000000000191a1b1c1d1e1f20,
1452 72 => "0x000000000000000000000000000000000000000000000018191a1b1c1d1e1f20".parse().unwrap(),
1453 80 => "0x000000000000000000000000000000000000000000001718191a1b1c1d1e1f20".parse().unwrap(),
1454 88 => "0x000000000000000000000000000000000000000000161718191a1b1c1d1e1f20".parse().unwrap(),
1455 96 => "0x000000000000000000000000000000000000000015161718191a1b1c1d1e1f20".parse().unwrap(),
1456 104 => "0x000000000000000000000000000000000000001415161718191a1b1c1d1e1f20".parse().unwrap(),
1457 112 => "0x000000000000000000000000000000000000131415161718191a1b1c1d1e1f20".parse().unwrap(),
1458 120 => "0x000000000000000000000000000000000012131415161718191a1b1c1d1e1f20".parse().unwrap(),
1459 128 => 0x000000000000000000000000000000001112131415161718191a1b1c1d1e1f20,
1460 136 => "0x000000000000000000000000000000101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1461 144 => "0x00000000000000000000000000000f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1462 152 => "0x000000000000000000000000000e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1463 160 => "0x0000000000000000000000000d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1464 168 => "0x00000000000000000000000c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1465 176 => "0x000000000000000000000b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1466 184 => "0x0000000000000000000a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1467 192 => "0x0000000000000000090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1468 200 => "0x0000000000000008090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1469 208 => "0x0000000000000708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1470 216 => "0x0000000000060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1471 224 => "0x0000000005060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1472 232 => "0x0000000405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1473 240 => "0x0000030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1474 248 => "0x0002030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1475 256 => "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".parse().unwrap(),
1476 };
1477 }
1478
1479 #[test]
1480 fn detokenize_negative_int() {
1481 let word = [0xff; 32];
1482 let token = WordToken::new(word);
1483 assert_eq!(<Int<8>>::detokenize(token), -1);
1484 assert_eq!(<Int<16>>::detokenize(token), -1);
1485 assert_eq!(<Int<24>>::detokenize(token), Signed::MINUS_ONE);
1486 assert_eq!(<Int<32>>::detokenize(token), -1);
1487 assert_eq!(<Int<40>>::detokenize(token), Signed::MINUS_ONE);
1488 assert_eq!(<Int<48>>::detokenize(token), Signed::MINUS_ONE);
1489 assert_eq!(<Int<56>>::detokenize(token), Signed::MINUS_ONE);
1490 assert_eq!(<Int<64>>::detokenize(token), -1);
1491 assert_eq!(<Int<72>>::detokenize(token), Signed::MINUS_ONE);
1492 assert_eq!(<Int<80>>::detokenize(token), Signed::MINUS_ONE);
1493 assert_eq!(<Int<88>>::detokenize(token), Signed::MINUS_ONE);
1494 assert_eq!(<Int<96>>::detokenize(token), Signed::MINUS_ONE);
1495 assert_eq!(<Int<104>>::detokenize(token), Signed::MINUS_ONE);
1496 assert_eq!(<Int<112>>::detokenize(token), Signed::MINUS_ONE);
1497 assert_eq!(<Int<120>>::detokenize(token), Signed::MINUS_ONE);
1498 assert_eq!(<Int<128>>::detokenize(token), -1);
1499 assert_eq!(<Int<136>>::detokenize(token), Signed::MINUS_ONE);
1500 assert_eq!(<Int<144>>::detokenize(token), Signed::MINUS_ONE);
1501 assert_eq!(<Int<152>>::detokenize(token), Signed::MINUS_ONE);
1502 assert_eq!(<Int<160>>::detokenize(token), Signed::MINUS_ONE);
1503 assert_eq!(<Int<168>>::detokenize(token), Signed::MINUS_ONE);
1504 assert_eq!(<Int<176>>::detokenize(token), Signed::MINUS_ONE);
1505 assert_eq!(<Int<184>>::detokenize(token), Signed::MINUS_ONE);
1506 assert_eq!(<Int<192>>::detokenize(token), Signed::MINUS_ONE);
1507 assert_eq!(<Int<200>>::detokenize(token), Signed::MINUS_ONE);
1508 assert_eq!(<Int<208>>::detokenize(token), Signed::MINUS_ONE);
1509 assert_eq!(<Int<216>>::detokenize(token), Signed::MINUS_ONE);
1510 assert_eq!(<Int<224>>::detokenize(token), Signed::MINUS_ONE);
1511 assert_eq!(<Int<232>>::detokenize(token), Signed::MINUS_ONE);
1512 assert_eq!(<Int<240>>::detokenize(token), Signed::MINUS_ONE);
1513 assert_eq!(<Int<248>>::detokenize(token), Signed::MINUS_ONE);
1514 assert_eq!(<Int<256>>::detokenize(token), Signed::MINUS_ONE);
1515 }
1516
1517 #[test]
1518 #[rustfmt::skip]
1519 fn detokenize_int() {
1520 use alloy_primitives::Uint;
1521
1522 let word =
1523 core::array::from_fn(|i| (i | (0x80 * (i % 2 == 1) as usize)) as u8 + 1);
1524 let token = WordToken::new(word);
1525 trait Conv<const BITS: usize, const LIMBS: usize> {
1526 fn as_uint_as_int(&self) -> Signed<BITS, LIMBS>;
1527 }
1528 impl<const BITS: usize, const LIMBS: usize> Conv<BITS, LIMBS> for str {
1529 fn as_uint_as_int(&self) -> Signed<BITS, LIMBS> {
1530 Signed::<BITS, LIMBS>::from_raw(self.parse::<Uint<BITS, LIMBS>>().unwrap())
1531 }
1532 }
1533 assert_eq!(<Int<8>>::detokenize(token), 0x00000000000000000000000000000000000000000000000000000000000000a0_u8 as i8);
1534 assert_eq!(<Int<16>>::detokenize(token), 0x0000000000000000000000000000000000000000000000000000000000001fa0_u16 as i16);
1535 assert_eq!(<Int<24>>::detokenize(token), "0x00000000000000000000000000000000000000000000000000000000009e1fa0".as_uint_as_int());
1536 assert_eq!(<Int<32>>::detokenize(token), 0x000000000000000000000000000000000000000000000000000000001d9e1fa0_u32 as i32);
1537 assert_eq!(<Int<40>>::detokenize(token), "0x0000000000000000000000000000000000000000000000000000009c1d9e1fa0".as_uint_as_int());
1538 assert_eq!(<Int<48>>::detokenize(token), "0x00000000000000000000000000000000000000000000000000001b9c1d9e1fa0".as_uint_as_int());
1539 assert_eq!(<Int<56>>::detokenize(token), "0x000000000000000000000000000000000000000000000000009a1b9c1d9e1fa0".as_uint_as_int());
1540 assert_eq!(<Int<64>>::detokenize(token), 0x000000000000000000000000000000000000000000000000199a1b9c1d9e1fa0_u64 as i64);
1541 assert_eq!(<Int<72>>::detokenize(token), "0x000000000000000000000000000000000000000000000098199a1b9c1d9e1fa0".as_uint_as_int());
1542 assert_eq!(<Int<80>>::detokenize(token), "0x000000000000000000000000000000000000000000001798199a1b9c1d9e1fa0".as_uint_as_int());
1543 assert_eq!(<Int<88>>::detokenize(token), "0x000000000000000000000000000000000000000000961798199a1b9c1d9e1fa0".as_uint_as_int());
1544 assert_eq!(<Int<96>>::detokenize(token), "0x000000000000000000000000000000000000000015961798199a1b9c1d9e1fa0".as_uint_as_int());
1545 assert_eq!(<Int<104>>::detokenize(token), "0x000000000000000000000000000000000000009415961798199a1b9c1d9e1fa0".as_uint_as_int());
1546 assert_eq!(<Int<112>>::detokenize(token), "0x000000000000000000000000000000000000139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1547 assert_eq!(<Int<120>>::detokenize(token), "0x000000000000000000000000000000000092139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1548 assert_eq!(<Int<128>>::detokenize(token), 0x000000000000000000000000000000001192139415961798199a1b9c1d9e1fa0_u128 as i128);
1549 assert_eq!(<Int<136>>::detokenize(token), "0x000000000000000000000000000000901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1550 assert_eq!(<Int<144>>::detokenize(token), "0x00000000000000000000000000000f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1551 assert_eq!(<Int<152>>::detokenize(token), "0x000000000000000000000000008e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1552 assert_eq!(<Int<160>>::detokenize(token), "0x0000000000000000000000000d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1553 assert_eq!(<Int<168>>::detokenize(token), "0x00000000000000000000008c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1554 assert_eq!(<Int<176>>::detokenize(token), "0x000000000000000000000b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1555 assert_eq!(<Int<184>>::detokenize(token), "0x0000000000000000008a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1556 assert_eq!(<Int<192>>::detokenize(token), "0x0000000000000000098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1557 assert_eq!(<Int<200>>::detokenize(token), "0x0000000000000088098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1558 assert_eq!(<Int<208>>::detokenize(token), "0x0000000000000788098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1559 assert_eq!(<Int<216>>::detokenize(token), "0x0000000000860788098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1560 assert_eq!(<Int<224>>::detokenize(token), "0x0000000005860788098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1561 assert_eq!(<Int<232>>::detokenize(token), "0x0000008405860788098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1562 assert_eq!(<Int<240>>::detokenize(token), "0x0000038405860788098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1563 assert_eq!(<Int<248>>::detokenize(token), "0x0082038405860788098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1564 assert_eq!(<Int<256>>::detokenize(token), "0x0182038405860788098a0b8c0d8e0f901192139415961798199a1b9c1d9e1fa0".as_uint_as_int());
1565 }
1566
1567 #[test]
1568 fn encode_packed() {
1569 use alloy_primitives::Uint;
1570
1571 let value = (
1572 RustAddress::with_last_byte(1),
1573 Uint::<160, 3>::from(2),
1574 Uint::from(3u32),
1575 Signed::unchecked_from(-3i32),
1576 3u32,
1577 -3i32,
1578 );
1579
1580 let res_ty =
1581 <sol! { (address, uint160, uint24, int24, uint32, int32) }>::abi_encode_packed(&value);
1582 let res_value = value.abi_encode_packed();
1583 let expected = hex!(
1584 "0000000000000000000000000000000000000001"
1585 "0000000000000000000000000000000000000002"
1586 "000003"
1587 "fffffd"
1588 "00000003"
1589 "fffffffd"
1590 );
1591 assert_eq!(hex::encode(res_ty), hex::encode(expected));
1592 assert_eq!(hex::encode(res_value), hex::encode(expected));
1593 }
1594}