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 #[cfg_attr(
48 feature = "eip712",
49 doc = "- [`CustomStruct`](DynSolType::CustomStruct): the same as `Tuple`"
50 )]
51 #[doc(alias = "tokenize")] 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 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 (|| -> 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 (|| -> 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 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 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 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 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 assert!(DynSolType::Uint(256).coerce_str("0.1 wei").is_err());
873 assert!(DynSolType::Uint(256).coerce_str("0.0000000000000000001ether").is_err());
874
875 assert!(DynSolType::Uint(256).coerce_str("1.0000000000000000001ether").is_err());
877
878 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 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 assert!(DynSolType::Address.coerce_str("00000000000000000000000000000000000000").is_err());
963 assert!(DynSolType::Address.coerce_str("000000000000000000000000000000000000000").is_err());
965 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 }
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 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 #[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}