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