fix(abigen): handle lossy ethabi generated abi structs (#950)
* fix(abigen): handle lossy ethabi generated abi structs * chore: rustfmt
This commit is contained in:
parent
60515d9404
commit
45a37faa3d
|
@ -91,23 +91,43 @@ impl Context {
|
|||
tuple: ParamType,
|
||||
) -> Result<TokenStream> {
|
||||
let mut fields = Vec::with_capacity(sol_struct.fields().len());
|
||||
|
||||
// determines whether we have enough info to create named fields
|
||||
let is_tuple = sol_struct.has_nameless_field();
|
||||
|
||||
for field in sol_struct.fields() {
|
||||
let field_name = util::ident(&field.name().to_snake_case());
|
||||
match field.r#type() {
|
||||
FieldType::Elementary(ty) => {
|
||||
let ty = types::expand(ty)?;
|
||||
fields.push(quote! { pub #field_name: #ty });
|
||||
}
|
||||
FieldType::Struct(struct_ty) => {
|
||||
let ty = expand_struct_type(struct_ty);
|
||||
fields.push(quote! { pub #field_name: #ty });
|
||||
}
|
||||
let ty = match field.r#type() {
|
||||
FieldType::Elementary(ty) => types::expand(ty)?,
|
||||
FieldType::Struct(struct_ty) => expand_struct_type(struct_ty),
|
||||
FieldType::Mapping(_) => {
|
||||
eyre::bail!("Mapping types in struct `{}` are not supported {:?}", name, field)
|
||||
}
|
||||
};
|
||||
|
||||
if is_tuple {
|
||||
fields.push(ty);
|
||||
} else {
|
||||
let field_name = util::ident(&field.name().to_snake_case());
|
||||
fields.push(quote! { pub #field_name: #ty });
|
||||
}
|
||||
}
|
||||
|
||||
let name = util::ident(name);
|
||||
|
||||
let struct_def = if is_tuple {
|
||||
quote! {
|
||||
pub struct #name(
|
||||
#( #fields ),*
|
||||
);
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
pub struct #name {
|
||||
#( #fields ),*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let sig = if let ParamType::Tuple(ref tokens) = tuple {
|
||||
tokens.iter().map(|kind| kind.to_string()).collect::<Vec<_>>().join(",")
|
||||
} else {
|
||||
|
@ -118,8 +138,6 @@ impl Context {
|
|||
|
||||
let abi_signature_doc = util::expand_doc(&format!("`{}`", abi_signature));
|
||||
|
||||
let name = util::ident(name);
|
||||
|
||||
// use the same derives as for events
|
||||
let derives = util::expand_derives(&self.event_derives);
|
||||
|
||||
|
@ -127,9 +145,7 @@ impl Context {
|
|||
Ok(quote! {
|
||||
#abi_signature_doc
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)]
|
||||
pub struct #name {
|
||||
#( #fields ),*
|
||||
}
|
||||
#struct_def
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -231,3 +231,17 @@ impl ContractBindings {
|
|||
name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn can_generate_structs() {
|
||||
let greeter = include_str!("../../tests/solidity-contracts/greeter_with_struct.json");
|
||||
let abigen = Abigen::new("Greeter", greeter).unwrap();
|
||||
let gen = abigen.generate().unwrap();
|
||||
let out = gen.tokens.to_string();
|
||||
assert!(out.contains("pub struct Stuff"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -502,7 +502,7 @@ mod tests {
|
|||
|
||||
fn run_test<T>(test: T)
|
||||
where
|
||||
T: FnOnce(&Context) -> () + panic::UnwindSafe,
|
||||
T: FnOnce(&Context) + panic::UnwindSafe,
|
||||
{
|
||||
let crate_root = std::path::Path::new(&env!("CARGO_MANIFEST_DIR")).to_owned();
|
||||
let console = Abigen::new(
|
||||
|
|
|
@ -8,6 +8,7 @@ use serde::{
|
|||
};
|
||||
|
||||
/// Contract ABI as a list of items where each item can be a function, constructor or event
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RawAbi(Vec<Item>);
|
||||
|
||||
impl IntoIterator for RawAbi {
|
||||
|
@ -84,11 +85,12 @@ pub struct Item {
|
|||
pub outputs: Vec<Component>,
|
||||
}
|
||||
|
||||
/// Either
|
||||
/// Either an input/output or a nested component of an input/output
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Component {
|
||||
#[serde(rename = "internalType", default, skip_serializing_if = "Option::is_none")]
|
||||
pub internal_type: Option<String>,
|
||||
#[serde(default)]
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: String,
|
||||
|
@ -112,4 +114,12 @@ mod tests {
|
|||
include_str!("../../tests/solidity-contracts/verifier_abi_hardhat.json");
|
||||
let _ = serde_json::from_str::<RawAbi>(VERIFIER_ABI).unwrap();
|
||||
}
|
||||
|
||||
/// due to ethabi's limitations some may be stripped when ethers-solc generates the abi, such as
|
||||
/// the name of the component
|
||||
#[test]
|
||||
fn can_parse_ethers_solc_generated_abi() {
|
||||
let s = r#"[{"type":"function","name":"greet","inputs":[{"internalType":"struct Greeter.Stuff","name":"stuff","type":"tuple","components":[{"type":"bool"}]}],"outputs":[{"internalType":"struct Greeter.Stuff","name":"","type":"tuple","components":[{"type":"bool"}]}],"stateMutability":"view"}]"#;
|
||||
let _ = serde_json::from_str::<RawAbi>(s).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ mod tests {
|
|||
#[test]
|
||||
fn parse_address_missing_prefix() {
|
||||
assert!(
|
||||
!parse_address("0000000000000000000000000000000000000000").is_ok(),
|
||||
parse_address("0000000000000000000000000000000000000000").is_err(),
|
||||
"parsing address not starting with 0x should fail"
|
||||
);
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ mod tests {
|
|||
#[test]
|
||||
fn parse_address_address_too_short() {
|
||||
assert!(
|
||||
!parse_address("0x00000000000000").is_ok(),
|
||||
parse_address("0x00000000000000").is_err(),
|
||||
"parsing address not starting with 0x should fail"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"abi": [
|
||||
{
|
||||
"type": "function",
|
||||
"name": "greet",
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "struct Greeter.Stuff",
|
||||
"name": "stuff",
|
||||
"type": "tuple",
|
||||
"components": [
|
||||
{
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "struct Greeter.Stuff",
|
||||
"name": "",
|
||||
"type": "tuple",
|
||||
"components": [
|
||||
{
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stateMutability": "view"
|
||||
}
|
||||
],
|
||||
"bytecode": {
|
||||
"object": "0x608060405234801561001057600080fd5b50610242806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80635581701b14610030575b600080fd5b61004a60048036038101906100459190610199565b610060565b60405161005791906101f1565b60405180910390f35b610068610070565b819050919050565b60405180602001604052806000151581525090565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100e282610099565b810181811067ffffffffffffffff82111715610101576101006100aa565b5b80604052505050565b6000610114610085565b905061012082826100d9565b919050565b60008115159050919050565b61013a81610125565b811461014557600080fd5b50565b60008135905061015781610131565b92915050565b60006020828403121561017357610172610094565b5b61017d602061010a565b9050600061018d84828501610148565b60008301525092915050565b6000602082840312156101af576101ae61008f565b5b60006101bd8482850161015d565b91505092915050565b6101cf81610125565b82525050565b6020820160008201516101eb60008501826101c6565b50505050565b600060208201905061020660008301846101d5565b9291505056fea2646970667358221220890202b0964477379a457ab3725a21d7c14581e4596552e32a54e23f1c6564e064736f6c634300080c0033",
|
||||
"sourceMap": "58:158:0:-:0;;;;;;;;;;;;;;;;;;;",
|
||||
"linkReferences": {}
|
||||
},
|
||||
"deployedBytecode": {
|
||||
"object": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80635581701b14610030575b600080fd5b61004a60048036038101906100459190610199565b610060565b60405161005791906101f1565b60405180910390f35b610068610070565b819050919050565b60405180602001604052806000151581525090565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100e282610099565b810181811067ffffffffffffffff82111715610101576101006100aa565b5b80604052505050565b6000610114610085565b905061012082826100d9565b919050565b60008115159050919050565b61013a81610125565b811461014557600080fd5b50565b60008135905061015781610131565b92915050565b60006020828403121561017357610172610094565b5b61017d602061010a565b9050600061018d84828501610148565b60008301525092915050565b6000602082840312156101af576101ae61008f565b5b60006101bd8482850161015d565b91505092915050565b6101cf81610125565b82525050565b6020820160008201516101eb60008501826101c6565b50505050565b600060208201905061020660008301846101d5565b9291505056fea2646970667358221220890202b0964477379a457ab3725a21d7c14581e4596552e32a54e23f1c6564e064736f6c634300080c0033",
|
||||
"sourceMap": "58:158:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115:99;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;171:12;;:::i;:::-;202:5;195:12;;115:99;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;:::o;7:75:1:-;40:6;73:2;67:9;57:19;;7:75;:::o;88:117::-;197:1;194;187:12;334:117;443:1;440;433:12;457:102;498:6;549:2;545:7;540:2;533:5;529:14;525:28;515:38;;457:102;;;:::o;565:180::-;613:77;610:1;603:88;710:4;707:1;700:15;734:4;731:1;724:15;751:281;834:27;856:4;834:27;:::i;:::-;826:6;822:40;964:6;952:10;949:22;928:18;916:10;913:34;910:62;907:88;;;975:18;;:::i;:::-;907:88;1015:10;1011:2;1004:22;794:238;751:281;;:::o;1038:129::-;1072:6;1099:20;;:::i;:::-;1089:30;;1128:33;1156:4;1148:6;1128:33;:::i;:::-;1038:129;;;:::o;1296:90::-;1330:7;1373:5;1366:13;1359:21;1348:32;;1296:90;;;:::o;1392:116::-;1462:21;1477:5;1462:21;:::i;:::-;1455:5;1452:32;1442:60;;1498:1;1495;1488:12;1442:60;1392:116;:::o;1514:133::-;1557:5;1595:6;1582:20;1573:29;;1611:30;1635:5;1611:30;:::i;:::-;1514:133;;;;:::o;1681:405::-;1750:5;1794:4;1782:9;1777:3;1773:19;1769:30;1766:117;;;1802:79;;:::i;:::-;1766:117;1901:21;1917:4;1901:21;:::i;:::-;1892:30;;1981:1;2021:46;2063:3;2054:6;2043:9;2039:22;2021:46;:::i;:::-;2014:4;2007:5;2003:16;1996:72;1932:147;1681:405;;;;:::o;2092:369::-;2171:6;2220:2;2208:9;2199:7;2195:23;2191:32;2188:119;;;2226:79;;:::i;:::-;2188:119;2346:1;2371:73;2436:7;2427:6;2416:9;2412:22;2371:73;:::i;:::-;2361:83;;2317:137;2092:369;;;;:::o;2467:99::-;2538:21;2553:5;2538:21;:::i;:::-;2533:3;2526:34;2467:99;;:::o;2624:317::-;2761:4;2756:3;2752:14;2848:4;2841:5;2837:16;2831:23;2867:57;2918:4;2913:3;2909:14;2895:12;2867:57;:::i;:::-;2776:158;2730:211;2624:317;;:::o;2947:302::-;3080:4;3118:2;3107:9;3103:18;3095:26;;3131:111;3239:1;3228:9;3224:17;3215:6;3131:111;:::i;:::-;2947:302;;;;:::o",
|
||||
"linkReferences": {}
|
||||
}
|
||||
}
|
|
@ -280,6 +280,11 @@ impl SolStruct {
|
|||
&self.fields
|
||||
}
|
||||
|
||||
/// Returns `true` if a field with an empty name exists
|
||||
pub fn has_nameless_field(&self) -> bool {
|
||||
self.fields.iter().any(|f| f.name.is_empty())
|
||||
}
|
||||
|
||||
/// If the struct only consists of elementary fields, this will return `ParamType::Tuple` with
|
||||
/// all those fields
|
||||
pub fn as_tuple(&self) -> Option<ParamType> {
|
||||
|
|
Loading…
Reference in New Issue