alloy_dyn_abi/dynamic/
ty.rs

1use crate::{DynSolValue, DynToken, Error, Result, SolType, Specifier, Word};
2use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
3use alloy_primitives::{
4    try_vec,
5    utils::{box_try_new, vec_try_with_capacity},
6};
7use alloy_sol_types::{abi::Decoder, sol_data};
8use core::{fmt, iter::zip, num::NonZeroUsize, str::FromStr};
9use parser::TypeSpecifier;
10
11#[cfg(feature = "eip712")]
12macro_rules! as_tuple {
13    ($ty:ident $t:tt) => {
14        $ty::Tuple($t) | $ty::CustomStruct { tuple: $t, .. }
15    };
16}
17#[cfg(not(feature = "eip712"))]
18macro_rules! as_tuple {
19    ($ty:ident $t:tt) => {
20        $ty::Tuple($t)
21    };
22}
23pub(crate) use as_tuple;
24
25/// A dynamic Solidity type.
26///
27/// Equivalent to an enum wrapper around all implementers of [`SolType`].
28///
29/// This is used to represent Solidity types that are not known at compile time.
30/// It is used in conjunction with [`DynToken`] and [`DynSolValue`] to allow for
31/// dynamic ABI encoding and decoding.
32///
33/// # Examples
34///
35/// Parsing Solidity type strings:
36///
37/// ```
38/// use alloy_dyn_abi::DynSolType;
39///
40/// let type_name = "(bool,address)[]";
41/// let ty = DynSolType::parse(type_name)?;
42/// assert_eq!(
43///     ty,
44///     DynSolType::Array(Box::new(DynSolType::Tuple(
45///         vec![DynSolType::Bool, DynSolType::Address,]
46///     )))
47/// );
48/// assert_eq!(ty.sol_type_name(), type_name);
49///
50/// // alternatively, you can use the FromStr impl
51/// let ty2 = type_name.parse::<DynSolType>()?;
52/// assert_eq!(ty, ty2);
53/// # Ok::<_, alloy_dyn_abi::Error>(())
54/// ```
55///
56/// Decoding dynamic types:
57///
58/// ```
59/// use alloy_dyn_abi::{DynSolType, DynSolValue};
60/// use alloy_primitives::U256;
61///
62/// let my_type = DynSolType::Uint(256);
63/// let my_data: DynSolValue = U256::from(183u64).into();
64///
65/// let encoded = my_data.abi_encode();
66/// let decoded = my_type.abi_decode(&encoded)?;
67///
68/// assert_eq!(decoded, my_data);
69///
70/// let my_type = DynSolType::Array(Box::new(my_type));
71/// let my_data = DynSolValue::Array(vec![my_data.clone()]);
72///
73/// let encoded = my_data.abi_encode();
74/// let decoded = my_type.abi_decode(&encoded)?;
75///
76/// assert_eq!(decoded, my_data);
77/// # Ok::<_, alloy_dyn_abi::Error>(())
78/// ```
79#[derive(Clone, Debug, PartialEq, Eq, Hash)]
80pub enum DynSolType {
81    /// Boolean.
82    Bool,
83    /// Signed Integer.
84    Int(usize),
85    /// Unsigned Integer.
86    Uint(usize),
87    /// Fixed-size bytes, up to 32.
88    FixedBytes(usize),
89    /// Address.
90    Address,
91    /// Function.
92    Function,
93
94    /// Dynamic bytes.
95    Bytes,
96    /// String.
97    String,
98
99    /// Dynamically sized array.
100    Array(Box<DynSolType>),
101    /// Fixed-sized array.
102    FixedArray(Box<DynSolType>, usize),
103    /// Tuple.
104    Tuple(Vec<DynSolType>),
105
106    /// User-defined struct.
107    #[cfg(feature = "eip712")]
108    CustomStruct {
109        /// Name of the struct.
110        name: String,
111        /// Prop names.
112        prop_names: Vec<String>,
113        /// Inner types.
114        tuple: Vec<DynSolType>,
115    },
116}
117
118impl fmt::Display for DynSolType {
119    #[inline]
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        f.write_str(&self.sol_type_name())
122    }
123}
124
125impl FromStr for DynSolType {
126    type Err = Error;
127
128    #[inline]
129    fn from_str(s: &str) -> Result<Self, Self::Err> {
130        Self::parse(s)
131    }
132}
133
134impl DynSolType {
135    /// Parses a Solidity type name string into a [`DynSolType`].
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// # use alloy_dyn_abi::DynSolType;
141    /// let type_name = "uint256";
142    /// let ty = DynSolType::parse(type_name)?;
143    /// assert_eq!(ty, DynSolType::Uint(256));
144    /// assert_eq!(ty.sol_type_name(), type_name);
145    /// assert_eq!(ty.to_string(), type_name);
146    ///
147    /// // alternatively, you can use the FromStr impl
148    /// let ty2 = type_name.parse::<DynSolType>()?;
149    /// assert_eq!(ty2, ty);
150    /// # Ok::<_, alloy_dyn_abi::Error>(())
151    /// ```
152    #[inline]
153    pub fn parse(s: &str) -> Result<Self> {
154        TypeSpecifier::parse(s).map_err(Error::TypeParser).and_then(|t| t.resolve())
155    }
156
157    /// Calculate the nesting depth of this type. Simple types have a nesting
158    /// depth of 0, while all other types have a nesting depth of at least 1.
159    pub fn nesting_depth(&self) -> usize {
160        match self {
161            Self::Bool
162            | Self::Int(_)
163            | Self::Uint(_)
164            | Self::FixedBytes(_)
165            | Self::Address
166            | Self::Function
167            | Self::Bytes
168            | Self::String => 0,
169            Self::Array(contents) | Self::FixedArray(contents, _) => 1 + contents.nesting_depth(),
170            as_tuple!(Self tuple) => 1 + tuple.iter().map(Self::nesting_depth).max().unwrap_or(0),
171        }
172    }
173
174    /// Fallible cast to the contents of a variant.
175    #[inline]
176    pub fn as_tuple(&self) -> Option<&[Self]> {
177        match self {
178            Self::Tuple(t) => Some(t),
179            _ => None,
180        }
181    }
182
183    /// Fallible cast to the contents of a variant.
184    #[inline]
185    #[allow(clippy::missing_const_for_fn)]
186    pub fn as_custom_struct(&self) -> Option<(&str, &[String], &[Self])> {
187        match self {
188            #[cfg(feature = "eip712")]
189            Self::CustomStruct { name, prop_names, tuple } => Some((name, prop_names, tuple)),
190            _ => None,
191        }
192    }
193
194    /// Returns whether this type is contains a custom struct.
195    #[inline]
196    #[allow(clippy::missing_const_for_fn)]
197    pub fn has_custom_struct(&self) -> bool {
198        #[cfg(feature = "eip712")]
199        {
200            match self {
201                Self::CustomStruct { .. } => true,
202                Self::Array(t) => t.has_custom_struct(),
203                Self::FixedArray(t, _) => t.has_custom_struct(),
204                Self::Tuple(t) => t.iter().any(Self::has_custom_struct),
205                _ => false,
206            }
207        }
208        #[cfg(not(feature = "eip712"))]
209        {
210            false
211        }
212    }
213
214    /// Check that the given [`DynSolValue`]s match these types.
215    ///
216    /// See [`matches`](Self::matches) for more information.
217    #[inline]
218    pub fn matches_many(types: &[Self], values: &[DynSolValue]) -> bool {
219        types.len() == values.len() && zip(types, values).all(|(t, v)| t.matches(v))
220    }
221
222    /// Check that the given [`DynSolValue`] matches this type.
223    ///
224    /// Note: this will not check any names, but just the types; e.g for
225    /// `CustomStruct`, when the "eip712" feature is enabled, this will only
226    /// check equality between the lengths and types of the tuple.
227    pub fn matches(&self, value: &DynSolValue) -> bool {
228        match self {
229            Self::Bool => matches!(value, DynSolValue::Bool(_)),
230            Self::Int(size) => matches!(value, DynSolValue::Int(_, s) if s == size),
231            Self::Uint(size) => matches!(value, DynSolValue::Uint(_, s) if s == size),
232            Self::FixedBytes(size) => matches!(value, DynSolValue::FixedBytes(_, s) if s == size),
233            Self::Address => matches!(value, DynSolValue::Address(_)),
234            Self::Function => matches!(value, DynSolValue::Function(_)),
235            Self::Bytes => matches!(value, DynSolValue::Bytes(_)),
236            Self::String => matches!(value, DynSolValue::String(_)),
237            Self::Array(t) => {
238                matches!(value, DynSolValue::Array(v) if v.iter().all(|v| t.matches(v)))
239            }
240            Self::FixedArray(t, size) => matches!(
241                value,
242                DynSolValue::FixedArray(v) if v.len() == *size && v.iter().all(|v| t.matches(v))
243            ),
244            Self::Tuple(types) => {
245                matches!(value, as_tuple!(DynSolValue tuple) if zip(types, tuple).all(|(t, v)| t.matches(v)))
246            }
247            #[cfg(feature = "eip712")]
248            Self::CustomStruct { name: _, prop_names, tuple } => {
249                if let DynSolValue::CustomStruct { name: _, prop_names: p, tuple: t } = value {
250                    // check just types
251                    prop_names.len() == tuple.len()
252                        && prop_names.len() == p.len()
253                        && tuple.len() == t.len()
254                        && zip(tuple, t).all(|(a, b)| a.matches(b))
255                } else if let DynSolValue::Tuple(v) = value {
256                    zip(v, tuple).all(|(v, t)| t.matches(v))
257                } else {
258                    false
259                }
260            }
261        }
262    }
263
264    /// Dynamic detokenization.
265    // This should not fail when using a token created by `Self::empty_dyn_token`.
266    #[allow(clippy::unnecessary_to_owned)] // https://github.com/rust-lang/rust-clippy/issues/8148
267    pub fn detokenize(&self, token: DynToken<'_>) -> Result<DynSolValue> {
268        match (self, token) {
269            (Self::Bool, DynToken::Word(word)) => {
270                Ok(DynSolValue::Bool(sol_data::Bool::detokenize(word.into())))
271            }
272
273            // cheating here, but it's ok
274            (Self::Int(size), DynToken::Word(word)) => {
275                Ok(DynSolValue::Int(sol_data::Int::<256>::detokenize(word.into()), *size))
276            }
277
278            (Self::Uint(size), DynToken::Word(word)) => {
279                Ok(DynSolValue::Uint(sol_data::Uint::<256>::detokenize(word.into()), *size))
280            }
281
282            (Self::FixedBytes(size), DynToken::Word(word)) => Ok(DynSolValue::FixedBytes(
283                sol_data::FixedBytes::<32>::detokenize(word.into()),
284                *size,
285            )),
286
287            (Self::Address, DynToken::Word(word)) => {
288                Ok(DynSolValue::Address(sol_data::Address::detokenize(word.into())))
289            }
290
291            (Self::Function, DynToken::Word(word)) => {
292                Ok(DynSolValue::Function(sol_data::Function::detokenize(word.into())))
293            }
294
295            (Self::Bytes, DynToken::PackedSeq(buf)) => Ok(DynSolValue::Bytes(buf.to_vec())),
296
297            (Self::String, DynToken::PackedSeq(buf)) => {
298                Ok(DynSolValue::String(sol_data::String::detokenize(buf.into())))
299            }
300
301            (Self::Array(t), DynToken::DynSeq { contents, .. }) => {
302                t.detokenize_array(contents.into_owned()).map(DynSolValue::Array)
303            }
304
305            (Self::FixedArray(t, size), DynToken::FixedSeq(tokens, _)) => {
306                if *size != tokens.len() {
307                    return Err(crate::Error::custom(
308                        "array length mismatch on dynamic detokenization",
309                    ));
310                }
311                t.detokenize_array(tokens.into_owned()).map(DynSolValue::FixedArray)
312            }
313
314            (Self::Tuple(types), DynToken::FixedSeq(tokens, _)) => {
315                if types.len() != tokens.len() {
316                    return Err(crate::Error::custom(
317                        "tuple length mismatch on dynamic detokenization",
318                    ));
319                }
320                Self::detokenize_many(types, tokens.into_owned()).map(DynSolValue::Tuple)
321            }
322
323            #[cfg(feature = "eip712")]
324            (Self::CustomStruct { name, tuple, prop_names }, DynToken::FixedSeq(tokens, len)) => {
325                if len != tokens.len() || len != tuple.len() {
326                    return Err(crate::Error::custom(
327                        "custom length mismatch on dynamic detokenization",
328                    ));
329                }
330                Self::detokenize_many(tuple, tokens.into_owned()).map(|tuple| {
331                    DynSolValue::CustomStruct {
332                        name: name.clone(),
333                        prop_names: prop_names.clone(),
334                        tuple,
335                    }
336                })
337            }
338
339            _ => Err(crate::Error::custom("mismatched types on dynamic detokenization")),
340        }
341    }
342
343    fn detokenize_array(&self, tokens: Vec<DynToken<'_>>) -> Result<Vec<DynSolValue>> {
344        let mut values = vec_try_with_capacity(tokens.len())?;
345        for token in tokens {
346            values.push(self.detokenize(token)?);
347        }
348        Ok(values)
349    }
350
351    fn detokenize_many(types: &[Self], tokens: Vec<DynToken<'_>>) -> Result<Vec<DynSolValue>> {
352        assert_eq!(types.len(), tokens.len());
353        let mut values = vec_try_with_capacity(tokens.len())?;
354        for (ty, token) in zip(types, tokens) {
355            values.push(ty.detokenize(token)?);
356        }
357        Ok(values)
358    }
359
360    #[inline]
361    #[allow(clippy::missing_const_for_fn)]
362    fn sol_type_name_simple(&self) -> Option<&'static str> {
363        match self {
364            Self::Address => Some("address"),
365            Self::Function => Some("function"),
366            Self::Bool => Some("bool"),
367            Self::Bytes => Some("bytes"),
368            Self::String => Some("string"),
369            _ => None,
370        }
371    }
372
373    #[inline]
374    fn sol_type_name_raw(&self, out: &mut String) {
375        match self {
376            Self::Address | Self::Function | Self::Bool | Self::Bytes | Self::String => {
377                out.push_str(unsafe { self.sol_type_name_simple().unwrap_unchecked() });
378            }
379
380            Self::FixedBytes(size) | Self::Int(size) | Self::Uint(size) => {
381                let prefix = match self {
382                    Self::FixedBytes(..) => "bytes",
383                    Self::Int(..) => "int",
384                    Self::Uint(..) => "uint",
385                    _ => unreachable!(),
386                };
387                out.push_str(prefix);
388                out.push_str(itoa::Buffer::new().format(*size));
389            }
390
391            as_tuple!(Self tuple) => {
392                out.push('(');
393                for (i, val) in tuple.iter().enumerate() {
394                    if i > 0 {
395                        out.push(',');
396                    }
397                    val.sol_type_name_raw(out);
398                }
399                if tuple.len() == 1 {
400                    out.push(',');
401                }
402                out.push(')');
403            }
404            Self::Array(t) => {
405                t.sol_type_name_raw(out);
406                out.push_str("[]");
407            }
408            Self::FixedArray(t, len) => {
409                t.sol_type_name_raw(out);
410                out.push('[');
411                out.push_str(itoa::Buffer::new().format(*len));
412                out.push(']');
413            }
414        }
415    }
416
417    /// Returns an estimate of the number of bytes needed to format this type.
418    ///
419    /// This calculation is meant to be an upper bound for valid types to avoid
420    /// a second allocation in `sol_type_name_raw` and thus is almost never
421    /// going to be exact.
422    fn sol_type_name_capacity(&self) -> usize {
423        match self {
424            | Self::Address // 7
425            | Self::Function // 8
426            | Self::Bool // 4
427            | Self::Bytes // 5
428            | Self::String // 6
429            | Self::FixedBytes(_) // 5 + 2
430            | Self::Int(_) // 3 + 3
431            | Self::Uint(_) // 4 + 3
432            => 8,
433
434            | Self::Array(t) // t + 2
435            | Self::FixedArray(t, _) // t + 2 + log10(len)
436            => t.sol_type_name_capacity() + 8,
437
438            as_tuple!(Self tuple) // sum(tuple) + len(tuple) + 2
439            => tuple.iter().map(Self::sol_type_name_capacity).sum::<usize>() + 8,
440        }
441    }
442
443    /// The Solidity type name. This returns the Solidity type corresponding to
444    /// this value, if it is known. A type will not be known if the value
445    /// contains an empty sequence, e.g. `T[0]`.
446    pub fn sol_type_name(&self) -> Cow<'static, str> {
447        if let Some(s) = self.sol_type_name_simple() {
448            Cow::Borrowed(s)
449        } else {
450            let mut s = String::with_capacity(self.sol_type_name_capacity());
451            self.sol_type_name_raw(&mut s);
452            Cow::Owned(s)
453        }
454    }
455
456    /// The Solidity type name, as a `String`.
457    ///
458    /// Note: this shadows the inherent [`ToString`] implementation, derived
459    /// from [`fmt::Display`], for performance reasons.
460    #[inline]
461    #[allow(clippy::inherent_to_string_shadow_display)]
462    pub fn to_string(&self) -> String {
463        self.sol_type_name().into_owned()
464    }
465
466    /// Instantiate an empty dyn token, to be decoded into.
467    ///
468    /// ## Warning
469    ///
470    /// This function may allocate an unbounded amount of memory based on user
471    /// input types. It must be used with care to avoid DOS issues.
472    fn empty_dyn_token<'a>(&self) -> Result<DynToken<'a>> {
473        Ok(match self {
474            Self::Address
475            | Self::Function
476            | Self::Bool
477            | Self::FixedBytes(_)
478            | Self::Int(_)
479            | Self::Uint(_) => DynToken::Word(Word::ZERO),
480
481            Self::Bytes | Self::String => DynToken::PackedSeq(&[]),
482
483            Self::Array(t) => DynToken::DynSeq {
484                contents: Default::default(),
485                template: Some(box_try_new(t.empty_dyn_token()?)?),
486            },
487            &Self::FixedArray(ref t, size) => {
488                DynToken::FixedSeq(try_vec![t.empty_dyn_token()?; size]?.into(), size)
489            }
490            as_tuple!(Self tuple) => {
491                let mut tokens = vec_try_with_capacity(tuple.len())?;
492                for ty in tuple {
493                    tokens.push(ty.empty_dyn_token()?);
494                }
495                DynToken::FixedSeq(tokens.into(), tuple.len())
496            }
497        })
498    }
499
500    /// Decode an event topic into a [`DynSolValue`].
501    pub(crate) fn decode_event_topic(&self, topic: Word) -> DynSolValue {
502        match self {
503            Self::Address
504            | Self::Function
505            | Self::Bool
506            | Self::FixedBytes(_)
507            | Self::Int(_)
508            | Self::Uint(_) => self.detokenize(DynToken::Word(topic)).unwrap(),
509            _ => DynSolValue::FixedBytes(topic, 32),
510        }
511    }
512
513    /// Decode a [`DynSolValue`] from a byte slice. Fails if the value does not
514    /// match this type.
515    ///
516    /// This method is used for decoding single values. It assumes the `data`
517    /// argument is an encoded single-element sequence wrapping the `self` type.
518    #[inline]
519    #[cfg_attr(debug_assertions, track_caller)]
520    pub fn abi_decode(&self, data: &[u8]) -> Result<DynSolValue> {
521        self.abi_decode_inner(&mut Decoder::new(data), DynToken::decode_single_populate)
522    }
523
524    /// Decode a [`DynSolValue`] from a byte slice. Fails if the value does not
525    /// match this type.
526    ///
527    /// This method is used for decoding function arguments. It tries to
528    /// determine whether the user intended to decode a sequence or an
529    /// individual value. If the `self` type is a tuple, the `data` will be
530    /// decoded as a sequence, otherwise it will be decoded as a single value.
531    ///
532    /// # Examples
533    ///
534    /// ```solidity
535    /// // This function takes a single simple param:
536    /// // DynSolType::Uint(256).decode_params(data)
537    /// function myFunc(uint256 a) public;
538    ///
539    /// // This function takes 2 params:
540    /// // DynSolType::Tuple(vec![DynSolType::Uint(256), DynSolType::Bool])
541    /// //     .decode_params(data)
542    /// function myFunc(uint256 b, bool c) public;
543    /// ```
544    #[inline]
545    #[cfg_attr(debug_assertions, track_caller)]
546    pub fn abi_decode_params(&self, data: &[u8]) -> Result<DynSolValue> {
547        match self {
548            Self::Tuple(_) => self.abi_decode_sequence(data),
549            _ => self.abi_decode(data),
550        }
551    }
552
553    /// Decode a [`DynSolValue`] from a byte slice. Fails if the value does not
554    /// match this type.
555    #[inline]
556    #[cfg_attr(debug_assertions, track_caller)]
557    pub fn abi_decode_sequence(&self, data: &[u8]) -> Result<DynSolValue> {
558        self.abi_decode_inner(&mut Decoder::new(data), DynToken::decode_sequence_populate)
559    }
560
561    /// Returns `true` if this type is dynamically sized type.
562    pub fn is_dynamic(&self) -> bool {
563        match self {
564            Self::Address
565            | Self::Function
566            | Self::Bool
567            | Self::Uint(..)
568            | Self::Int(..)
569            | Self::FixedBytes(..) => false,
570            Self::Bytes | Self::String | Self::Array(_) => true,
571            Self::Tuple(tuple) => tuple.iter().any(Self::is_dynamic),
572            Self::FixedArray(inner, _) => inner.is_dynamic(),
573            #[cfg(feature = "eip712")]
574            Self::CustomStruct { tuple, .. } => tuple.iter().any(Self::is_dynamic),
575        }
576    }
577
578    /// Calculate the minimum number of ABI words necessary to encode this
579    /// type.
580    pub fn minimum_words(&self) -> usize {
581        match self {
582            // word types are always 1
583            Self::Bool |
584            Self::Int(_) |
585            Self::Uint(_) |
586            Self::FixedBytes(_) |
587            Self::Address |
588            Self::Function |
589            // packed/dynamic seq types may be empty
590            Self::Bytes |
591            Self::String |
592            Self::Array(_) => 1,
593            // fixed-seq types are the sum of their components
594            Self::FixedArray(v, size) => size * v.minimum_words(),
595            Self::Tuple(tuple) => tuple.iter().map(|ty| ty.minimum_words()).sum(),
596            #[cfg(feature = "eip712")]
597            Self::CustomStruct { tuple, ..} => tuple.iter().map(|ty| ty.minimum_words()).sum(),
598        }
599    }
600
601    #[inline]
602    #[cfg_attr(debug_assertions, track_caller)]
603    pub(crate) fn abi_decode_inner<'d, F>(
604        &self,
605        decoder: &mut Decoder<'d>,
606        f: F,
607    ) -> Result<DynSolValue>
608    where
609        F: FnOnce(&mut DynToken<'d>, &mut Decoder<'d>) -> Result<()>,
610    {
611        if self.is_zst() {
612            return Ok(self.zero_sized_value().expect("checked"));
613        }
614
615        if decoder.remaining_words() < self.minimum_words() {
616            return Err(Error::SolTypes(alloy_sol_types::Error::Overrun));
617        }
618
619        let mut token = self.empty_dyn_token()?;
620        f(&mut token, decoder)?;
621        let value = self.detokenize(token).expect("invalid empty_dyn_token");
622        debug_assert!(
623            self.matches(&value),
624            "decoded value does not match type:\n  type: {self:?}\n value: {value:?}"
625        );
626        Ok(value)
627    }
628
629    /// Wrap in an array of the specified size
630    #[inline]
631    pub(crate) fn array_wrap(self, size: Option<NonZeroUsize>) -> Self {
632        match size {
633            Some(size) => Self::FixedArray(Box::new(self), size.get()),
634            None => Self::Array(Box::new(self)),
635        }
636    }
637
638    /// Iteratively wrap in arrays.
639    #[inline]
640    pub(crate) fn array_wrap_from_iter(
641        self,
642        iter: impl IntoIterator<Item = Option<NonZeroUsize>>,
643    ) -> Self {
644        iter.into_iter().fold(self, Self::array_wrap)
645    }
646
647    /// Return true if the type is zero-sized, e.g. `()` or `T[0]`
648    #[inline]
649    pub fn is_zst(&self) -> bool {
650        match self {
651            Self::Array(inner) => inner.is_zst(),
652            Self::FixedArray(inner, size) => *size == 0 || inner.is_zst(),
653            Self::Tuple(inner) => inner.is_empty() || inner.iter().all(|t| t.is_zst()),
654            _ => false,
655        }
656    }
657
658    #[inline]
659    const fn zero_sized_value(&self) -> Option<DynSolValue> {
660        match self {
661            Self::Array(_) => Some(DynSolValue::Array(vec![])),
662            Self::FixedArray(_, _) => Some(DynSolValue::FixedArray(vec![])),
663            Self::Tuple(_) => Some(DynSolValue::Tuple(vec![])),
664            _ => None,
665        }
666    }
667}
668
669#[cfg(test)]
670mod tests {
671    use super::*;
672    use alloc::string::ToString;
673    use alloy_primitives::{Address, hex};
674
675    #[test]
676    fn dynamically_encodes() {
677        let word1 =
678            "0000000000000000000000000101010101010101010101010101010101010101".parse().unwrap();
679        let word2 =
680            "0000000000000000000000000202020202020202020202020202020202020202".parse().unwrap();
681
682        let val = DynSolValue::Address(Address::repeat_byte(0x01));
683        let token = val.tokenize();
684        assert_eq!(token, DynToken::from(word1));
685
686        let val = DynSolValue::FixedArray(vec![
687            Address::repeat_byte(0x01).into(),
688            Address::repeat_byte(0x02).into(),
689        ]);
690
691        let token = val.tokenize();
692        assert_eq!(
693            token,
694            DynToken::FixedSeq(vec![DynToken::Word(word1), DynToken::Word(word2)].into(), 2)
695        );
696        let mut enc = crate::Encoder::default();
697        DynSolValue::encode_seq_to(val.as_fixed_seq().unwrap(), &mut enc);
698        assert_eq!(enc.finish(), vec![word1, word2]);
699    }
700
701    // also tests the type name parser
702    macro_rules! encoder_tests {
703        ($($name:ident($ty:literal, $encoded:literal)),* $(,)?) => {$(
704            #[test]
705            fn $name() {
706                encoder_test($ty, &hex!($encoded));
707            }
708        )*};
709    }
710
711    fn encoder_test(s: &str, encoded: &[u8]) {
712        let ty: DynSolType = s.parse().expect("parsing failed");
713        assert_eq!(ty.sol_type_name(), s, "type names are not the same");
714
715        let value = ty.abi_decode_params(encoded).expect("decoding failed");
716        if let Some(value_name) = value.sol_type_name() {
717            assert_eq!(value_name, s, "value names are not the same");
718        }
719
720        // Tuples are treated as top-level lists. So if we encounter a
721        // dynamic tuple, the total length of the encoded data will include
722        // the offset, but the encoding/decoding process will not. To
723        // account for this, we add 32 bytes to the expected length when
724        // the type is a dynamic tuple.
725        let mut len = encoded.len();
726        if value.as_tuple().is_some() && value.is_dynamic() {
727            len += 32;
728        }
729        assert_eq!(value.total_words() * 32, len, "dyn_tuple={}", len != encoded.len());
730
731        let re_encoded = value.abi_encode_params();
732        assert!(
733            re_encoded == encoded,
734            "
735  type: {ty}
736 value: {value:?}
737re-enc: {re_enc}
738   enc: {encoded}",
739            re_enc = hex::encode(re_encoded),
740            encoded = hex::encode(encoded),
741        );
742    }
743
744    encoder_tests! {
745        address("address", "0000000000000000000000001111111111111111111111111111111111111111"),
746
747        dynamic_array_of_addresses("address[]", "
748            0000000000000000000000000000000000000000000000000000000000000020
749            0000000000000000000000000000000000000000000000000000000000000002
750            0000000000000000000000001111111111111111111111111111111111111111
751            0000000000000000000000002222222222222222222222222222222222222222
752        "),
753
754        fixed_array_of_addresses("address[2]", "
755            0000000000000000000000001111111111111111111111111111111111111111
756            0000000000000000000000002222222222222222222222222222222222222222
757        "),
758
759        two_addresses("(address,address)", "
760            0000000000000000000000001111111111111111111111111111111111111111
761            0000000000000000000000002222222222222222222222222222222222222222
762        "),
763
764        fixed_array_of_dynamic_arrays_of_addresses("address[][2]", "
765            0000000000000000000000000000000000000000000000000000000000000020
766            0000000000000000000000000000000000000000000000000000000000000040
767            00000000000000000000000000000000000000000000000000000000000000a0
768            0000000000000000000000000000000000000000000000000000000000000002
769            0000000000000000000000001111111111111111111111111111111111111111
770            0000000000000000000000002222222222222222222222222222222222222222
771            0000000000000000000000000000000000000000000000000000000000000002
772            0000000000000000000000003333333333333333333333333333333333333333
773            0000000000000000000000004444444444444444444444444444444444444444
774        "),
775
776        dynamic_array_of_fixed_arrays_of_addresses("address[2][]", "
777            0000000000000000000000000000000000000000000000000000000000000020
778            0000000000000000000000000000000000000000000000000000000000000002
779            0000000000000000000000001111111111111111111111111111111111111111
780            0000000000000000000000002222222222222222222222222222222222222222
781            0000000000000000000000003333333333333333333333333333333333333333
782            0000000000000000000000004444444444444444444444444444444444444444
783        "),
784
785        dynamic_array_of_dynamic_arrays("address[][]", "
786            0000000000000000000000000000000000000000000000000000000000000020
787            0000000000000000000000000000000000000000000000000000000000000002
788            0000000000000000000000000000000000000000000000000000000000000040
789            0000000000000000000000000000000000000000000000000000000000000080
790            0000000000000000000000000000000000000000000000000000000000000001
791            0000000000000000000000001111111111111111111111111111111111111111
792            0000000000000000000000000000000000000000000000000000000000000001
793            0000000000000000000000002222222222222222222222222222222222222222
794        "),
795
796        dynamic_array_of_dynamic_arrays2("address[][]", "
797            0000000000000000000000000000000000000000000000000000000000000020
798            0000000000000000000000000000000000000000000000000000000000000002
799            0000000000000000000000000000000000000000000000000000000000000040
800            00000000000000000000000000000000000000000000000000000000000000a0
801            0000000000000000000000000000000000000000000000000000000000000002
802            0000000000000000000000001111111111111111111111111111111111111111
803            0000000000000000000000002222222222222222222222222222222222222222
804            0000000000000000000000000000000000000000000000000000000000000002
805            0000000000000000000000003333333333333333333333333333333333333333
806            0000000000000000000000004444444444444444444444444444444444444444
807        "),
808
809        fixed_array_of_fixed_arrays("address[2][2]", "
810            0000000000000000000000001111111111111111111111111111111111111111
811            0000000000000000000000002222222222222222222222222222222222222222
812            0000000000000000000000003333333333333333333333333333333333333333
813            0000000000000000000000004444444444444444444444444444444444444444
814        "),
815
816        fixed_array_of_static_tuples_followed_by_dynamic_type("((uint256,uint256,address)[2],string)", "
817            0000000000000000000000000000000000000000000000000000000005930cc5
818            0000000000000000000000000000000000000000000000000000000015002967
819            0000000000000000000000004444444444444444444444444444444444444444
820            000000000000000000000000000000000000000000000000000000000000307b
821            00000000000000000000000000000000000000000000000000000000000001c3
822            0000000000000000000000002222222222222222222222222222222222222222
823            00000000000000000000000000000000000000000000000000000000000000e0
824            0000000000000000000000000000000000000000000000000000000000000009
825            6761766f66796f726b0000000000000000000000000000000000000000000000
826        "),
827
828        empty_array("address[]", "
829            0000000000000000000000000000000000000000000000000000000000000020
830            0000000000000000000000000000000000000000000000000000000000000000
831        "),
832
833        empty_array_2("(address[],address[])", "
834            0000000000000000000000000000000000000000000000000000000000000040
835            0000000000000000000000000000000000000000000000000000000000000060
836            0000000000000000000000000000000000000000000000000000000000000000
837            0000000000000000000000000000000000000000000000000000000000000000
838        "),
839
840        // Nested empty arrays
841        empty_array_3("(address[][],address[][])", "
842            0000000000000000000000000000000000000000000000000000000000000040
843            00000000000000000000000000000000000000000000000000000000000000a0
844            0000000000000000000000000000000000000000000000000000000000000001
845            0000000000000000000000000000000000000000000000000000000000000020
846            0000000000000000000000000000000000000000000000000000000000000000
847            0000000000000000000000000000000000000000000000000000000000000001
848            0000000000000000000000000000000000000000000000000000000000000020
849            0000000000000000000000000000000000000000000000000000000000000000
850        "),
851
852        fixed_bytes("bytes2", "1234000000000000000000000000000000000000000000000000000000000000"),
853
854        string("string", "
855            0000000000000000000000000000000000000000000000000000000000000020
856            0000000000000000000000000000000000000000000000000000000000000009
857            6761766f66796f726b0000000000000000000000000000000000000000000000
858        "),
859
860        bytes("bytes", "
861            0000000000000000000000000000000000000000000000000000000000000020
862            0000000000000000000000000000000000000000000000000000000000000002
863            1234000000000000000000000000000000000000000000000000000000000000
864        "),
865
866        bytes_2("bytes", "
867            0000000000000000000000000000000000000000000000000000000000000020
868            000000000000000000000000000000000000000000000000000000000000001f
869            1000000000000000000000000000000000000000000000000000000000000200
870        "),
871
872        bytes_3("bytes", "
873            0000000000000000000000000000000000000000000000000000000000000020
874            0000000000000000000000000000000000000000000000000000000000000040
875            1000000000000000000000000000000000000000000000000000000000000000
876            1000000000000000000000000000000000000000000000000000000000000000
877        "),
878
879        two_bytes("(bytes,bytes)", "
880            0000000000000000000000000000000000000000000000000000000000000040
881            0000000000000000000000000000000000000000000000000000000000000080
882            000000000000000000000000000000000000000000000000000000000000001f
883            1000000000000000000000000000000000000000000000000000000000000200
884            0000000000000000000000000000000000000000000000000000000000000020
885            0010000000000000000000000000000000000000000000000000000000000002
886        "),
887
888        uint("uint256", "0000000000000000000000000000000000000000000000000000000000000004"),
889
890        int("int256", "0000000000000000000000000000000000000000000000000000000000000004"),
891
892        bool("bool", "0000000000000000000000000000000000000000000000000000000000000001"),
893
894        bool2("bool", "0000000000000000000000000000000000000000000000000000000000000000"),
895
896        comprehensive_test("(uint8,bytes,uint8,bytes)", "
897            0000000000000000000000000000000000000000000000000000000000000005
898            0000000000000000000000000000000000000000000000000000000000000080
899            0000000000000000000000000000000000000000000000000000000000000003
900            00000000000000000000000000000000000000000000000000000000000000e0
901            0000000000000000000000000000000000000000000000000000000000000040
902            131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
903            131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
904            0000000000000000000000000000000000000000000000000000000000000040
905            131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
906            131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
907        "),
908
909        comprehensive_test2("(bool,string,uint8,uint8,uint8,uint8[])", "
910            0000000000000000000000000000000000000000000000000000000000000001
911            00000000000000000000000000000000000000000000000000000000000000c0
912            0000000000000000000000000000000000000000000000000000000000000002
913            0000000000000000000000000000000000000000000000000000000000000003
914            0000000000000000000000000000000000000000000000000000000000000004
915            0000000000000000000000000000000000000000000000000000000000000100
916            0000000000000000000000000000000000000000000000000000000000000009
917            6761766f66796f726b0000000000000000000000000000000000000000000000
918            0000000000000000000000000000000000000000000000000000000000000003
919            0000000000000000000000000000000000000000000000000000000000000005
920            0000000000000000000000000000000000000000000000000000000000000006
921            0000000000000000000000000000000000000000000000000000000000000007
922        "),
923
924        dynamic_array_of_bytes("bytes[]", "
925            0000000000000000000000000000000000000000000000000000000000000020
926            0000000000000000000000000000000000000000000000000000000000000001
927            0000000000000000000000000000000000000000000000000000000000000020
928            0000000000000000000000000000000000000000000000000000000000000026
929            019c80031b20d5e69c8093a571162299032018d913930d93ab320ae5ea44a421
930            8a274f00d6070000000000000000000000000000000000000000000000000000
931        "),
932
933        dynamic_array_of_bytes2("bytes[]", "
934            0000000000000000000000000000000000000000000000000000000000000020
935            0000000000000000000000000000000000000000000000000000000000000002
936            0000000000000000000000000000000000000000000000000000000000000040
937            00000000000000000000000000000000000000000000000000000000000000a0
938            0000000000000000000000000000000000000000000000000000000000000026
939            4444444444444444444444444444444444444444444444444444444444444444
940            4444444444440000000000000000000000000000000000000000000000000000
941            0000000000000000000000000000000000000000000000000000000000000026
942            6666666666666666666666666666666666666666666666666666666666666666
943            6666666666660000000000000000000000000000000000000000000000000000
944        "),
945
946        static_tuple_of_addresses("(address,address)", "
947            0000000000000000000000001111111111111111111111111111111111111111
948            0000000000000000000000002222222222222222222222222222222222222222
949        "),
950
951        dynamic_tuple("((string,string),)", "
952            0000000000000000000000000000000000000000000000000000000000000020
953            0000000000000000000000000000000000000000000000000000000000000040
954            0000000000000000000000000000000000000000000000000000000000000080
955            0000000000000000000000000000000000000000000000000000000000000009
956            6761766f66796f726b0000000000000000000000000000000000000000000000
957            0000000000000000000000000000000000000000000000000000000000000009
958            6761766f66796f726b0000000000000000000000000000000000000000000000
959        "),
960
961        dynamic_tuple_of_bytes("((bytes,bytes),)", "
962            0000000000000000000000000000000000000000000000000000000000000020
963            0000000000000000000000000000000000000000000000000000000000000040
964            00000000000000000000000000000000000000000000000000000000000000a0
965            0000000000000000000000000000000000000000000000000000000000000026
966            4444444444444444444444444444444444444444444444444444444444444444
967            4444444444440000000000000000000000000000000000000000000000000000
968            0000000000000000000000000000000000000000000000000000000000000026
969            6666666666666666666666666666666666666666666666666666666666666666
970            6666666666660000000000000000000000000000000000000000000000000000
971        "),
972
973        complex_tuple("((uint256,string,address,address),)", "
974            0000000000000000000000000000000000000000000000000000000000000020
975            1111111111111111111111111111111111111111111111111111111111111111
976            0000000000000000000000000000000000000000000000000000000000000080
977            0000000000000000000000001111111111111111111111111111111111111111
978            0000000000000000000000002222222222222222222222222222222222222222
979            0000000000000000000000000000000000000000000000000000000000000009
980            6761766f66796f726b0000000000000000000000000000000000000000000000
981        "),
982
983        nested_tuple("((string,bool,string,(string,string,(string,string))),)", "
984            0000000000000000000000000000000000000000000000000000000000000020
985            0000000000000000000000000000000000000000000000000000000000000080
986            0000000000000000000000000000000000000000000000000000000000000001
987            00000000000000000000000000000000000000000000000000000000000000c0
988            0000000000000000000000000000000000000000000000000000000000000100
989            0000000000000000000000000000000000000000000000000000000000000004
990            7465737400000000000000000000000000000000000000000000000000000000
991            0000000000000000000000000000000000000000000000000000000000000006
992            6379626f72670000000000000000000000000000000000000000000000000000
993            0000000000000000000000000000000000000000000000000000000000000060
994            00000000000000000000000000000000000000000000000000000000000000a0
995            00000000000000000000000000000000000000000000000000000000000000e0
996            0000000000000000000000000000000000000000000000000000000000000005
997            6e69676874000000000000000000000000000000000000000000000000000000
998            0000000000000000000000000000000000000000000000000000000000000003
999            6461790000000000000000000000000000000000000000000000000000000000
1000            0000000000000000000000000000000000000000000000000000000000000040
1001            0000000000000000000000000000000000000000000000000000000000000080
1002            0000000000000000000000000000000000000000000000000000000000000004
1003            7765656500000000000000000000000000000000000000000000000000000000
1004            0000000000000000000000000000000000000000000000000000000000000008
1005            66756e7465737473000000000000000000000000000000000000000000000000
1006        "),
1007
1008        params_containing_dynamic_tuple("(address,(bool,string,string),address,address,bool)", "
1009            0000000000000000000000002222222222222222222222222222222222222222
1010            00000000000000000000000000000000000000000000000000000000000000a0
1011            0000000000000000000000003333333333333333333333333333333333333333
1012            0000000000000000000000004444444444444444444444444444444444444444
1013            0000000000000000000000000000000000000000000000000000000000000000
1014            0000000000000000000000000000000000000000000000000000000000000001
1015            0000000000000000000000000000000000000000000000000000000000000060
1016            00000000000000000000000000000000000000000000000000000000000000a0
1017            0000000000000000000000000000000000000000000000000000000000000009
1018            7370616365736869700000000000000000000000000000000000000000000000
1019            0000000000000000000000000000000000000000000000000000000000000006
1020            6379626f72670000000000000000000000000000000000000000000000000000
1021        "),
1022
1023        params_containing_static_tuple("(address,(address,bool,bool),address,address)", "
1024            0000000000000000000000001111111111111111111111111111111111111111
1025            0000000000000000000000002222222222222222222222222222222222222222
1026            0000000000000000000000000000000000000000000000000000000000000001
1027            0000000000000000000000000000000000000000000000000000000000000000
1028            0000000000000000000000003333333333333333333333333333333333333333
1029            0000000000000000000000004444444444444444444444444444444444444444
1030        "),
1031
1032        dynamic_tuple_with_nested_static_tuples("((((bool,uint16),),uint16[]),)", "
1033            0000000000000000000000000000000000000000000000000000000000000020
1034            0000000000000000000000000000000000000000000000000000000000000000
1035            0000000000000000000000000000000000000000000000000000000000000777
1036            0000000000000000000000000000000000000000000000000000000000000060
1037            0000000000000000000000000000000000000000000000000000000000000002
1038            0000000000000000000000000000000000000000000000000000000000000042
1039            0000000000000000000000000000000000000000000000000000000000001337
1040        "),
1041
1042        // https://github.com/foundry-rs/book/issues/1286
1043        tuple_array("((uint256,)[],uint256)", "
1044            0000000000000000000000000000000000000000000000000000000000000040
1045            000000000000000000000000000000000000000000000000000000000000007b
1046            0000000000000000000000000000000000000000000000000000000000000001
1047            0000000000000000000000000000000000000000000000000000000000000001
1048        "),
1049        nested_tuple_array("(((uint256,)[],uint256),)", "
1050            0000000000000000000000000000000000000000000000000000000000000020
1051            0000000000000000000000000000000000000000000000000000000000000040
1052            000000000000000000000000000000000000000000000000000000000000007b
1053            0000000000000000000000000000000000000000000000000000000000000001
1054            0000000000000000000000000000000000000000000000000000000000000001
1055        "),
1056    }
1057
1058    // https://github.com/alloy-rs/core/issues/392
1059    #[test]
1060    fn zst_dos() {
1061        let my_type: DynSolType = "()[]".parse().unwrap();
1062        let value = my_type.abi_decode(&hex!("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000FFFFFFFF"));
1063        assert_eq!(value, Ok(DynSolValue::Array(vec![])));
1064    }
1065
1066    #[test]
1067    #[cfg_attr(miri, ignore = "takes too long")]
1068    fn recursive_dos() {
1069        // https://github.com/alloy-rs/core/issues/490
1070        let payload = "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020";
1071
1072        // Used to eat 60 gb of memory and then crash.
1073        let my_type: DynSolType = "uint256[][][][][][][][][][]".parse().unwrap();
1074        let decoded = my_type.abi_decode(&hex::decode(payload).unwrap());
1075        assert_eq!(decoded, Err(alloy_sol_types::Error::RecursionLimitExceeded(16).into()));
1076
1077        // https://github.com/paulmillr/micro-eth-signer/discussions/20
1078        let payload = &"0000000000000000000000000000000000000000000000000000000000000020\
1079             000000000000000000000000000000000000000000000000000000000000000a\
1080             0000000000000000000000000000000000000000000000000000000000000020"
1081            .repeat(64);
1082        let my_type: DynSolType = "uint256[][][][][][][][][][]".parse().unwrap();
1083        let decoded = my_type.abi_decode(&hex::decode(payload).unwrap());
1084        assert_eq!(
1085            decoded,
1086            Err(alloy_sol_types::Error::TypeCheckFail {
1087                expected_type: "offset (usize)".into(),
1088                data: "0000000000000000000000000000000000000000000a00000000000000000000"
1089                    .to_string()
1090            }
1091            .into())
1092        );
1093
1094        let my_type: DynSolType = "bytes[][][][][][][][][][]".parse().unwrap();
1095        let decoded = my_type.abi_decode(&hex::decode(payload).unwrap());
1096        assert_eq!(
1097            decoded,
1098            Err(alloy_sol_types::Error::TypeCheckFail {
1099                expected_type: "offset (usize)".into(),
1100                data: "0000000000000000000000000000000000000000000a00000000000000000000"
1101                    .to_string()
1102            }
1103            .into())
1104        );
1105    }
1106
1107    // https://github.com/alloy-rs/core/issues/490
1108    #[test]
1109    fn large_dyn_array_dos() {
1110        let payload = "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000FFFFFFFF";
1111
1112        // Used to eat 60 gb of memory.
1113        let my_type: DynSolType = "uint32[1][]".parse().unwrap();
1114        let decoded = my_type.abi_decode(&hex::decode(payload).unwrap());
1115        assert_eq!(decoded, Err(alloy_sol_types::Error::Overrun.into()))
1116    }
1117
1118    #[test]
1119    fn fixed_array_dos() {
1120        let t = "uint32[9999999999]".parse::<DynSolType>().unwrap();
1121        let decoded = t.abi_decode(&[]);
1122        assert_eq!(decoded, Err(alloy_sol_types::Error::Overrun.into()))
1123    }
1124
1125    macro_rules! packed_tests {
1126        ($($name:ident($ty:literal, $v:literal, $encoded:literal)),* $(,)?) => {
1127            mod packed {
1128                use super::*;
1129
1130                $(
1131                    #[test]
1132                    fn $name() {
1133                        packed_test($ty, $v, &hex!($encoded));
1134                    }
1135                )*
1136            }
1137        };
1138    }
1139
1140    fn packed_test(t_s: &str, v_s: &str, expected: &[u8]) {
1141        let ty: DynSolType = t_s.parse().expect("parsing failed");
1142        assert_eq!(ty.sol_type_name(), t_s, "type names are not the same");
1143
1144        let value = match ty.coerce_str(v_s) {
1145            Ok(v) => v,
1146            Err(e) => {
1147                panic!("failed to coerce to a value: {e}");
1148            }
1149        };
1150        if let Some(value_name) = value.sol_type_name() {
1151            assert_eq!(value_name, t_s, "value names are not the same");
1152        }
1153
1154        let packed = value.abi_encode_packed();
1155        assert!(
1156            packed == expected,
1157            "
1158    type: {ty}
1159   value: {value:?}
1160  packed: {packed}
1161expected: {expected}",
1162            packed = hex::encode(packed),
1163            expected = hex::encode(expected),
1164        );
1165    }
1166
1167    packed_tests! {
1168        address("address", "1111111111111111111111111111111111111111", "1111111111111111111111111111111111111111"),
1169
1170        bool_false("bool", "false", "00"),
1171        bool_true("bool", "true", "01"),
1172
1173        int8_1("int8", "0", "00"),
1174        int8_2("int8", "1", "01"),
1175        int8_3("int8", "16", "10"),
1176        int8_4("int8", "127", "7f"),
1177        neg_int8_1("int8", "-1", "ff"),
1178        neg_int8_2("int8", "-16", "f0"),
1179        neg_int8_3("int8", "-127", "81"),
1180        neg_int8_4("int8", "-128", "80"),
1181
1182        int16_1("int16", "0", "0000"),
1183        int16_2("int16", "1", "0001"),
1184        int16_3("int16", "16", "0010"),
1185        int16_4("int16", "127", "007f"),
1186        int16_5("int16", "128", "0080"),
1187        int16_6("int16", "8192", "2000"),
1188        int16_7("int16", "32767", "7fff"),
1189        neg_int16_1("int16", "-1", "ffff"),
1190        neg_int16_2("int16", "-16", "fff0"),
1191        neg_int16_3("int16", "-127", "ff81"),
1192        neg_int16_4("int16", "-128", "ff80"),
1193        neg_int16_5("int16", "-129", "ff7f"),
1194        neg_int16_6("int16", "-32767", "8001"),
1195        neg_int16_7("int16", "-32768", "8000"),
1196
1197        int32_1("int32", "0", "00000000"),
1198        int32_2("int32", "-1", "ffffffff"),
1199        int64_1("int64", "0", "0000000000000000"),
1200        int64_2("int64", "-1", "ffffffffffffffff"),
1201        int128_1("int128", "0", "00000000000000000000000000000000"),
1202        int128_2("int128", "-1", "ffffffffffffffffffffffffffffffff"),
1203        int256_1("int256", "0", "0000000000000000000000000000000000000000000000000000000000000000"),
1204        int256_2("int256", "-1", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
1205
1206        uint8_1("uint8", "0", "00"),
1207        uint8_2("uint8", "1", "01"),
1208        uint8_3("uint8", "16", "10"),
1209        uint16("uint16", "0", "0000"),
1210        uint32("uint32", "0", "00000000"),
1211        uint64("uint64", "0", "0000000000000000"),
1212        uint128("uint128", "0", "00000000000000000000000000000000"),
1213        uint256_1("uint256", "0", "0000000000000000000000000000000000000000000000000000000000000000"),
1214        uint256_2("uint256", "42", "000000000000000000000000000000000000000000000000000000000000002a"),
1215        uint256_3("uint256", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
1216
1217        string_1("string", "a", "61"),
1218        string_2("string", "ab", "6162"),
1219        string_3("string", "abc", "616263"),
1220
1221        bytes_1("bytes", "00", "00"),
1222        bytes_2("bytes", "0001", "0001"),
1223        bytes_3("bytes", "000102", "000102"),
1224
1225        fbytes_1("bytes1", "00", "00"),
1226        fbytes_2("bytes2", "1234", "1234"),
1227        fbytes_3("(address,bytes20)", "(\
1228            1111111111111111111111111111111111111111,\
1229            2222222222222222222222222222222222222222\
1230        )", "
1231            1111111111111111111111111111111111111111
1232            2222222222222222222222222222222222222222
1233        "),
1234        fbytes_4("bytes20[]", "[\
1235            1111111111111111111111111111111111111111,\
1236            2222222222222222222222222222222222222222\
1237        ]", "
1238            0000000000000000000000001111111111111111111111111111111111111111
1239            0000000000000000000000002222222222222222222222222222222222222222
1240        "),
1241        fbytes_5("bytes20[2]", "[\
1242            1111111111111111111111111111111111111111,\
1243            2222222222222222222222222222222222222222\
1244        ]", "
1245            0000000000000000000000001111111111111111111111111111111111111111
1246            0000000000000000000000002222222222222222222222222222222222222222
1247        "),
1248
1249        dynamic_array_of_addresses("address[]", "[\
1250            1111111111111111111111111111111111111111,\
1251            2222222222222222222222222222222222222222\
1252        ]", "
1253            0000000000000000000000001111111111111111111111111111111111111111
1254            0000000000000000000000002222222222222222222222222222222222222222
1255        "),
1256
1257        fixed_array_of_addresses("address[2]", "[\
1258            1111111111111111111111111111111111111111,\
1259            2222222222222222222222222222222222222222\
1260        ]", "
1261            0000000000000000000000001111111111111111111111111111111111111111
1262            0000000000000000000000002222222222222222222222222222222222222222
1263        "),
1264
1265        two_addresses("(address,address)", "(\
1266            1111111111111111111111111111111111111111,\
1267            2222222222222222222222222222222222222222\
1268        )", "
1269            1111111111111111111111111111111111111111
1270            2222222222222222222222222222222222222222
1271        "),
1272
1273        fixed_array_of_dynamic_arrays_of_addresses("address[][2]", "[\
1274            [1111111111111111111111111111111111111111, 2222222222222222222222222222222222222222],\
1275            [3333333333333333333333333333333333333333, 4444444444444444444444444444444444444444]\
1276        ]", "
1277            0000000000000000000000001111111111111111111111111111111111111111
1278            0000000000000000000000002222222222222222222222222222222222222222
1279            0000000000000000000000003333333333333333333333333333333333333333
1280            0000000000000000000000004444444444444444444444444444444444444444
1281        "),
1282
1283        dynamic_array_of_fixed_arrays_of_addresses("address[2][]", "[\
1284            [1111111111111111111111111111111111111111, 2222222222222222222222222222222222222222],\
1285            [3333333333333333333333333333333333333333, 4444444444444444444444444444444444444444]\
1286        ]", "
1287            0000000000000000000000001111111111111111111111111111111111111111
1288            0000000000000000000000002222222222222222222222222222222222222222
1289            0000000000000000000000003333333333333333333333333333333333333333
1290            0000000000000000000000004444444444444444444444444444444444444444
1291        "),
1292
1293        dynamic_array_of_dynamic_arrays("address[][]", "[\
1294            [1111111111111111111111111111111111111111],\
1295            [2222222222222222222222222222222222222222]\
1296        ]", "
1297            0000000000000000000000001111111111111111111111111111111111111111
1298            0000000000000000000000002222222222222222222222222222222222222222
1299        "),
1300
1301        dynamic_array_of_dynamic_arrays2("address[][]", "[\
1302            [1111111111111111111111111111111111111111, 2222222222222222222222222222222222222222],\
1303            [3333333333333333333333333333333333333333, 4444444444444444444444444444444444444444]\
1304        ]", "
1305            0000000000000000000000001111111111111111111111111111111111111111
1306            0000000000000000000000002222222222222222222222222222222222222222
1307            0000000000000000000000003333333333333333333333333333333333333333
1308            0000000000000000000000004444444444444444444444444444444444444444
1309        "),
1310
1311        dynamic_array_of_dynamic_arrays3("uint32[][]", "[\
1312            [1, 2],\
1313            [3, 4]\
1314        ]", "
1315            0000000000000000000000000000000000000000000000000000000000000001
1316            0000000000000000000000000000000000000000000000000000000000000002
1317            0000000000000000000000000000000000000000000000000000000000000003
1318            0000000000000000000000000000000000000000000000000000000000000004
1319        "),
1320    }
1321}