alloy_dyn_abi/
coerce.rs

1use crate::{DynSolType, DynSolValue, Result, dynamic::ty::as_tuple};
2use alloc::vec::Vec;
3use alloy_primitives::{Address, Function, I256, Sign, U256, hex};
4use alloy_sol_types::Word;
5use core::fmt;
6use parser::{
7    Input, new_input,
8    utils::{array_parser, char_parser, spanned},
9};
10use winnow::{
11    ModalParser, ModalResult, Parser,
12    ascii::{alpha0, alpha1, digit1, hex_digit0, hex_digit1, space0},
13    combinator::{cut_err, dispatch, empty, fail, opt, preceded, trace},
14    error::{
15        AddContext, ContextError, ErrMode, FromExternalError, ParserError, StrContext,
16        StrContextValue,
17    },
18    stream::Stream,
19    token::take_while,
20};
21
22impl DynSolType {
23    /// Coerces a string into a [`DynSolValue`] via this type.
24    ///
25    /// # Syntax
26    ///
27    /// - [`Bool`](DynSolType::Bool): `true|false`
28    /// - [`Int`](DynSolType::Int): `[+-]?{Uint}`
29    /// - [`Uint`](DynSolType::Uint): `{literal}(\.[0-9]+)?(\s*{unit})?`
30    ///   - literal: base 2, 8, 10, or 16 integer literal. If not in base 10, must be prefixed with
31    ///     `0b`, `0o`, or `0x` respectively.
32    ///   - unit: same as [Solidity ether units](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#ether-units)
33    ///   - decimals with more digits than the unit's exponent value are not allowed
34    /// - [`FixedBytes`](DynSolType::FixedBytes): `(0x)?[0-9A-Fa-f]{$0*2}`
35    /// - [`Address`](DynSolType::Address): `(0x)?[0-9A-Fa-f]{40}`
36    /// - [`Function`](DynSolType::Function): `(0x)?[0-9A-Fa-f]{48}`
37    /// - [`Bytes`](DynSolType::Bytes): `(0x)?[0-9A-Fa-f]+`
38    /// - [`String`](DynSolType::String): `.*`
39    ///   - can be surrounded by a pair of `"` or `'`
40    ///   - trims whitespace if not surrounded
41    /// - [`Array`](DynSolType::Array): any number of the inner type delimited by commas (`,`) and
42    ///   surrounded by brackets (`[]`)
43    /// - [`FixedArray`](DynSolType::FixedArray): exactly the given number of the inner type
44    ///   delimited by commas (`,`) and surrounded by brackets (`[]`)
45    /// - [`Tuple`](DynSolType::Tuple): the inner types delimited by commas (`,`) and surrounded by
46    ///   parentheses (`()`)
47    #[cfg_attr(
48        feature = "eip712",
49        doc = "- [`CustomStruct`](DynSolType::CustomStruct): the same as `Tuple`"
50    )]
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// use alloy_dyn_abi::{DynSolType, DynSolValue};
56    /// use alloy_primitives::U256;
57    ///
58    /// let ty: DynSolType = "(uint256,string)[]".parse()?;
59    /// let value = ty.coerce_str("[(0, \"hello\"), (4.2e1, \"world\")]")?;
60    /// assert_eq!(
61    ///     value,
62    ///     DynSolValue::Array(vec![
63    ///         DynSolValue::Tuple(vec![
64    ///             DynSolValue::Uint(U256::from(0), 256),
65    ///             DynSolValue::String(String::from("hello"))
66    ///         ]),
67    ///         DynSolValue::Tuple(vec![
68    ///             DynSolValue::Uint(U256::from(42), 256),
69    ///             DynSolValue::String(String::from("world"))
70    ///         ]),
71    ///     ])
72    /// );
73    /// assert!(value.matches(&ty));
74    /// assert_eq!(value.as_type().unwrap(), ty);
75    /// # Ok::<_, alloy_dyn_abi::Error>(())
76    /// ```
77    #[doc(alias = "tokenize")] // from ethabi
78    pub fn coerce_str(&self, s: &str) -> Result<DynSolValue> {
79        ValueParser::new(self)
80            .parse(new_input(s))
81            .map_err(|e| crate::Error::TypeParser(parser::Error::parser(e)))
82    }
83}
84
85struct ValueParser<'a> {
86    ty: &'a DynSolType,
87    list_end: Option<char>,
88}
89
90impl<'i> Parser<Input<'i>, DynSolValue, ErrMode<ContextError>> for ValueParser<'_> {
91    fn parse_next(&mut self, input: &mut Input<'i>) -> ModalResult<DynSolValue, ContextError> {
92        #[cfg(feature = "debug")]
93        let name = self.ty.sol_type_name();
94        #[cfg(not(feature = "debug"))]
95        let name = "value_parser";
96        trace(name, move |input: &mut Input<'i>| match self.ty {
97            DynSolType::Bool => bool(input).map(DynSolValue::Bool),
98            &DynSolType::Int(size) => {
99                int(size).parse_next(input).map(|int| DynSolValue::Int(int, size))
100            }
101            &DynSolType::Uint(size) => {
102                uint(size).parse_next(input).map(|uint| DynSolValue::Uint(uint, size))
103            }
104            &DynSolType::FixedBytes(size) => {
105                fixed_bytes(size).parse_next(input).map(|word| DynSolValue::FixedBytes(word, size))
106            }
107            DynSolType::Address => address(input).map(DynSolValue::Address),
108            DynSolType::Function => function(input).map(DynSolValue::Function),
109            DynSolType::Bytes => bytes(input).map(DynSolValue::Bytes),
110            DynSolType::String => {
111                self.string().parse_next(input).map(|s| DynSolValue::String(s.into()))
112            }
113            DynSolType::Array(ty) => self.in_list(']', |this| {
114                this.with(ty).array().parse_next(input).map(DynSolValue::Array)
115            }),
116            DynSolType::FixedArray(ty, len) => self.in_list(']', |this| {
117                this.with(ty).fixed_array(*len).parse_next(input).map(DynSolValue::FixedArray)
118            }),
119            as_tuple!(DynSolType tys) => {
120                self.in_list(')', |this| this.tuple(tys).parse_next(input).map(DynSolValue::Tuple))
121            }
122        })
123        .parse_next(input)
124    }
125}
126
127impl<'a> ValueParser<'a> {
128    #[inline]
129    const fn new(ty: &'a DynSolType) -> Self {
130        Self { list_end: None, ty }
131    }
132
133    #[inline]
134    fn in_list<F: FnOnce(&mut Self) -> R, R>(&mut self, list_end: char, f: F) -> R {
135        let prev = self.list_end.replace(list_end);
136        let r = f(self);
137        self.list_end = prev;
138        r
139    }
140
141    #[inline]
142    const fn with(&self, ty: &'a DynSolType) -> Self {
143        Self { list_end: self.list_end, ty }
144    }
145
146    #[inline]
147    fn string<'s, 'i: 's>(&'s self) -> impl ModalParser<Input<'i>, &'i str, ContextError> + 's {
148        trace("string", |input: &mut Input<'i>| {
149            let Some(delim) = input.chars().next() else {
150                return Ok("");
151            };
152            let has_delim = matches!(delim, '"' | '\'');
153            if has_delim {
154                let _ = input.next_token();
155            }
156
157            // TODO: escapes?
158            let mut s = if has_delim || self.list_end.is_some() {
159                let (chs, l) = if has_delim {
160                    ([delim, '\0'], 1)
161                } else if let Some(c) = self.list_end {
162                    ([',', c], 2)
163                } else {
164                    unreachable!()
165                };
166                let min = if has_delim { 0 } else { 1 };
167                take_while(min.., move |c: char| !unsafe { chs.get_unchecked(..l) }.contains(&c))
168                    .parse_next(input)?
169            } else {
170                input.next_slice(input.len())
171            };
172
173            if has_delim {
174                cut_err(char_parser(delim))
175                    .context(StrContext::Label("string"))
176                    .parse_next(input)?;
177            } else {
178                s = s.trim_end();
179            }
180
181            Ok(s)
182        })
183    }
184
185    #[inline]
186    fn array<'i: 'a>(self) -> impl ModalParser<Input<'i>, Vec<DynSolValue>, ContextError> + 'a {
187        #[cfg(feature = "debug")]
188        let name = format!("{}[]", self.ty);
189        #[cfg(not(feature = "debug"))]
190        let name = "array";
191        trace(name, array_parser(self))
192    }
193
194    #[inline]
195    fn fixed_array<'i: 'a>(
196        self,
197        len: usize,
198    ) -> impl ModalParser<Input<'i>, Vec<DynSolValue>, ContextError> + 'a {
199        #[cfg(feature = "debug")]
200        let name = format!("{}[{len}]", self.ty);
201        #[cfg(not(feature = "debug"))]
202        let name = "fixed_array";
203        trace(
204            name,
205            array_parser(self).try_map(move |values: Vec<DynSolValue>| {
206                if values.len() == len {
207                    Ok(values)
208                } else {
209                    Err(Error::FixedArrayLengthMismatch(len, values.len()))
210                }
211            }),
212        )
213    }
214
215    #[inline]
216    #[allow(clippy::ptr_arg)]
217    fn tuple<'i: 's, 't: 's, 's>(
218        &'s self,
219        tuple: &'t Vec<DynSolType>,
220    ) -> impl ModalParser<Input<'i>, Vec<DynSolValue>, ContextError> + 's {
221        #[cfg(feature = "debug")]
222        let name = DynSolType::Tuple(tuple.clone()).to_string();
223        #[cfg(not(feature = "debug"))]
224        let name = "tuple";
225        trace(name, move |input: &mut Input<'i>| {
226            space0(input)?;
227            char_parser('(').parse_next(input)?;
228
229            let mut values = Vec::with_capacity(tuple.len());
230            for (i, ty) in tuple.iter().enumerate() {
231                if i > 0 {
232                    space0(input)?;
233                    char_parser(',').parse_next(input)?;
234                }
235                space0(input)?;
236                values.push(self.with(ty).parse_next(input)?);
237            }
238
239            space0(input)?;
240            char_parser(')').parse_next(input)?;
241
242            Ok(values)
243        })
244    }
245}
246
247#[derive(Debug)]
248enum Error {
249    IntOverflow,
250    FractionalNotAllowed(U256),
251    NegativeUnits,
252    TooManyDecimals(usize, usize),
253    InvalidFixedBytesLength(usize),
254    FixedArrayLengthMismatch(usize, usize),
255    EmptyHexStringWithoutPrefix,
256}
257
258impl core::error::Error for Error {}
259
260impl fmt::Display for Error {
261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262        match self {
263            Self::IntOverflow => f.write_str("number too large to fit in target type"),
264            Self::TooManyDecimals(expected, actual) => {
265                write!(f, "expected at most {expected} decimals, got {actual}")
266            }
267            Self::FractionalNotAllowed(n) => write!(f, "non-zero fraction .{n} not allowed"),
268            Self::NegativeUnits => f.write_str("negative units not allowed"),
269            Self::InvalidFixedBytesLength(len) => {
270                write!(f, "fixed bytes length {len} greater than 32")
271            }
272            Self::FixedArrayLengthMismatch(expected, actual) => {
273                write!(f, "fixed array length mismatch: expected {expected} elements, got {actual}")
274            }
275            Self::EmptyHexStringWithoutPrefix => {
276                f.write_str("expected hex digits or the `0x` prefix for an empty hex string")
277            }
278        }
279    }
280}
281
282#[inline]
283fn bool(input: &mut Input<'_>) -> ModalResult<bool> {
284    trace(
285        "bool",
286        dispatch! {alpha1.context(StrContext::Label("boolean"));
287            "true" => empty.value(true),
288            "false" => empty.value(false),
289            _ => fail
290        }
291        .context(StrContext::Label("boolean")),
292    )
293    .parse_next(input)
294}
295
296#[inline]
297fn int<'i>(size: usize) -> impl ModalParser<Input<'i>, I256, ContextError> {
298    #[cfg(feature = "debug")]
299    let name = format!("int{size}");
300    #[cfg(not(feature = "debug"))]
301    let name = "int";
302    trace(
303        name,
304        (int_sign, uint(size)).try_map(move |(sign, abs)| {
305            if !sign.is_negative() && abs.bit_len() > size - 1 {
306                return Err(Error::IntOverflow);
307            }
308            I256::checked_from_sign_and_abs(sign, abs).ok_or(Error::IntOverflow)
309        }),
310    )
311}
312
313#[inline]
314fn int_sign(input: &mut Input<'_>) -> ModalResult<Sign> {
315    trace("int_sign", |input: &mut Input<'_>| match input.as_bytes().first() {
316        Some(b'+') => {
317            let _ = input.next_slice(1);
318            Ok(Sign::Positive)
319        }
320        Some(b'-') => {
321            let _ = input.next_slice(1);
322            Ok(Sign::Negative)
323        }
324        Some(_) | None => Ok(Sign::Positive),
325    })
326    .parse_next(input)
327}
328
329#[inline]
330fn uint<'i>(len: usize) -> impl ModalParser<Input<'i>, U256, ContextError> {
331    #[cfg(feature = "debug")]
332    let name = format!("uint{len}");
333    #[cfg(not(feature = "debug"))]
334    let name = "uint";
335    trace(name, move |input: &mut Input<'_>| {
336        let intpart = prefixed_int(input)?;
337        let fract =
338            opt(preceded(
339                '.',
340                cut_err(digit1.context(StrContext::Expected(StrContextValue::Description(
341                    "at least one digit",
342                )))),
343            ))
344            .parse_next(input)?;
345
346        let intpart =
347            intpart.parse::<U256>().map_err(|e| ErrMode::from_external_error(input, e))?;
348        let e = opt(scientific_notation).parse_next(input)?.unwrap_or(0);
349
350        let _ = space0(input)?;
351        let units = int_units(input)?;
352
353        let units = units as isize + e;
354        if units < 0 {
355            return Err(ErrMode::from_external_error(input, Error::NegativeUnits));
356        }
357        let units = units as usize;
358
359        let uint = if let Some(fract) = fract {
360            let fract_uint = U256::from_str_radix(fract, 10)
361                .map_err(|e| ErrMode::from_external_error(input, e))?;
362
363            if units == 0 && !fract_uint.is_zero() {
364                return Err(ErrMode::from_external_error(
365                    input,
366                    Error::FractionalNotAllowed(fract_uint),
367                ));
368            }
369
370            if fract.len() > units {
371                return Err(ErrMode::from_external_error(
372                    input,
373                    Error::TooManyDecimals(units, fract.len()),
374                ));
375            }
376
377            // (intpart * 10^fract.len() + fract) * 10^(units-fract.len())
378            (|| -> Option<U256> {
379                let extension = U256::from(10u64).checked_pow(U256::from(fract.len()))?;
380                let extended = intpart.checked_mul(extension)?;
381                let uint = fract_uint.checked_add(extended)?;
382                let units = U256::from(10u64).checked_pow(U256::from(units - fract.len()))?;
383                uint.checked_mul(units)
384            })()
385        } else if units > 0 {
386            // intpart * 10^units
387            (|| -> Option<U256> {
388                let units = U256::from(10u64).checked_pow(U256::from(units))?;
389                intpart.checked_mul(units)
390            })()
391        } else {
392            Some(intpart)
393        }
394        .ok_or_else(|| ErrMode::from_external_error(input, Error::IntOverflow))?;
395
396        if uint.bit_len() > len {
397            return Err(ErrMode::from_external_error(input, Error::IntOverflow));
398        }
399
400        Ok(uint)
401    })
402}
403
404#[inline]
405fn prefixed_int<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
406    trace(
407        "prefixed_int",
408        spanned(|input: &mut Input<'i>| {
409            let has_prefix =
410                matches!(input.get(..2), Some("0b" | "0B" | "0o" | "0O" | "0x" | "0X"));
411            let checkpoint = input.checkpoint();
412            if has_prefix {
413                let _ = input.next_slice(2);
414                // parse hex since it's the most general
415                hex_digit1(input)
416            } else {
417                digit1(input)
418            }
419            .map_err(|e: ErrMode<_>| {
420                e.add_context(
421                    input,
422                    &checkpoint,
423                    StrContext::Expected(StrContextValue::Description("at least one digit")),
424                )
425            })
426        }),
427    )
428    .parse_next(input)
429    .map(|(s, _)| s)
430}
431
432#[inline]
433fn int_units(input: &mut Input<'_>) -> ModalResult<usize> {
434    trace(
435        "int_units",
436        dispatch! {alpha0;
437            "ether" => empty.value(18),
438            "gwei" | "nano" | "nanoether" => empty.value(9),
439            "" | "wei" => empty.value(0),
440            _ => fail,
441        },
442    )
443    .parse_next(input)
444}
445
446#[inline]
447fn scientific_notation(input: &mut Input<'_>) -> ModalResult<isize> {
448    // Check if we have 'e' or 'E' followed by an optional sign and digits
449    if !matches!(input.chars().next(), Some('e' | 'E')) {
450        return Err(ErrMode::from_input(input));
451    }
452    let _ = input.next_token();
453    winnow::ascii::dec_int(input)
454}
455
456#[inline]
457fn fixed_bytes<'i>(len: usize) -> impl ModalParser<Input<'i>, Word, ContextError> {
458    #[cfg(feature = "debug")]
459    let name = format!("bytes{len}");
460    #[cfg(not(feature = "debug"))]
461    let name = "bytesN";
462    trace(name, move |input: &mut Input<'_>| {
463        if len > Word::len_bytes() {
464            return Err(
465                ErrMode::from_external_error(input, Error::InvalidFixedBytesLength(len)).cut()
466            );
467        }
468
469        let hex = hex_str(input)?;
470        let mut out = Word::ZERO;
471        match hex::decode_to_slice(hex, &mut out[..len]) {
472            Ok(()) => Ok(out),
473            Err(e) => Err(ErrMode::from_external_error(input, e).cut()),
474        }
475    })
476}
477
478#[inline]
479fn address(input: &mut Input<'_>) -> ModalResult<Address> {
480    trace("address", hex_str.try_map(hex::FromHex::from_hex)).parse_next(input)
481}
482
483#[inline]
484fn function(input: &mut Input<'_>) -> ModalResult<Function> {
485    trace("function", hex_str.try_map(hex::FromHex::from_hex)).parse_next(input)
486}
487
488#[inline]
489fn bytes(input: &mut Input<'_>) -> ModalResult<Vec<u8>> {
490    trace("bytes", hex_str.try_map(hex::decode)).parse_next(input)
491}
492
493#[inline]
494fn hex_str<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
495    trace("hex_str", |input: &mut Input<'i>| {
496        // Allow empty `bytes` only with a prefix.
497        let has_prefix = opt("0x").parse_next(input)?.is_some();
498        let s = hex_digit0(input)?;
499        if !has_prefix && s.is_empty() {
500            return Err(ErrMode::from_external_error(input, Error::EmptyHexStringWithoutPrefix));
501        }
502        Ok(s)
503    })
504    .parse_next(input)
505}
506
507#[cfg(test)]
508mod tests {
509    use super::*;
510    use alloc::{
511        boxed::Box,
512        string::{String, ToString},
513    };
514    use alloy_primitives::address;
515    use core::str::FromStr;
516
517    fn uint_test(s: &str, expected: Result<&str, ()>) {
518        for (ty, negate) in [
519            (DynSolType::Uint(256), false),
520            (DynSolType::Int(256), false),
521            (DynSolType::Int(256), true),
522        ] {
523            let s = if negate { &format!("-{s}") } else { s };
524            let expected = if negate {
525                expected.map(|s| format!("-{s}"))
526            } else {
527                expected.map(|s| s.to_string())
528            };
529            let d = format!("{s:?} as {ty:?}");
530
531            let actual = ty.coerce_str(s);
532            match (actual, expected) {
533                (Ok(actual), Ok(expected)) => match (actual, ty) {
534                    (DynSolValue::Uint(v, 256), DynSolType::Uint(256)) => {
535                        assert_eq!(v, expected.parse::<U256>().unwrap(), "{d}");
536                    }
537                    (DynSolValue::Int(v, 256), DynSolType::Int(256)) => {
538                        assert_eq!(v, expected.parse::<I256>().unwrap(), "{d}");
539                    }
540                    (actual, _) => panic!("{d}: unexpected value: {actual:?}"),
541                },
542                (Err(_), Err(())) => {}
543                (Ok(actual), Err(_)) => panic!("{d}: expected failure, got {actual:?}"),
544                (Err(e), Ok(_)) => panic!("{d}: {e:?}"),
545            }
546        }
547    }
548
549    #[track_caller]
550    fn assert_error_contains(e: &impl core::fmt::Display, s: &str) {
551        if cfg!(feature = "std") {
552            let es = e.to_string();
553            assert!(es.contains(s), "{s:?} not in {es:?}");
554        }
555    }
556
557    #[test]
558    fn coerce_bool() {
559        assert_eq!(DynSolType::Bool.coerce_str("true").unwrap(), DynSolValue::Bool(true));
560        assert_eq!(DynSolType::Bool.coerce_str("false").unwrap(), DynSolValue::Bool(false));
561
562        assert!(DynSolType::Bool.coerce_str("").is_err());
563        assert!(DynSolType::Bool.coerce_str("0").is_err());
564        assert!(DynSolType::Bool.coerce_str("1").is_err());
565        assert!(DynSolType::Bool.coerce_str("tru").is_err());
566    }
567
568    #[test]
569    fn coerce_int() {
570        assert_eq!(
571            DynSolType::Int(256)
572                .coerce_str("0x1111111111111111111111111111111111111111111111111111111111111111")
573                .unwrap(),
574            DynSolValue::Int(I256::from_be_bytes([0x11; 32]), 256)
575        );
576
577        assert_eq!(
578            DynSolType::Int(256)
579                .coerce_str("0x2222222222222222222222222222222222222222222222222222222222222222")
580                .unwrap(),
581            DynSolValue::Int(I256::from_be_bytes([0x22; 32]), 256)
582        );
583
584        assert_eq!(
585            DynSolType::Int(256)
586                .coerce_str("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
587                .unwrap(),
588            DynSolValue::Int(I256::MAX, 256)
589        );
590        assert!(
591            DynSolType::Int(256)
592                .coerce_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
593                .is_err()
594        );
595
596        assert_eq!(
597            DynSolType::Int(256).coerce_str("0").unwrap(),
598            DynSolValue::Int(I256::ZERO, 256)
599        );
600
601        assert_eq!(
602            DynSolType::Int(256).coerce_str("-0").unwrap(),
603            DynSolValue::Int(I256::ZERO, 256)
604        );
605
606        assert_eq!(
607            DynSolType::Int(256).coerce_str("+0").unwrap(),
608            DynSolValue::Int(I256::ZERO, 256)
609        );
610
611        assert_eq!(
612            DynSolType::Int(256).coerce_str("-1").unwrap(),
613            DynSolValue::Int(I256::MINUS_ONE, 256)
614        );
615
616        assert_eq!(
617            DynSolType::Int(256)
618                .coerce_str(
619                    "57896044618658097711785492504343953926634992332820282019728792003956564819967"
620                )
621                .unwrap(),
622            DynSolValue::Int(I256::MAX, 256)
623        );
624        assert_eq!(
625            DynSolType::Int(256)
626                .coerce_str(
627                    "-57896044618658097711785492504343953926634992332820282019728792003956564819968"
628                )
629                .unwrap(),
630            DynSolValue::Int(I256::MIN, 256)
631        );
632    }
633
634    #[test]
635    fn coerce_int_overflow() {
636        assert_eq!(
637            DynSolType::Int(8).coerce_str("126").unwrap(),
638            DynSolValue::Int(I256::try_from(126).unwrap(), 8),
639        );
640        assert_eq!(
641            DynSolType::Int(8).coerce_str("127").unwrap(),
642            DynSolValue::Int(I256::try_from(127).unwrap(), 8),
643        );
644        assert!(DynSolType::Int(8).coerce_str("128").is_err());
645        assert!(DynSolType::Int(8).coerce_str("129").is_err());
646        assert_eq!(
647            DynSolType::Int(16).coerce_str("128").unwrap(),
648            DynSolValue::Int(I256::try_from(128).unwrap(), 16),
649        );
650        assert_eq!(
651            DynSolType::Int(16).coerce_str("129").unwrap(),
652            DynSolValue::Int(I256::try_from(129).unwrap(), 16),
653        );
654
655        assert_eq!(
656            DynSolType::Int(8).coerce_str("-1").unwrap(),
657            DynSolValue::Int(I256::MINUS_ONE, 8),
658        );
659        assert_eq!(
660            DynSolType::Int(16).coerce_str("-1").unwrap(),
661            DynSolValue::Int(I256::MINUS_ONE, 16),
662        );
663    }
664
665    #[test]
666    fn coerce_uint() {
667        assert_eq!(
668            DynSolType::Uint(256)
669                .coerce_str("0x1111111111111111111111111111111111111111111111111111111111111111")
670                .unwrap(),
671            DynSolValue::Uint(U256::from_be_bytes([0x11; 32]), 256)
672        );
673
674        assert_eq!(
675            DynSolType::Uint(256)
676                .coerce_str("0x2222222222222222222222222222222222222222222222222222222222222222")
677                .unwrap(),
678            DynSolValue::Uint(U256::from_be_bytes([0x22; 32]), 256)
679        );
680
681        assert_eq!(
682            DynSolType::Uint(256)
683                .coerce_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
684                .unwrap(),
685            DynSolValue::Uint(U256::from_be_bytes([0xff; 32]), 256)
686        );
687
688        // 255 bits fails
689        assert!(
690            DynSolType::Uint(255)
691                .coerce_str("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
692                .is_err()
693        );
694
695        assert_eq!(
696            DynSolType::Uint(256)
697                .coerce_str(
698                    "115792089237316195423570985008687907853269984665640564039457584007913129639935"
699                )
700                .unwrap(),
701            DynSolValue::Uint(U256::MAX, 256)
702        );
703
704        assert_eq!(
705            DynSolType::Uint(256).coerce_str("0").unwrap(),
706            DynSolValue::Uint(U256::ZERO, 256)
707        );
708
709        assert_eq!(
710            DynSolType::Uint(256).coerce_str("1").unwrap(),
711            DynSolValue::Uint(U256::from(1), 256)
712        );
713    }
714
715    #[test]
716    fn coerce_uint_overflow() {
717        assert_eq!(
718            DynSolType::Uint(8).coerce_str("254").unwrap(),
719            DynSolValue::Uint(U256::from(254), 8),
720        );
721        assert_eq!(
722            DynSolType::Uint(8).coerce_str("255").unwrap(),
723            DynSolValue::Uint(U256::from(255), 8),
724        );
725        assert!(DynSolType::Uint(8).coerce_str("256").is_err());
726        assert!(DynSolType::Uint(8).coerce_str("257").is_err());
727        assert_eq!(
728            DynSolType::Uint(16).coerce_str("256").unwrap(),
729            DynSolValue::Uint(U256::from(256), 16),
730        );
731        assert_eq!(
732            DynSolType::Uint(16).coerce_str("257").unwrap(),
733            DynSolValue::Uint(U256::from(257), 16),
734        );
735    }
736
737    #[test]
738    fn coerce_uint_wei() {
739        assert_eq!(
740            DynSolType::Uint(256).coerce_str("1wei").unwrap(),
741            DynSolValue::Uint(U256::from(1), 256)
742        );
743        assert_eq!(
744            DynSolType::Uint(256).coerce_str("1 wei").unwrap(),
745            DynSolValue::Uint(U256::from(1), 256)
746        );
747
748        assert!(DynSolType::Uint(256).coerce_str("1").is_ok());
749        assert!(DynSolType::Uint(256).coerce_str("1.").is_err());
750        assert!(DynSolType::Uint(256).coerce_str("1 .").is_err());
751        assert!(DynSolType::Uint(256).coerce_str("1 .0").is_err());
752        assert!(DynSolType::Uint(256).coerce_str("1.wei").is_err());
753        assert!(DynSolType::Uint(256).coerce_str("1. wei").is_err());
754        assert!(DynSolType::Uint(256).coerce_str("1.0wei").is_err());
755        assert!(DynSolType::Uint(256).coerce_str("1.0 wei").is_err());
756        assert!(DynSolType::Uint(256).coerce_str("1.00wei").is_err());
757        assert!(DynSolType::Uint(256).coerce_str("1.00 wei").is_err());
758    }
759
760    #[test]
761    fn coerce_uint_gwei() {
762        assert_eq!(
763            DynSolType::Uint(256).coerce_str("1nano").unwrap(),
764            DynSolValue::Uint(U256::from_str("1000000000").unwrap(), 256)
765        );
766
767        assert_eq!(
768            DynSolType::Uint(256).coerce_str("1nanoether").unwrap(),
769            DynSolValue::Uint(U256::from_str("1000000000").unwrap(), 256)
770        );
771
772        assert_eq!(
773            DynSolType::Uint(256).coerce_str("1gwei").unwrap(),
774            DynSolValue::Uint(U256::from_str("1000000000").unwrap(), 256)
775        );
776
777        assert_eq!(
778            DynSolType::Uint(256).coerce_str("0.1 gwei").unwrap(),
779            DynSolValue::Uint(U256::from_str("100000000").unwrap(), 256)
780        );
781
782        assert_eq!(
783            DynSolType::Uint(256).coerce_str("0.000000001gwei").unwrap(),
784            DynSolValue::Uint(U256::from(1), 256)
785        );
786
787        assert_eq!(
788            DynSolType::Uint(256).coerce_str("0.123456789gwei").unwrap(),
789            DynSolValue::Uint(U256::from_str("123456789").unwrap(), 256)
790        );
791
792        assert_eq!(
793            DynSolType::Uint(256).coerce_str("123456789123.123456789gwei").unwrap(),
794            DynSolValue::Uint(U256::from_str("123456789123123456789").unwrap(), 256)
795        );
796    }
797
798    #[test]
799    fn coerce_uint_ether() {
800        assert_eq!(
801            DynSolType::Uint(256).coerce_str("10000000000ether").unwrap(),
802            DynSolValue::Uint(U256::from_str("10000000000000000000000000000").unwrap(), 256)
803        );
804
805        assert_eq!(
806            DynSolType::Uint(256).coerce_str("1ether").unwrap(),
807            DynSolValue::Uint(U256::from_str("1000000000000000000").unwrap(), 256)
808        );
809
810        assert_eq!(
811            DynSolType::Uint(256).coerce_str("0.01 ether").unwrap(),
812            DynSolValue::Uint(U256::from_str("10000000000000000").unwrap(), 256)
813        );
814
815        assert_eq!(
816            DynSolType::Uint(256).coerce_str("0.000000000000000001ether").unwrap(),
817            DynSolValue::Uint(U256::from(1), 256)
818        );
819
820        assert_eq!(
821            DynSolType::Uint(256).coerce_str("0.000000000000000001ether"),
822            DynSolType::Uint(256).coerce_str("1wei"),
823        );
824
825        assert_eq!(
826            DynSolType::Uint(256).coerce_str("0.123456789123456789ether").unwrap(),
827            DynSolValue::Uint(U256::from_str("123456789123456789").unwrap(), 256)
828        );
829
830        assert_eq!(
831            DynSolType::Uint(256).coerce_str("0.123456789123456000ether").unwrap(),
832            DynSolValue::Uint(U256::from_str("123456789123456000").unwrap(), 256)
833        );
834
835        assert_eq!(
836            DynSolType::Uint(256).coerce_str("0.1234567891234560ether").unwrap(),
837            DynSolValue::Uint(U256::from_str("123456789123456000").unwrap(), 256)
838        );
839
840        assert_eq!(
841            DynSolType::Uint(256).coerce_str("123456.123456789123456789ether").unwrap(),
842            DynSolValue::Uint(U256::from_str("123456123456789123456789").unwrap(), 256)
843        );
844
845        assert_eq!(
846            DynSolType::Uint(256).coerce_str("123456.123456789123456000ether").unwrap(),
847            DynSolValue::Uint(U256::from_str("123456123456789123456000").unwrap(), 256)
848        );
849
850        assert_eq!(
851            DynSolType::Uint(256).coerce_str("123456.1234567891234560ether").unwrap(),
852            DynSolValue::Uint(U256::from_str("123456123456789123456000").unwrap(), 256)
853        );
854    }
855
856    #[test]
857    fn coerce_uint_array_ether() {
858        assert_eq!(
859            DynSolType::Array(Box::new(DynSolType::Uint(256)))
860                .coerce_str("[ 1   ether,  10 ether ]")
861                .unwrap(),
862            DynSolValue::Array(vec![
863                DynSolValue::Uint(U256::from_str("1000000000000000000").unwrap(), 256),
864                DynSolValue::Uint(U256::from_str("10000000000000000000").unwrap(), 256),
865            ])
866        );
867    }
868
869    #[test]
870    fn coerce_uint_invalid_units() {
871        // 0.1 wei
872        assert!(DynSolType::Uint(256).coerce_str("0.1 wei").is_err());
873        assert!(DynSolType::Uint(256).coerce_str("0.0000000000000000001ether").is_err());
874
875        // 1 ether + 0.1 wei
876        assert!(DynSolType::Uint(256).coerce_str("1.0000000000000000001ether").is_err());
877
878        // 1_000_000_000 ether + 0.1 wei
879        assert!(DynSolType::Uint(256).coerce_str("1000000000.0000000000000000001ether").is_err());
880
881        assert!(DynSolType::Uint(256).coerce_str("0..1 gwei").is_err());
882
883        assert!(DynSolType::Uint(256).coerce_str("..1 gwei").is_err());
884
885        assert!(DynSolType::Uint(256).coerce_str("1. gwei").is_err());
886
887        assert!(DynSolType::Uint(256).coerce_str(".1 gwei").is_err());
888
889        assert!(DynSolType::Uint(256).coerce_str("2.1.1 gwei").is_err());
890
891        assert!(DynSolType::Uint(256).coerce_str(".1.1 gwei").is_err());
892
893        assert!(DynSolType::Uint(256).coerce_str("1abc").is_err());
894
895        assert!(DynSolType::Uint(256).coerce_str("1 gwei ").is_err());
896
897        assert!(DynSolType::Uint(256).coerce_str("g 1 gwei").is_err());
898
899        assert!(DynSolType::Uint(256).coerce_str("1gwei 1 gwei").is_err());
900    }
901
902    #[test]
903    fn coerce_fixed_bytes() {
904        let mk_word = |sl: &[u8]| {
905            let mut out = Word::ZERO;
906            out[..sl.len()].copy_from_slice(sl);
907            out
908        };
909
910        // not actually valid, but we don't care here
911        assert_eq!(
912            DynSolType::FixedBytes(0).coerce_str("0x").unwrap(),
913            DynSolValue::FixedBytes(mk_word(&[]), 0)
914        );
915
916        assert_eq!(
917            DynSolType::FixedBytes(1).coerce_str("0x00").unwrap(),
918            DynSolValue::FixedBytes(mk_word(&[0x00]), 1)
919        );
920        assert_eq!(
921            DynSolType::FixedBytes(1).coerce_str("0x00").unwrap(),
922            DynSolValue::FixedBytes(mk_word(&[0x00]), 1)
923        );
924        assert_eq!(
925            DynSolType::FixedBytes(2).coerce_str("0017").unwrap(),
926            DynSolValue::FixedBytes(mk_word(&[0x00, 0x17]), 2)
927        );
928        assert_eq!(
929            DynSolType::FixedBytes(3).coerce_str("123456").unwrap(),
930            DynSolValue::FixedBytes(mk_word(&[0x12, 0x34, 0x56]), 3)
931        );
932
933        let e = DynSolType::FixedBytes(1).coerce_str("").unwrap_err();
934        assert_error_contains(&e, &Error::EmptyHexStringWithoutPrefix.to_string());
935        let e = DynSolType::FixedBytes(1).coerce_str("0").unwrap_err();
936        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
937        let e = DynSolType::FixedBytes(1).coerce_str("0x").unwrap_err();
938        assert_error_contains(&e, &hex::FromHexError::InvalidStringLength.to_string());
939        let e = DynSolType::FixedBytes(1).coerce_str("0x0").unwrap_err();
940        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
941
942        let t = DynSolType::Array(Box::new(DynSolType::FixedBytes(1)));
943        let e = t.coerce_str("[0]").unwrap_err();
944        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
945        let e = t.coerce_str("[0x]").unwrap_err();
946        assert_error_contains(&e, &hex::FromHexError::InvalidStringLength.to_string());
947        let e = t.coerce_str("[0x0]").unwrap_err();
948        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
949
950        let t = DynSolType::Array(Box::new(DynSolType::Tuple(vec![DynSolType::FixedBytes(1)])));
951        let e = t.coerce_str("[(0)]").unwrap_err();
952        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
953        let e = t.coerce_str("[(0x)]").unwrap_err();
954        assert_error_contains(&e, &hex::FromHexError::InvalidStringLength.to_string());
955        let e = t.coerce_str("[(0x0)]").unwrap_err();
956        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
957    }
958
959    #[test]
960    fn coerce_address() {
961        // 38
962        assert!(DynSolType::Address.coerce_str("00000000000000000000000000000000000000").is_err());
963        // 39
964        assert!(DynSolType::Address.coerce_str("000000000000000000000000000000000000000").is_err());
965        // 40
966        assert_eq!(
967            DynSolType::Address.coerce_str("0000000000000000000000000000000000000000").unwrap(),
968            DynSolValue::Address(Address::ZERO)
969        );
970        assert_eq!(
971            DynSolType::Address.coerce_str("0x1111111111111111111111111111111111111111").unwrap(),
972            DynSolValue::Address(Address::new([0x11; 20]))
973        );
974        assert_eq!(
975            DynSolType::Address.coerce_str("2222222222222222222222222222222222222222").unwrap(),
976            DynSolValue::Address(Address::new([0x22; 20]))
977        );
978    }
979
980    #[test]
981    fn coerce_function() {
982        assert_eq!(
983            DynSolType::Function
984                .coerce_str("000000000000000000000000000000000000000000000000")
985                .unwrap(),
986            DynSolValue::Function(Function::ZERO)
987        );
988        assert_eq!(
989            DynSolType::Function
990                .coerce_str("0x111111111111111111111111111111111111111111111111")
991                .unwrap(),
992            DynSolValue::Function(Function::new([0x11; 24]))
993        );
994        assert_eq!(
995            DynSolType::Function
996                .coerce_str("222222222222222222222222222222222222222222222222")
997                .unwrap(),
998            DynSolValue::Function(Function::new([0x22; 24]))
999        );
1000    }
1001
1002    #[test]
1003    fn coerce_bytes() {
1004        let e = DynSolType::Bytes.coerce_str("").unwrap_err();
1005        assert_error_contains(&e, &Error::EmptyHexStringWithoutPrefix.to_string());
1006
1007        assert_eq!(DynSolType::Bytes.coerce_str("0x").unwrap(), DynSolValue::Bytes(vec![]));
1008        assert!(DynSolType::Bytes.coerce_str("0x0").is_err());
1009        assert!(DynSolType::Bytes.coerce_str("0").is_err());
1010        assert_eq!(DynSolType::Bytes.coerce_str("00").unwrap(), DynSolValue::Bytes(vec![0]));
1011        assert_eq!(DynSolType::Bytes.coerce_str("0x00").unwrap(), DynSolValue::Bytes(vec![0]));
1012
1013        assert_eq!(
1014            DynSolType::Bytes.coerce_str("123456").unwrap(),
1015            DynSolValue::Bytes(vec![0x12, 0x34, 0x56])
1016        );
1017        assert_eq!(
1018            DynSolType::Bytes.coerce_str("0x0017").unwrap(),
1019            DynSolValue::Bytes(vec![0x00, 0x17])
1020        );
1021
1022        let t = DynSolType::Tuple(vec![DynSolType::Bytes, DynSolType::Bytes]);
1023        let e = t.coerce_str("(0, 0x0)").unwrap_err();
1024        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
1025
1026        // TODO: cut_err in `array_parser` somehow
1027        /*
1028        let t = DynSolType::Array(Box::new(DynSolType::Tuple(vec![
1029            DynSolType::Bytes,
1030            DynSolType::Bytes,
1031        ])));
1032        let e = t.coerce_str("[(0, 0x0)]").unwrap_err();
1033        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
1034
1035        let t = DynSolType::Array(Box::new(DynSolType::Tuple(vec![
1036            DynSolType::Bytes,
1037            DynSolType::Bytes,
1038        ])));
1039        let e = t.coerce_str("[(0x00, 0x0)]").unwrap_err();
1040        assert_error_contains(&e, &hex::FromHexError::OddLength.to_string());
1041        */
1042    }
1043
1044    #[test]
1045    fn coerce_string() {
1046        assert_eq!(
1047            DynSolType::String.coerce_str("gavofyork").unwrap(),
1048            DynSolValue::String("gavofyork".into())
1049        );
1050        assert_eq!(
1051            DynSolType::String.coerce_str("gav of york").unwrap(),
1052            DynSolValue::String("gav of york".into())
1053        );
1054        assert_eq!(
1055            DynSolType::String.coerce_str("\"hello world\"").unwrap(),
1056            DynSolValue::String("hello world".into())
1057        );
1058        assert_eq!(
1059            DynSolType::String.coerce_str("'hello world'").unwrap(),
1060            DynSolValue::String("hello world".into())
1061        );
1062        assert_eq!(
1063            DynSolType::String.coerce_str("'\"hello world\"'").unwrap(),
1064            DynSolValue::String("\"hello world\"".into())
1065        );
1066        assert_eq!(
1067            DynSolType::String.coerce_str("'   hello world '").unwrap(),
1068            DynSolValue::String("   hello world ".into())
1069        );
1070        assert_eq!(
1071            DynSolType::String.coerce_str("'\"hello world'").unwrap(),
1072            DynSolValue::String("\"hello world".into())
1073        );
1074        assert_eq!(
1075            DynSolType::String.coerce_str("a, b").unwrap(),
1076            DynSolValue::String("a, b".into())
1077        );
1078        assert_eq!(
1079            DynSolType::String.coerce_str("hello (world)").unwrap(),
1080            DynSolValue::String("hello (world)".into())
1081        );
1082
1083        assert!(DynSolType::String.coerce_str("\"hello world").is_err());
1084        assert!(DynSolType::String.coerce_str("\"hello world'").is_err());
1085        assert!(DynSolType::String.coerce_str("'hello world").is_err());
1086        assert!(DynSolType::String.coerce_str("'hello world\"").is_err());
1087
1088        assert_eq!(
1089            DynSolType::String.coerce_str("Hello, world!").unwrap(),
1090            DynSolValue::String("Hello, world!".into())
1091        );
1092        let s = "$$g]a\"v/of;[()];2,yo\r)k_";
1093        assert_eq!(DynSolType::String.coerce_str(s).unwrap(), DynSolValue::String(s.into()));
1094    }
1095
1096    #[test]
1097    fn coerce_strings() {
1098        let arr = DynSolType::Array(Box::new(DynSolType::String));
1099        let mk_arr = |s: &[&str]| {
1100            DynSolValue::Array(s.iter().map(|s| DynSolValue::String(s.to_string())).collect())
1101        };
1102
1103        assert_eq!(arr.coerce_str("[]").unwrap(), mk_arr(&[]));
1104        assert_eq!(arr.coerce_str("[    ]").unwrap(), mk_arr(&[]));
1105
1106        // TODO: should this be an error?
1107        // assert!(arr.coerce_str("[,]").is_err());
1108        // assert!(arr.coerce_str("[ , ]").is_err());
1109
1110        assert_eq!(arr.coerce_str("[ foo bar ]").unwrap(), mk_arr(&["foo bar"]));
1111        assert_eq!(arr.coerce_str("[foo bar,]").unwrap(), mk_arr(&["foo bar"]));
1112        assert_eq!(arr.coerce_str("[  foo bar,  ]").unwrap(), mk_arr(&["foo bar"]));
1113        assert_eq!(arr.coerce_str("[ foo , bar ]").unwrap(), mk_arr(&["foo", "bar"]));
1114
1115        assert_eq!(arr.coerce_str("[\"foo\",\"bar\"]").unwrap(), mk_arr(&["foo", "bar"]));
1116
1117        assert_eq!(arr.coerce_str("['']").unwrap(), mk_arr(&[""]));
1118        assert_eq!(arr.coerce_str("[\"\"]").unwrap(), mk_arr(&[""]));
1119        assert_eq!(arr.coerce_str("['', '']").unwrap(), mk_arr(&["", ""]));
1120        assert_eq!(arr.coerce_str("['', \"\"]").unwrap(), mk_arr(&["", ""]));
1121        assert_eq!(arr.coerce_str("[\"\", '']").unwrap(), mk_arr(&["", ""]));
1122        assert_eq!(arr.coerce_str("[\"\", \"\"]").unwrap(), mk_arr(&["", ""]));
1123    }
1124
1125    #[test]
1126    fn coerce_array_of_bytes_and_strings() {
1127        let ty = DynSolType::Array(Box::new(DynSolType::Bytes));
1128        assert_eq!(ty.coerce_str("[]"), Ok(DynSolValue::Array(vec![])));
1129        assert_eq!(ty.coerce_str("[0x]"), Ok(DynSolValue::Array(vec![DynSolValue::Bytes(vec![])])));
1130
1131        let ty = DynSolType::Array(Box::new(DynSolType::String));
1132        assert_eq!(ty.coerce_str("[]"), Ok(DynSolValue::Array(vec![])));
1133        assert_eq!(
1134            ty.coerce_str("[\"\"]"),
1135            Ok(DynSolValue::Array(vec![DynSolValue::String(String::new())]))
1136        );
1137        assert_eq!(
1138            ty.coerce_str("[0x]"),
1139            Ok(DynSolValue::Array(vec![DynSolValue::String("0x".into())]))
1140        );
1141    }
1142
1143    #[test]
1144    fn coerce_empty_array() {
1145        assert_eq!(
1146            DynSolType::Array(Box::new(DynSolType::Bool)).coerce_str("[]").unwrap(),
1147            DynSolValue::Array(vec![])
1148        );
1149        assert_eq!(
1150            DynSolType::FixedArray(Box::new(DynSolType::Bool), 0).coerce_str("[]").unwrap(),
1151            DynSolValue::FixedArray(vec![]),
1152        );
1153        assert!(DynSolType::FixedArray(Box::new(DynSolType::Bool), 1).coerce_str("[]").is_err());
1154    }
1155
1156    #[test]
1157    fn coerce_bool_array() {
1158        assert_eq!(
1159            DynSolType::coerce_str(&DynSolType::Array(Box::new(DynSolType::Bool)), "[true, false]")
1160                .unwrap(),
1161            DynSolValue::Array(vec![DynSolValue::Bool(true), DynSolValue::Bool(false)])
1162        );
1163    }
1164
1165    #[test]
1166    fn coerce_bool_array_of_arrays() {
1167        assert_eq!(
1168            DynSolType::coerce_str(
1169                &DynSolType::Array(Box::new(DynSolType::Array(Box::new(DynSolType::Bool)))),
1170                "[ [ true, true, false ], [ false]]"
1171            )
1172            .unwrap(),
1173            DynSolValue::Array(vec![
1174                DynSolValue::Array(vec![
1175                    DynSolValue::Bool(true),
1176                    DynSolValue::Bool(true),
1177                    DynSolValue::Bool(false)
1178                ]),
1179                DynSolValue::Array(vec![DynSolValue::Bool(false)])
1180            ])
1181        );
1182    }
1183
1184    #[test]
1185    fn coerce_bool_fixed_array() {
1186        let ty = DynSolType::FixedArray(Box::new(DynSolType::Bool), 3);
1187        assert!(ty.coerce_str("[]").is_err());
1188        assert!(ty.coerce_str("[true]").is_err());
1189        assert!(ty.coerce_str("[true, false]").is_err());
1190        assert_eq!(
1191            ty.coerce_str("[true, false, true]").unwrap(),
1192            DynSolValue::FixedArray(vec![
1193                DynSolValue::Bool(true),
1194                DynSolValue::Bool(false),
1195                DynSolValue::Bool(true),
1196            ])
1197        );
1198        assert!(ty.coerce_str("[true, false, false, true]").is_err());
1199    }
1200
1201    #[test]
1202    fn single_quoted_in_array_must_error() {
1203        assert!(
1204            DynSolType::Array(Box::new(DynSolType::Bool))
1205                .coerce_str("[true,\"false,false]")
1206                .is_err()
1207        );
1208        assert!(DynSolType::Array(Box::new(DynSolType::Bool)).coerce_str("[false\"]").is_err());
1209        assert!(
1210            DynSolType::Array(Box::new(DynSolType::Bool)).coerce_str("[true,false\"]").is_err()
1211        );
1212        assert!(
1213            DynSolType::Array(Box::new(DynSolType::Bool))
1214                .coerce_str("[true,\"false\",false]")
1215                .is_err()
1216        );
1217        assert!(DynSolType::Array(Box::new(DynSolType::Bool)).coerce_str("[true,false]").is_ok());
1218    }
1219
1220    #[test]
1221    fn tuples() {
1222        let ty = DynSolType::Tuple(vec![DynSolType::String, DynSolType::Bool, DynSolType::String]);
1223        assert_eq!(
1224            ty.coerce_str("(\"a,]) b\", true, true? ]and] false!)").unwrap(),
1225            DynSolValue::Tuple(vec![
1226                DynSolValue::String("a,]) b".into()),
1227                DynSolValue::Bool(true),
1228                DynSolValue::String("true? ]and] false!".into()),
1229            ])
1230        );
1231        assert!(ty.coerce_str("(\"\", true, a, b)").is_err());
1232        assert!(ty.coerce_str("(a, b, true, a)").is_err());
1233    }
1234
1235    #[test]
1236    fn tuples_arrays_mixed() {
1237        assert_eq!(
1238            DynSolType::Array(Box::new(DynSolType::Tuple(vec![
1239                DynSolType::Array(Box::new(DynSolType::Tuple(vec![DynSolType::Bool]))),
1240                DynSolType::Array(Box::new(DynSolType::Tuple(vec![
1241                    DynSolType::Bool,
1242                    DynSolType::Bool
1243                ]))),
1244            ])))
1245            .coerce_str("[([(true)],[(false,true)])]")
1246            .unwrap(),
1247            DynSolValue::Array(vec![DynSolValue::Tuple(vec![
1248                DynSolValue::Array(vec![DynSolValue::Tuple(vec![DynSolValue::Bool(true)])]),
1249                DynSolValue::Array(vec![DynSolValue::Tuple(vec![
1250                    DynSolValue::Bool(false),
1251                    DynSolValue::Bool(true)
1252                ])]),
1253            ])])
1254        );
1255
1256        assert_eq!(
1257            DynSolType::Tuple(vec![
1258                DynSolType::Array(Box::new(DynSolType::Tuple(vec![DynSolType::Bool]))),
1259                DynSolType::Array(Box::new(DynSolType::Tuple(vec![
1260                    DynSolType::Bool,
1261                    DynSolType::Bool
1262                ]))),
1263            ])
1264            .coerce_str("([(true)],[(false,true)])")
1265            .unwrap(),
1266            DynSolValue::Tuple(vec![
1267                DynSolValue::Array(vec![DynSolValue::Tuple(vec![DynSolValue::Bool(true)])]),
1268                DynSolValue::Array(vec![DynSolValue::Tuple(vec![
1269                    DynSolValue::Bool(false),
1270                    DynSolValue::Bool(true)
1271                ])]),
1272            ])
1273        );
1274    }
1275
1276    #[test]
1277    fn tuple_array_nested() {
1278        assert_eq!(
1279            DynSolType::Tuple(vec![
1280                DynSolType::Array(Box::new(DynSolType::Tuple(vec![DynSolType::Address]))),
1281                DynSolType::Uint(256),
1282            ])
1283            .coerce_str("([(5c9d55b78febcc2061715ba4f57ecf8ea2711f2c)],2)")
1284            .unwrap(),
1285            DynSolValue::Tuple(vec![
1286                DynSolValue::Array(vec![DynSolValue::Tuple(vec![DynSolValue::Address(address!(
1287                    "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c"
1288                ))])]),
1289                DynSolValue::Uint(U256::from(2), 256),
1290            ])
1291        );
1292    }
1293
1294    // keep `n` low to avoid stack overflows (debug mode)
1295    #[test]
1296    fn lotsa_array_nesting() {
1297        let n = 10;
1298
1299        let mut ty = DynSolType::Bool;
1300        for _ in 0..n {
1301            ty = DynSolType::Array(Box::new(ty));
1302        }
1303        let mut value_str = String::new();
1304        value_str.push_str(&"[".repeat(n));
1305        value_str.push_str("true");
1306        value_str.push_str(&"]".repeat(n));
1307
1308        let mut value = ty.coerce_str(&value_str).unwrap();
1309        for _ in 0..n {
1310            let DynSolValue::Array(arr) = value else { panic!("{value:?}") };
1311            assert_eq!(arr.len(), 1);
1312            value = arr.into_iter().next().unwrap();
1313        }
1314        assert_eq!(value, DynSolValue::Bool(true));
1315    }
1316
1317    #[test]
1318    fn lotsa_tuple_nesting() {
1319        let n = 10;
1320
1321        let mut ty = DynSolType::Bool;
1322        for _ in 0..n {
1323            ty = DynSolType::Tuple(vec![ty]);
1324        }
1325        let mut value_str = String::new();
1326        value_str.push_str(&"(".repeat(n));
1327        value_str.push_str("true");
1328        value_str.push_str(&")".repeat(n));
1329
1330        let mut value = ty.coerce_str(&value_str).unwrap();
1331        for _ in 0..n {
1332            let DynSolValue::Tuple(tuple) = value else { panic!("{value:?}") };
1333            assert_eq!(tuple.len(), 1);
1334            value = tuple.into_iter().next().unwrap();
1335        }
1336        assert_eq!(value, DynSolValue::Bool(true));
1337    }
1338
1339    #[test]
1340    fn coerce_uint_scientific() {
1341        uint_test("1e18", Ok("1000000000000000000"));
1342
1343        uint_test("0.03069536448928848133e20", Ok("3069536448928848133"));
1344
1345        uint_test("1.5e18", Ok("1500000000000000000"));
1346
1347        uint_test("1e-3 ether", Ok("1000000000000000"));
1348        uint_test("1.0e-3 ether", Ok("1000000000000000"));
1349        uint_test("1.1e-3 ether", Ok("1100000000000000"));
1350
1351        uint_test("74258.225772486694040708e18", Ok("74258225772486694040708"));
1352        uint_test("0.03069536448928848133e20", Ok("3069536448928848133"));
1353        uint_test("0.000000000003069536448928848133e30", Ok("3069536448928848133"));
1354
1355        uint_test("1e-1", Err(()));
1356        uint_test("1e-2", Err(()));
1357        uint_test("1e-18", Err(()));
1358        uint_test("1 e18", Err(()));
1359        uint_test("1ex", Err(()));
1360        uint_test("1e", Err(()));
1361    }
1362}