Repository: gakonst/ethers-rs
Pull request #2335 (2023-04-07 17:44:16)

fix(abigen): SolStruct derives edge case
<!--
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

From: <https://t.me/ethers_rs/27028>

A struct that contains an array of other structs doesn't add derives when it should. This is because the check [here](https://github.com/gakonst/ethers-rs/blob/1dd35458695e2b967d4c2ff278cc8d0eaadcc9fb/ethers-contract/ethers-contract-abigen/src/util.rs#L235-L239) is incorrect and shouldn't exist.

<!--
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


gakonst: LGTM - needs lint @DaniPopes 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7c2f760d..fe729f3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,16 @@ which is configured [here](./cliff.toml).
 
 Please do not manually edit this file.
 
+## [Unreleased]
+
+### Miscellaneous Tasks
+
+- Fix clippy lints
+
+### Other
+
+- Revert "temp: disable cyclical dep"
+
 ## [2.0.3] - 2023-04-12
 
 ### Bug Fixes
@@ -20,11 +30,69 @@ Please do not manually edit this file.
 - No need to multiply again with `GWEI_TO_WEI_U256` ([#2326](https://github.com/gakonst/ethers-rs/issues/2326))
 - [**breaking**] Change the `GasOracle` fields to be `f64` ([#2325](https://github.com/gakonst/ethers-rs/issues/2325))
 - Docsrs cfg_attr ([#2309](https://github.com/gakonst/ethers-rs/issues/2309))
+
+### Documentation
+
+- Update some doctest examples ([#2339](https://github.com/gakonst/ethers-rs/issues/2339))
+- Add erc20 token transfer example ([#2295](https://github.com/gakonst/ethers-rs/issues/2295))
+
+### Features
+
+- Add Base Goerli chain ([#2338](https://github.com/gakonst/ethers-rs/issues/2338))
+- Very permissive etherscan gwei deser ([#2327](https://github.com/gakonst/ethers-rs/issues/2327))
+- Syn 2.0, merge eip712 crate into ethers-contract-derive ([#2279](https://github.com/gakonst/ethers-rs/issues/2279))
+- Add Settings sanitize ([#2329](https://github.com/gakonst/ethers-rs/issues/2329))
+- `Transaction::decode()` sets the hash ([#2303](https://github.com/gakonst/ethers-rs/issues/2303))
+
+### Miscellaneous Tasks
+
+- Minify test json files ([#2341](https://github.com/gakonst/ethers-rs/issues/2341))
+- Dont retain errors ([#2332](https://github.com/gakonst/ethers-rs/issues/2332))
+- Update solang-parser ([#2334](https://github.com/gakonst/ethers-rs/issues/2334))
+- Update deny config ([#2330](https://github.com/gakonst/ethers-rs/issues/2330))
+- Ignore another rev ([#2311](https://github.com/gakonst/ethers-rs/issues/2311))
+- Use ethers 2 by default when generating bindings ([#2317](https://github.com/gakonst/ethers-rs/issues/2317))
+
+### Other
+
+- Disable cyclical dep
+- Add scroll alpha testnet ([#2316](https://github.com/gakonst/ethers-rs/issues/2316))
+- Add legacy-ws feat to meta crate ([#2328](https://github.com/gakonst/ethers-rs/issues/2328))
+
+### Performance
+
+- Early return in EthCodec derive ([#2314](https://github.com/gakonst/ethers-rs/issues/2314))
+
+## [2.0.2] - 2023-03-28
+
+### Bug Fixes
+
 - Ensure ethers-solc has tokio-rt-multithread
 - Ambiguous_glob_reexports rustc lint ([#2301](https://github.com/gakonst/ethers-rs/issues/2301))
 - Broken eip155 logic in aws signer ([#2300](https://github.com/gakonst/ethers-rs/issues/2300))
 - Enable doc_cfg feature for docsrs ([#2294](https://github.com/gakonst/ethers-rs/issues/2294))
 - Add missing feature on ethers tests
+
+### Depedencies
+
+- Bump generic-array
+
+### Miscellaneous Tasks
+
+- Add eyre dependency ([#2305](https://github.com/gakonst/ethers-rs/issues/2305))
+
+### Other
+
+- Rm celo integration test, install missing solc version ([#2292](https://github.com/gakonst/ethers-rs/issues/2292))
+
+### Testing
+
+- Ensure multithreaded tokio rt
+
+## [2.0.1] - 2023-03-21
+
+### Bug Fixes
+
 - Ethers-contract circular dep on ethers-signers ([#2291](https://github.com/gakonst/ethers-rs/issues/2291))
 - Features ([#2290](https://github.com/gakonst/ethers-rs/issues/2290))
 - Handle all struct field types ([#2289](https://github.com/gakonst/ethers-rs/issues/2289))
@@ -98,7 +166,6 @@ Please do not manually edit this file.
 
 ### Depedencies
 
-- Bump generic-array
 - Bump MSRV from 1.64 to 1.65 ([#2277](https://github.com/gakonst/ethers-rs/issues/2277))
 - Bump and use workspace dependencies ([#2222](https://github.com/gakonst/ethers-rs/issues/2222))
 - Bump crypto deps ([#2260](https://github.com/gakonst/ethers-rs/issues/2260))
@@ -168,8 +235,6 @@ Please do not manually edit this file.
 
 ### Documentation
 
-- Update some doctest examples ([#2339](https://github.com/gakonst/ethers-rs/issues/2339))
-- Add erc20 token transfer example ([#2295](https://github.com/gakonst/ethers-rs/issues/2295))
 - Fix broken links, update documentation ([#2203](https://github.com/gakonst/ethers-rs/issues/2203))
 - Update providers book and examples ([#2098](https://github.com/gakonst/ethers-rs/issues/2098))
 - Rename `event_derives` to `derives` ([#2018](https://github.com/gakonst/ethers-rs/issues/2018))
@@ -181,11 +246,6 @@ Please do not manually edit this file.
 
 ### Features
 
-- Add Base Goerli chain ([#2338](https://github.com/gakonst/ethers-rs/issues/2338))
-- Very permissive etherscan gwei deser ([#2327](https://github.com/gakonst/ethers-rs/issues/2327))
-- Syn 2.0, merge eip712 crate into ethers-contract-derive ([#2279](https://github.com/gakonst/ethers-rs/issues/2279))
-- Add Settings sanitize ([#2329](https://github.com/gakonst/ethers-rs/issues/2329))
-- `Transaction::decode()` sets the hash ([#2303](https://github.com/gakonst/ethers-rs/issues/2303))
 - Improve error diagnostic ([#2280](https://github.com/gakonst/ethers-rs/issues/2280))
 - Roundtrip serde + to/from strings ([#2270](https://github.com/gakonst/ethers-rs/issues/2270))
 - Support empty events ([#2263](https://github.com/gakonst/ethers-rs/issues/2263))
@@ -242,13 +302,6 @@ Please do not manually edit this file.
 
 ### Miscellaneous Tasks
 
-- Minify test json files ([#2341](https://github.com/gakonst/ethers-rs/issues/2341))
-- Dont retain errors ([#2332](https://github.com/gakonst/ethers-rs/issues/2332))
-- Update solang-parser ([#2334](https://github.com/gakonst/ethers-rs/issues/2334))
-- Update deny config ([#2330](https://github.com/gakonst/ethers-rs/issues/2330))
-- Ignore another rev ([#2311](https://github.com/gakonst/ethers-rs/issues/2311))
-- Use ethers 2 by default when generating bindings ([#2317](https://github.com/gakonst/ethers-rs/issues/2317))
-- Add eyre dependency ([#2305](https://github.com/gakonst/ethers-rs/issues/2305))
 - Remove redundant clone
 - Make clippy happy ([#2264](https://github.com/gakonst/ethers-rs/issues/2264))
 - Allow clippy false positive ([#2259](https://github.com/gakonst/ethers-rs/issues/2259))
@@ -282,10 +335,6 @@ Please do not manually edit this file.
 
 ### Other
 
-- Disable cyclical dep
-- Add scroll alpha testnet ([#2316](https://github.com/gakonst/ethers-rs/issues/2316))
-- Add legacy-ws feat to meta crate ([#2328](https://github.com/gakonst/ethers-rs/issues/2328))
-- Rm celo integration test, install missing solc version ([#2292](https://github.com/gakonst/ethers-rs/issues/2292))
 - Prestwich/gas escalator dangle ([#2284](https://github.com/gakonst/ethers-rs/issues/2284))
 - Contracts chapter ([#2281](https://github.com/gakonst/ethers-rs/issues/2281))
 - Revert "chore: remove redundant clone"
@@ -328,7 +377,6 @@ Please do not manually edit this file.
 
 ### Performance
 
-- Early return in EthCodec derive ([#2314](https://github.com/gakonst/ethers-rs/issues/2314))
 - Wrap source content in Arc ([#2138](https://github.com/gakonst/ethers-rs/issues/2138))
 - Avoid unnecessary allocations ([#2046](https://github.com/gakonst/ethers-rs/issues/2046))
 
@@ -360,7 +408,6 @@ Please do not manually edit this file.
 
 ### Testing
 
-- Ensure multithreaded tokio rt
 - Simplify test cleanup ([#2220](https://github.com/gakonst/ethers-rs/issues/2220))
 - Add parse pk test ([#2194](https://github.com/gakonst/ethers-rs/issues/2194))
 - Disable signer integration tests temporarily
diff --git a/Cargo.lock b/Cargo.lock
index 1c2ee748..d8f50ce8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -539,21 +539,19 @@ dependencies = [
 
 [[package]]
 name = "coins-bip39"
-version = "0.8.5"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad2a68a46b9d8cc90484f0689adc0e4c890eb215bf698ae52e5235bb88f40be7"
+checksum = "84f4d04ee18e58356accd644896aeb2094ddeafb6a713e056cef0c0a8e468c15"
 dependencies = [
  "bitvec 0.17.4",
  "coins-bip32",
  "getrandom",
- "hex",
  "hmac 0.12.1",
  "once_cell",
  "pbkdf2 0.12.1",
  "rand",
  "sha2 0.10.6",
  "thiserror",
- "tracing",
 ]
 
 [[package]]
diff --git a/cliff.toml b/cliff.toml
index 01e6475d..e1f1e8ae 100644
--- a/cliff.toml
+++ b/cliff.toml
@@ -20,7 +20,7 @@ Please do not manually edit this file.\n
 # https://tera.netlify.app/docs/#introduction
 body = """
 {% if version %}\
-    ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
+    ## [{{ version | trim_start_matches(pat="ethers-") | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
 {% else %}\
     ## [Unreleased]
 {% endif %}\
@@ -69,12 +69,12 @@ commit_parsers = [
 protect_breaking_commits = true
 # filter out the commits that are not matched by commit parsers
 filter_commits = false
-# glob pattern for matching git tags
+# *glob pattern* for matching git tags
 tag_pattern = "*"
-# regex for skipping tags
+# *regex* for skipping tagged commits entirely
 # skip_tags = "v0.1.0-beta.1"
-# regex for ignoring tags
-ignore_tags = "^ethers.*"
+# *regex* for ignoring tags, but including the commits into the next one
+ignore_tags = "^ethers-.*-.*"
 # sort the tags topologically
 topo_order = false
 # sort the commits inside sections by oldest/newest order
diff --git a/ethers-contract/ethers-contract-abigen/src/util.rs b/ethers-contract/ethers-contract-abigen/src/util.rs
index b4f0acfd..0c6f4756 100644
--- a/ethers-contract/ethers-contract-abigen/src/util.rs
+++ b/ethers-contract/ethers-contract-abigen/src/util.rs
@@ -232,11 +232,12 @@ fn _derive_builtin_traits_struct(
     for (field, ty) in fields.iter().zip(params) {
         match &field.ty {
             FieldType::Struct(s_ty) => {
-                // a tuple here is actually a sol struct so we skip it
-                if !matches!(ty, ParamType::Tuple(_)) {
-                    *def &= can_derive_default(ty);
-                    *others &= can_derive_builtin_traits(ty);
+                // `ty` here can only be `Tuple`, `Array(Tuple)`, or `FixedArray(Tuple(), len)`.
+                // We recurse on the Tuple's fields and check the FixedArray's length.
+                if let StructFieldType::FixedArray(_, len) = s_ty {
+                    *def &= *len <= MAX_SUPPORTED_ARRAY_LEN;
                 }
+
                 let id = s_ty.identifier();
                 // TODO: InternalStructs does not contain this field's ID if the struct and field
                 // are in 2 different modules, like in `can_generate_internal_structs_multiple`
diff --git a/ethers-signers/Cargo.toml b/ethers-signers/Cargo.toml
index e6a77af1..3d1acf36 100644
--- a/ethers-signers/Cargo.toml
+++ b/ethers-signers/Cargo.toml
@@ -28,7 +28,7 @@ ethers-core.workspace = true
 
 # crypto
 coins-bip32 = "0.8.3"
-coins-bip39 = "0.8.5"
+coins-bip39 = "0.8.6"
 elliptic-curve.workspace = true
 sha2.workspace = true
 rand.workspace = true


Test patch:
diff --git a/ethers-contract/tests/it/abigen.rs b/ethers-contract/tests/it/abigen.rs
index 348e3790..7a1cd79b 100644
--- a/ethers-contract/tests/it/abigen.rs
+++ b/ethers-contract/tests/it/abigen.rs
@@ -766,6 +766,15 @@ fn can_generate_large_output_struct() {
     let _r = GetByIdReturn(Info::default());
 }
 
+#[test]
+fn can_generate_large_structs() {
+    abigen!(LargeStructs, "ethers-contract/tests/solidity-contracts/LargeStructs.json");
+
+    assert_struct::<PoolStorage>();
+    assert_struct::<AssetStorage>();
+    assert_struct::<ChainStorage>();
+}
+
 #[test]
 fn can_generate_complex_function() {
     abigen!(
diff --git a/ethers-contract/tests/solidity-contracts/LargeStructs.json b/ethers-contract/tests/solidity-contracts/LargeStructs.json
new file mode 100644
index 00000000..3e46d7d1
--- /dev/null
+++ b/ethers-contract/tests/solidity-contracts/LargeStructs.json
@@ -0,0 +1,1 @@
+[{"inputs":[],"name":"getChainStorage","outputs":[{"components":[{"components":[{"internalType":"uint32","name":"shortFundingBaseRate8H","type":"uint32"},{"internalType":"uint32","name":"shortFundingLimitRate8H","type":"uint32"},{"internalType":"uint32","name":"fundingInterval","type":"uint32"},{"internalType":"uint32","name":"liquidityBaseFeeRate","type":"uint32"},{"internalType":"uint32","name":"liquidityDynamicFeeRate","type":"uint32"},{"internalType":"uint96","name":"mlpPriceLowerBound","type":"uint96"},{"internalType":"uint96","name":"mlpPriceUpperBound","type":"uint96"},{"internalType":"uint32","name":"lastFundingTime","type":"uint32"},{"internalType":"uint32","name":"sequence","type":"uint32"},{"internalType":"uint32","name":"strictStableDeviation","type":"uint32"}],"internalType":"struct IReader.PoolStorage","name":"pool","type":"tuple"},{"components":[{"internalType":"bytes32","name":"symbol","type":"bytes32"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"muxTokenAddress","type":"address"},{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint56","name":"flags","type":"uint56"},{"internalType":"uint32","name":"initialMarginRate","type":"uint32"},{"internalType":"uint32","name":"maintenanceMarginRate","type":"uint32"},{"internalType":"uint32","name":"positionFeeRate","type":"uint32"},{"internalType":"uint32","name":"liquidationFeeRate","type":"uint32"},{"internalType":"uint32","name":"minProfitRate","type":"uint32"},{"internalType":"uint32","name":"minProfitTime","type":"uint32"},{"internalType":"uint96","name":"maxLongPositionSize","type":"uint96"},{"internalType":"uint96","name":"maxShortPositionSize","type":"uint96"},{"internalType":"uint32","name":"spotWeight","type":"uint32"},{"internalType":"uint32","name":"longFundingBaseRate8H","type":"uint32"},{"internalType":"uint32","name":"longFundingLimitRate8H","type":"uint32"},{"internalType":"uint8","name":"referenceOracleType","type":"uint8"},{"internalType":"address","name":"referenceOracle","type":"address"},{"internalType":"uint32","name":"referenceDeviation","type":"uint32"},{"internalType":"uint32","name":"halfSpread","type":"uint32"},{"internalType":"uint128","name":"longCumulativeFundingRate","type":"uint128"},{"internalType":"uint128","name":"shortCumulativeFunding","type":"uint128"},{"internalType":"uint96","name":"spotLiquidity","type":"uint96"},{"internalType":"uint96","name":"credit","type":"uint96"},{"internalType":"uint96","name":"totalLongPosition","type":"uint96"},{"internalType":"uint96","name":"totalShortPosition","type":"uint96"},{"internalType":"uint96","name":"averageLongPrice","type":"uint96"},{"internalType":"uint96","name":"averageShortPrice","type":"uint96"},{"internalType":"uint128","name":"collectedFee","type":"uint128"},{"internalType":"uint256","name":"deduct","type":"uint256"}],"internalType":"struct IReader.AssetStorage[]","name":"assets","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"dexId","type":"uint8"},{"internalType":"uint8","name":"dexType","type":"uint8"},{"internalType":"uint8[]","name":"assetIds","type":"uint8[]"},{"internalType":"uint32[]","name":"assetWeightInDEX","type":"uint32[]"},{"internalType":"uint256[]","name":"totalSpotInDEX","type":"uint256[]"},{"internalType":"uint32","name":"dexWeight","type":"uint32"},{"internalType":"uint256","name":"dexLPBalance","type":"uint256"},{"internalType":"uint256[]","name":"liquidityBalance","type":"uint256[]"}],"internalType":"struct IReader.DexStorage[]","name":"dexes","type":"tuple[]"},{"internalType":"uint32","name":"liquidityLockPeriod","type":"uint32"},{"internalType":"uint32","name":"marketOrderTimeout","type":"uint32"},{"internalType":"uint32","name":"maxLimitOrderTimeout","type":"uint32"},{"internalType":"uint256","name":"lpDeduct","type":"uint256"},{"internalType":"uint256","name":"stableDeduct","type":"uint256"},{"internalType":"bool","name":"isPositionOrderPaused","type":"bool"},{"internalType":"bool","name":"isLiquidityOrderPaused","type":"bool"}],"internalType":"struct IReader.ChainStorage","name":"chain","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"orderIds","type":"uint64[]"}],"name":"getOrders","outputs":[{"internalType":"bytes32[3][]","name":"orders","type":"bytes32[3][]"},{"internalType":"bool[]","name":"isExist","type":"bool[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"subAccountIds","type":"bytes32[]"}],"name":"getSubAccounts","outputs":[{"components":[{"internalType":"uint96","name":"collateral","type":"uint96"},{"internalType":"uint96","name":"size","type":"uint96"},{"internalType":"uint32","name":"lastIncreasedTime","type":"uint32"},{"internalType":"uint96","name":"entryPrice","type":"uint96"},{"internalType":"uint128","name":"entryFunding","type":"uint128"}],"internalType":"struct IReader.SubAccountState[]","name":"subAccounts","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"subAccountIds","type":"bytes32[]"},{"internalType":"uint64[]","name":"orderIds","type":"uint64[]"}],"name":"getSubAccountsAndOrders","outputs":[{"components":[{"internalType":"uint96","name":"collateral","type":"uint96"},{"internalType":"uint96","name":"size","type":"uint96"},{"internalType":"uint32","name":"lastIncreasedTime","type":"uint32"},{"internalType":"uint96","name":"entryPrice","type":"uint96"},{"internalType":"uint128","name":"entryFunding","type":"uint128"}],"internalType":"struct IReader.SubAccountState[]","name":"subAccounts","type":"tuple[]"},{"internalType":"bytes32[3][]","name":"orders","type":"bytes32[3][]"},{"internalType":"bool[]","name":"isOrderExist","type":"bool[]"}],"stateMutability":"pure","type":"function"}]