Repository: gakonst/ethers-rs
Pull request #2290 (2023-03-21 15:54:14)

fix(solc): features
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.

Bug fixes and new features should include tests.

Contributors guide: https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md

The contributors guide includes instructions for running rustfmt and building the
documentation.
-->

## Motivation

removed by accident during refactoring

<!--
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
-->

## Solution

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

## PR Checklist

-   [ ] Added Tests
-   [ ] Added Documentation
-   [ ] Breaking changes



Patch:
diff --git a/ethers-contract/ethers-contract-abigen/src/util.rs b/ethers-contract/ethers-contract-abigen/src/util.rs
index e9453b5e..b4f0acfd 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-solc/Cargo.toml b/ethers-solc/Cargo.toml
index dd8a2a5c..0943167f 100644
--- a/ethers-solc/Cargo.toml
+++ b/ethers-solc/Cargo.toml
@@ -111,14 +111,14 @@ async = [
     "futures-util",
     "criterion/async_tokio",
 ]
-svm-solc = ["svm-builds", "sha2"]
+svm-solc = ["svm", "svm-builds", "sha2"]
 
 # Utilities for creating and testing project workspaces
 project-util = ["tempfile", "fs_extra", "rand"]
 
 tests = []
-openssl = ["svm/openssl"]
-rustls = ["svm/rustls"]
+openssl = ["svm?/openssl"]
+rustls = ["svm?/rustls"]
 
 # Deprecated
 asm = []
diff --git a/ethers-solc/src/resolver/mod.rs b/ethers-solc/src/resolver/mod.rs
index 7fd6ed75..16f7d1d6 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],


Test patch:
diff --git a/ethers-contract/tests/it/abigen.rs b/ethers-contract/tests/it/abigen.rs
index 45ca640a..348e3790 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<T: AbiDecode + AbiEncode>() {}
 const fn assert_tokenizeable<T: Tokenizable>() {}
@@ -16,7 +16,12 @@ const fn assert_call<T: AbiEncode + AbiDecode + Default + Tokenizable>() {}
 const fn assert_event<T: EthEvent>() {}
 const fn assert_clone<T: Clone>() {}
 const fn assert_default<T: Default>() {}
-const fn assert_builtin<T: std::fmt::Debug + PartialEq + Eq + std::hash::Hash>() {}
+const fn assert_builtin<T: Debug + PartialEq + Eq + Hash>() {}
+const fn assert_struct<T>()
+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::<VerifyingKey>();
-    assert_tokenizeable::<G1Point>();
-    assert_tokenizeable::<G2Point>();
+    assert_struct::<VerifyingKey>();
+    assert_struct::<G1Point>();
+    assert_struct::<G2Point>();
+}
 
-    assert_codec::<VerifyingKey>();
-    assert_codec::<G1Point>();
-    assert_codec::<G2Point>();
+#[test]
+fn can_generate_internal_structs_2() {
+    abigen!(Beefy, "./tests/solidity-contracts/BeefyV1.json");
+    assert_struct::<AuthoritySetCommitment>();
+    assert_struct::<BeefyConsensusState>();
+    assert_struct::<ProofNode>();
+    assert_struct::<BeefyConsensusProof>();
+
+    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::<VerifyingKey>();
@@ -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::<Foo>();
     assert_codec::<Foo>();
diff --git a/ethers-contract/tests/solidity-contracts/BeefyV1.json b/ethers-contract/tests/solidity-contracts/BeefyV1.json
new file mode 100644
index 00000000..51507f81
--- /dev/null
+++ b/ethers-contract/tests/solidity-contracts/BeefyV1.json
@@ -0,0 +1,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"}]