diff --git a/ethers-contract/ethers-contract-abigen/src/util.rs b/ethers-contract/ethers-contract-abigen/src/util.rs index e9453b5eb..b4f0acfd4 100644 --- a/ethers-contract/ethers-contract-abigen/src/util.rs +++ b/ethers-contract/ethers-contract-abigen/src/util.rs @@ -263,14 +263,15 @@ fn _derive_builtin_traits_struct( } } +/// Recurses on the type until it reaches the struct tuple `ParamType`. fn get_struct_params<'a>(s_ty: &StructFieldType, ty: &'a ParamType) -> &'a [ParamType] { match (s_ty, ty) { - (StructFieldType::Type(_), ParamType::Tuple(params)) => params, - (StructFieldType::Array(s_ty), ParamType::Array(ty)) => get_struct_params(s_ty, ty), - (StructFieldType::FixedArray(s_ty, _), ParamType::FixedArray(ty, _)) => { - get_struct_params(s_ty, ty) - } - _ => unreachable!(), + (_, ParamType::Tuple(params)) => params, + ( + StructFieldType::Array(s_ty) | StructFieldType::FixedArray(s_ty, _), + ParamType::Array(param) | ParamType::FixedArray(param, _), + ) => get_struct_params(s_ty, param), + _ => unreachable!("Unhandled struct field: {s_ty:?} | {ty:?}"), } } diff --git a/ethers-contract/tests/it/abigen.rs b/ethers-contract/tests/it/abigen.rs index 45ca640a5..348e37908 100644 --- a/ethers-contract/tests/it/abigen.rs +++ b/ethers-contract/tests/it/abigen.rs @@ -8,7 +8,7 @@ use ethers_core::{ }; use ethers_providers::{MockProvider, Provider}; use ethers_solc::Solc; -use std::sync::Arc; +use std::{fmt::Debug, hash::Hash, sync::Arc}; const fn assert_codec() {} const fn assert_tokenizeable() {} @@ -16,7 +16,12 @@ const fn assert_call() {} const fn assert_event() {} const fn assert_clone() {} const fn assert_default() {} -const fn assert_builtin() {} +const fn assert_builtin() {} +const fn assert_struct() +where + T: AbiEncode + AbiDecode + Tokenizable + Clone + Default + Debug + PartialEq + Eq + Hash, +{ +} #[test] fn can_generate_human_readable() { @@ -25,7 +30,7 @@ fn can_generate_human_readable() { r#"[ event ValueChanged(address indexed author, string oldValue, string newValue) ]"#, - event_derives(serde::Deserialize, serde::Serialize) + derives(serde::Deserialize, serde::Serialize) ); assert_eq!("ValueChanged", ValueChangedFilter::name()); assert_eq!("ValueChanged(address,string,string)", ValueChangedFilter::abi_signature()); @@ -43,13 +48,13 @@ fn can_generate_human_readable_multiple() { r#"[ event ValueChanged1(address indexed author, string oldValue, string newValue) ]"#, - event_derives(serde::Deserialize, serde::Serialize); + derives(serde::Deserialize, serde::Serialize); SimpleContract2, r#"[ event ValueChanged2(address indexed author, string oldValue, string newValue) ]"#, - event_derives(serde::Deserialize, serde::Serialize) + derives(serde::Deserialize, serde::Serialize) ); assert_eq!("ValueChanged1", ValueChanged1Filter::name()); assert_eq!("ValueChanged1(address,string,string)", ValueChanged1Filter::abi_signature()); @@ -66,7 +71,7 @@ fn can_generate_structs_readable() { struct Addresses {address[] addr; string s;} event ValueChanged(Value indexed old, Value newValue, Addresses _a) ]"#, - event_derives(serde::Deserialize, serde::Serialize) + derives(serde::Deserialize, serde::Serialize) ); let addr = Addresses { addr: vec!["eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee".parse().unwrap()], @@ -97,7 +102,7 @@ fn can_generate_structs_with_arrays_readable() { struct Addresses {address[] addr; string s;} event ValueChanged(Value indexed old, Value newValue, Addresses[] _a) ]"#, - event_derives(serde::Deserialize, serde::Serialize) + derives(serde::Deserialize, serde::Serialize) ); assert_eq!( "ValueChanged((address,string),(address,string),(address[],string)[])", @@ -113,15 +118,32 @@ fn can_generate_internal_structs() { abigen!( VerifierContract, "ethers-contract/tests/solidity-contracts/verifier_abi.json", - event_derives(serde::Deserialize, serde::Serialize) + derives(serde::Deserialize, serde::Serialize) ); - assert_tokenizeable::(); - assert_tokenizeable::(); - assert_tokenizeable::(); + assert_struct::(); + assert_struct::(); + assert_struct::(); +} - assert_codec::(); - assert_codec::(); - assert_codec::(); +#[test] +fn can_generate_internal_structs_2() { + abigen!(Beefy, "./tests/solidity-contracts/BeefyV1.json"); + assert_struct::(); + assert_struct::(); + assert_struct::(); + assert_struct::(); + + let s = + AuthoritySetCommitment { id: U256::from(1), len: U256::from(2), root: Default::default() }; + let _encoded = AbiEncode::encode(s.clone()); + + let s = BeefyConsensusState { current_authority_set: s, ..Default::default() }; + let _encoded = AbiEncode::encode(s); + + // tuple[][] + let node = ProofNode::default(); + let s = BeefyConsensusProof { authorities_proof: vec![vec![node; 2]; 2], ..Default::default() }; + let _encoded = AbiEncode::encode(s); } #[test] @@ -133,11 +155,11 @@ fn can_generate_internal_structs_multiple() { abigen!( VerifierContract, "ethers-contract/tests/solidity-contracts/verifier_abi.json", - event_derives(serde::Deserialize, serde::Serialize); + derives(serde::Deserialize, serde::Serialize); MyOtherVerifierContract, "ethers-contract/tests/solidity-contracts/verifier_abi.json", - event_derives(serde::Deserialize, serde::Serialize); + derives(serde::Deserialize, serde::Serialize); ); } assert_tokenizeable::(); @@ -207,7 +229,7 @@ fn can_generate_human_readable_with_structs() { function bar(uint256 x, uint256 y, address addr) yeet(uint256,uint256,address) ]"#, - event_derives(serde::Deserialize, serde::Serialize) + derives(serde::Deserialize, serde::Serialize) ); assert_tokenizeable::(); assert_codec::(); diff --git a/ethers-contract/tests/solidity-contracts/BeefyV1.json b/ethers-contract/tests/solidity-contracts/BeefyV1.json new file mode 100644 index 000000000..51507f816 --- /dev/null +++ b/ethers-contract/tests/solidity-contracts/BeefyV1.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"contract ISMPHost","name":"host","type":"address"},{"components":[{"internalType":"uint256","name":"latestHeight","type":"uint256"},{"internalType":"uint256","name":"latestTimestamp","type":"uint256"},{"internalType":"uint256","name":"frozenHeight","type":"uint256"},{"internalType":"bytes32","name":"latestHeadsRoot","type":"bytes32"},{"internalType":"uint256","name":"beefyActivationBlock","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"len","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct AuthoritySetCommitment","name":"currentAuthoritySet","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"len","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct AuthoritySetCommitment","name":"nextAuthoritySet","type":"tuple"}],"internalType":"struct BeefyConsensusState","name":"trustedState","type":"tuple"},{"components":[{"components":[{"components":[{"components":[{"internalType":"bytes2","name":"id","type":"bytes2"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Payload[]","name":"payload","type":"tuple[]"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"validatorSetId","type":"uint256"}],"internalType":"struct Commitment","name":"commitment","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"authorityIndex","type":"uint256"}],"internalType":"struct Signature[]","name":"signatures","type":"tuple[]"}],"internalType":"struct SignedCommitment","name":"signedCommitment","type":"tuple"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"parentNumber","type":"uint256"},{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"len","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct AuthoritySetCommitment","name":"nextAuthoritySet","type":"tuple"},{"internalType":"bytes32","name":"extra","type":"bytes32"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct BeefyMmrLeaf","name":"latestMmrLeaf","type":"tuple"},{"internalType":"bytes32[]","name":"mmrProof","type":"bytes32[]"},{"components":[{"internalType":"uint256","name":"k_index","type":"uint256"},{"internalType":"bytes32","name":"node","type":"bytes32"}],"internalType":"struct ProofNode[][]","name":"authoritiesProof","type":"tuple[][]"},{"internalType":"bytes","name":"header","type":"bytes"},{"internalType":"uint256","name":"headsIndex","type":"uint256"},{"internalType":"bytes[]","name":"extrinsicProof","type":"bytes[]"},{"internalType":"bytes","name":"timestampExtrinsic","type":"bytes"}],"internalType":"struct BeefyConsensusProof","name":"proof","type":"tuple"}],"name":"VerifyConsensus","outputs":[{"components":[{"internalType":"uint256","name":"latestHeight","type":"uint256"},{"internalType":"uint256","name":"latestTimestamp","type":"uint256"},{"internalType":"uint256","name":"frozenHeight","type":"uint256"},{"internalType":"bytes32","name":"latestHeadsRoot","type":"bytes32"},{"internalType":"uint256","name":"beefyActivationBlock","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"len","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct AuthoritySetCommitment","name":"currentAuthoritySet","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"len","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct AuthoritySetCommitment","name":"nextAuthoritySet","type":"tuple"}],"internalType":"struct BeefyConsensusState","name":"","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"internalType":"struct StateCommitment","name":"commitment","type":"tuple"}],"internalType":"struct IntermediateState","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}] diff --git a/ethers-solc/src/resolver/mod.rs b/ethers-solc/src/resolver/mod.rs index 7fd6ed753..16f7d1d61 100644 --- a/ethers-solc/src/resolver/mod.rs +++ b/ethers-solc/src/resolver/mod.rs @@ -903,6 +903,7 @@ impl Node { /// /// This returns an error if the file's version is invalid semver, or is not available such as /// 0.8.20, if the highest available version is `0.8.19` + #[allow(dead_code)] fn check_available_version( &self, all_versions: &[SolcVersion],