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