Skip to content

Commit

Permalink
fix(json-abi): Param.ty is not always a valid TypeSpecifier (#386)
Browse files Browse the repository at this point in the history
* fix(json-abi): `Param.ty` is not always a valid `TypeSpecifier`

* fix: workaround in type parser too

* test: better test case for this

* chore: remove earlier workaround

* chore: simplify workaround
  • Loading branch information
DaniPopes authored Oct 25, 2023
1 parent 343f799 commit 393f806
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 5 deletions.
9 changes: 9 additions & 0 deletions crates/dyn-abi/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,4 +381,13 @@ mod tests {
))
);
}

#[test]
fn library_enum_workaround() {
assert_eq!(parse("MyLibrary.MyEnum"), Ok(DynSolType::Uint(8)));
assert_eq!(
parse("MyLibrary.MyEnum[]"),
Ok(DynSolType::Array(Box::new(DynSolType::Uint(8))))
);
}
}
16 changes: 12 additions & 4 deletions crates/json-abi/src/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ use serde::{de::Unexpected, Deserialize, Deserializer, Serialize, Serializer};
pub struct Param {
/// The canonical Solidity type of the parameter, using the word "tuple" to
/// represent complex types. E.g. `uint256` or `bytes[2]` or `tuple` or
/// `tuple[2]`. This field always contains a valid
/// [`alloy_sol_type_parser::TypeSpecifier`].
/// `tuple[2]`.
///
/// Generally, this is a valid [`TypeSpecifier`], but in very rare
/// circumstances, such as when a function in a library contains an enum
/// in its parameters or return types, this will be `Contract.EnumName`
/// instead of the actual type (`uint8`).
pub ty: String,
/// The name of the parameter. This field always contains either the empty
/// string, or a valid Solidity identifier.
Expand Down Expand Up @@ -261,8 +265,12 @@ impl Param {
pub struct EventParam {
/// The canonical Solidity type of the parameter, using the word "tuple" to
/// represent complex types. E.g. `uint256` or `bytes[2]` or `tuple` or
/// `tuple[2]`. This field always contains a valid
/// [`alloy_sol_type_parser::TypeSpecifier`].
/// `tuple[2]`.
///
/// Generally, this is a valid [`TypeSpecifier`], but in very rare
/// circumstances, such as when a function in a library contains an enum
/// in its parameters or return types, this will be `Contract.EnumName`
/// instead of the actual type (`uint8`).
pub ty: String,
/// The name of the parameter. This field always contains either the empty
/// string, or a valid Solidity identifier.
Expand Down
1 change: 1 addition & 0 deletions crates/json-abi/tests/abi/EnumsInLibraryFunctions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum[2]","name":"x","type":"EnumsInLibraryFunctions.TheEnum[2]"}],"name":"enumArray","outputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum[2]","name":"","type":"EnumsInLibraryFunctions.TheEnum[2]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum[][69][]","name":"x","type":"EnumsInLibraryFunctions.TheEnum[][69][]"}],"name":"enumArrays","outputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum[][69][]","name":"","type":"EnumsInLibraryFunctions.TheEnum[][69][]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum[]","name":"x","type":"EnumsInLibraryFunctions.TheEnum[]"}],"name":"enumDynArray","outputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum[]","name":"","type":"EnumsInLibraryFunctions.TheEnum[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum","name":"x","type":"EnumsInLibraryFunctions.TheEnum"}],"name":"enum_","outputs":[{"internalType":"enum EnumsInLibraryFunctions.TheEnum","name":"","type":"EnumsInLibraryFunctions.TheEnum"}],"stateMutability":"pure","type":"function"}]
25 changes: 25 additions & 0 deletions crates/sol-macro/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,31 @@ mod tests {
assert_eq!(returns[1].ty.to_string(), "Execution[]");
assert_eq!(returns[1].name.as_ref().unwrap(), "f");
}
"EnumsInLibraryFunctions" => {
assert_eq!(c.name, "EnumsInLibraryFunctions");
assert_eq!(c.body.len(), 5);
let [Item::Udt(the_enum), Item::Function(f_array), Item::Function(f_arrays), Item::Function(f_dyn_array), Item::Function(f_just_enum)] =
&c.body[..]
else {
panic!("{c:#?}");
};

assert_eq!(the_enum.name, "TheEnum");
assert_eq!(the_enum.ty.to_string(), "uint8");

let function_tests = [
(f_array, "enumArray", "TheEnum[2]"),
(f_arrays, "enumArrays", "TheEnum[][69][]"),
(f_dyn_array, "enumDynArray", "TheEnum[]"),
(f_just_enum, "enum_", "TheEnum"),
];
for (f, name, ty) in function_tests {
assert_eq!(f.name.as_ref().unwrap(), name);
assert_eq!(f.arguments.type_strings().collect::<Vec<_>>(), [ty]);
let ret = &f.returns.as_ref().expect("no returns").returns;
assert_eq!(ret.type_strings().collect::<Vec<_>>(), [ty]);
}
}
_ => {}
}
}
Expand Down
15 changes: 14 additions & 1 deletion crates/sol-type-parser/src/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,20 @@ impl<'a> RootType<'a> {

/// [`winnow`] parser for this type.
pub fn parser(input: &mut &'a str) -> PResult<Self> {
trace("RootType", identifier).parse_next(input).map(Self)
trace("RootType", |input: &mut &'a str| {
identifier(input).map(|mut 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";
}
Self(ident)
})
})
.parse_next(input)
}

/// The string underlying this type. The type name.
Expand Down
24 changes: 24 additions & 0 deletions crates/syn-solidity/tests/contracts/EnumsInLibraryFunctions.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

library EnumsInLibraryFunctions {
enum TheEnum {
DoesntMatter
}

function enum_(TheEnum x) external pure returns (TheEnum) {
return x;
}

function enumDynArray(TheEnum[] memory x) external pure returns (TheEnum[] memory) {
return x;
}

function enumArray(TheEnum[2] memory x) external pure returns (TheEnum[2] memory) {
return x;
}

function enumArrays(TheEnum[][69][] memory x) external pure returns (TheEnum[][69][] memory) {
return x;
}
}

0 comments on commit 393f806

Please sign in to comment.