From bae924d4c025f90abd5771f4d6c2605ff1a1bbde Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Thu, 2 Nov 2023 01:50:03 +0100 Subject: [PATCH] fix(sol-type-parser): normalize `u?int` to `u?int256` --- crates/json-abi/src/utils.rs | 2 +- crates/sol-type-parser/src/root.rs | 38 +++++++++++++++++++------ crates/sol-type-parser/src/type_spec.rs | 17 +++++++++++ 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/crates/json-abi/src/utils.rs b/crates/json-abi/src/utils.rs index 70d325e91..49f59176e 100644 --- a/crates/json-abi/src/utils.rs +++ b/crates/json-abi/src/utils.rs @@ -296,7 +296,7 @@ mod tests { parse_sig::("toString(uint number)(string s)"), Ok(( "toString".into(), - vec![param2("uint", "number")], + vec![param2("uint256", "number")], vec![param2("string", "s")], false )) diff --git a/crates/sol-type-parser/src/root.rs b/crates/sol-type-parser/src/root.rs index 6e1db9197..4c7c84deb 100644 --- a/crates/sol-type-parser/src/root.rs +++ b/crates/sol-type-parser/src/root.rs @@ -5,6 +5,9 @@ use winnow::{trace::trace, PResult, Parser}; /// A root type, with no array suffixes. Corresponds to a single, non-sequence /// type. This is the most basic type specifier. /// +/// Note that this type might modify the input string, so [`span()`](Self::span) +/// must not be assumed to be the same as the input string. +/// /// # Examples /// /// ``` @@ -20,10 +23,12 @@ use winnow::{trace::trace, PResult, Parser}; /// /// // No tuples /// assert!(RootType::parse("(uint256,uint256)").is_err()); +/// +/// // Input string might get modified +/// assert_eq!(RootType::parse("uint")?.span(), "uint256"); /// # Ok::<_, alloy_sol_type_parser::Error>(()) /// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] pub struct RootType<'a>(&'a str); impl<'a> TryFrom<&'a str> for RootType<'a> { @@ -64,26 +69,28 @@ impl<'a> RootType<'a> { /// Parse a root type from a string. #[inline] pub fn parse(input: &'a str) -> Result { - if is_valid_identifier(input) { - Ok(Self(input)) - } else { - Err(Error::invalid_type_string(input)) - } + Self::parser.parse(input).map_err(Error::parser) } /// [`winnow`] parser for this type. pub fn parser(input: &mut &'a str) -> PResult { trace("RootType", |input: &mut &'a str| { - identifier(input).map(|mut ident| { + identifier(input).map(|ident| { // Workaround for enums in library function params or returns. // See: https://github.com/alloy-rs/core/pull/386 // See ethabi workaround: https://github.com/rust-ethereum/ethabi/blob/b1710adc18f5b771d2d2519c87248b1ba9430778/ethabi/src/param_type/reader.rs#L162-L167 if input.starts_with('.') { *input = &input[1..]; let _ = identifier(input); - ident = "uint8"; + return Self("uint8"); + } + + // Normalize the `u?int` aliases to the canonical `u?int256` + match ident { + "uint" => Self("uint256"), + "int" => Self("int256"), + _ => Self(ident), } - Self(ident) }) }) .parse_next(input) @@ -127,3 +134,16 @@ impl<'a> RootType<'a> { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn modified_input() { + assert_eq!(RootType::parse("Contract.Enum"), Ok(RootType("uint8"))); + + assert_eq!(RootType::parse("int"), Ok(RootType("int256"))); + assert_eq!(RootType::parse("uint"), Ok(RootType("uint256"))); + } +} diff --git a/crates/sol-type-parser/src/type_spec.rs b/crates/sol-type-parser/src/type_spec.rs index 8828b5331..139c4d1d4 100644 --- a/crates/sol-type-parser/src/type_spec.rs +++ b/crates/sol-type-parser/src/type_spec.rs @@ -149,6 +149,15 @@ mod test { #[test] fn parse_test() { + assert_eq!( + TypeSpecifier::parse("uint"), + Ok(TypeSpecifier { + span: "uint", + stem: TypeStem::parse("uint256").unwrap(), + sizes: vec![], + }) + ); + assert_eq!( TypeSpecifier::parse("uint256"), Ok(TypeSpecifier { @@ -256,6 +265,14 @@ mod test { #[test] fn try_basic_solidity() { + assert_eq!( + TypeSpecifier::parse("uint").unwrap().try_basic_solidity(), + Ok(()) + ); + assert_eq!( + TypeSpecifier::parse("int").unwrap().try_basic_solidity(), + Ok(()) + ); assert_eq!( TypeSpecifier::parse("uint256") .unwrap()