Repository: gakonst/ethers-rs
Pull request #2330 (2023-04-06 10:34:25)

chore: update deny config
<!--
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

- Remove outdated exceptions and `[[license.clarify]]`
- Make config more strict for wildcard and git dependencies
  - bad practice, git dependencies are not allowed when published so doesn't hurt adding an extra check
- Add `MPL-2.0` to license allow list since it generates a warning for being copy-left
  - Looked to other crates using the `webpki-roots` crate: <https://github.com/hyperium/tonic/blob/master/deny.toml>

The only remaining warnings are for duplicate crates


<!--
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/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e63f25d2..aea50aa1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -31,19 +31,19 @@ jobs:
                     - name: all features
                       flags: --workspace --all-features
                 include:
-                    # not workspace because compiling examples fails for no reason in CI,
+                    # not workspace because compiling examples fails for no reason in CI
                     - os: windows-latest
                       flags:
                           name: no default features
-                          flags: -p ethers --no-default-features
+                          flags: --no-default-features
                     - os: windows-latest
                       flags:
                           name: default features
-                          flags: -p ethers
+                          flags: ""
                     - os: windows-latest
                       flags:
                           name: all features
-                          flags: -p ethers --all-features
+                          flags: --all-features
         steps:
             - uses: actions/checkout@v3
             - uses: dtolnay/rust-toolchain@stable
@@ -85,16 +85,17 @@ jobs:
             - name: live tests
               run: cargo test -p ethers-etherscan --test it
 
-    live-tests:
-        name: live tests
-        runs-on: ubuntu-latest
-        concurrency: live-tests-${{ github.head_ref || github.run_id }}
-        steps:
-            - uses: actions/checkout@v3
-            - uses: dtolnay/rust-toolchain@stable
-            - uses: Swatinem/rust-cache@v2
-            - name: live tests
-              run: cargo test -p ethers --all-features
+    # TODO: Create a new `ethers-tests` crate in the workspace for live tests.
+    # live-tests:
+    #     name: live tests
+    #     runs-on: ubuntu-latest
+    #     concurrency: live-tests-${{ github.head_ref || github.run_id }}
+    #     steps:
+    #         - uses: actions/checkout@v3
+    #         - uses: dtolnay/rust-toolchain@stable
+    #         - uses: Swatinem/rust-cache@v2
+    #         - name: live tests
+    #           run: cargo test -p ethers-tests --all-features
 
     # TODO: [#2191](https://github.com/gakonst/ethers-rs/issues/2191)
     # feature-checks:
diff --git a/.github/workflows/deps.yml b/.github/workflows/deps.yml
index 2cd81aea..aa4dc847 100644
--- a/.github/workflows/deps.yml
+++ b/.github/workflows/deps.yml
@@ -8,27 +8,14 @@ on:
         branches: [master]
         paths: [Cargo.lock]
 
-env:
-    RUSTFLAGS: -D warnings
-    CARGO_TERM_COLOR: always
-
 concurrency: deps-${{ github.head_ref || github.run_id }}
 
 jobs:
     deny:
-        name: deny (${{ matrix.checks }})
+        name: deny
         runs-on: ubuntu-latest
-        strategy:
-            fail-fast: false
-            matrix:
-                checks:
-                    - advisories
-                    - bans licenses sources
-
-        continue-on-error: ${{ matrix.checks == 'advisories' }}
-
         steps:
             - uses: actions/checkout@v3
             - uses: EmbarkStudios/cargo-deny-action@v1
               with:
-                  command: check ${{ matrix.checks }}
+                  command: check all
diff --git a/Cargo.lock b/Cargo.lock
index dfcced99..7611919b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -20,9 +20,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "aead"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
 dependencies = [
  "crypto-common",
  "generic-array",
@@ -77,9 +77,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
 
 [[package]]
 name = "anyhow"
-version = "1.0.69"
+version = "1.0.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
+checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
 
 [[package]]
 name = "arrayvec"
@@ -98,13 +98,13 @@ dependencies = [
 
 [[package]]
 name = "async-trait"
-version = "0.1.66"
+version = "0.1.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b84f9ebcc6c1f5b8cb160f6990096a5c127f423fcb6e1ccc46c370cbdfb75dfc"
+checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -138,7 +138,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -209,9 +209,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.0.1"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5dd14596c0e5b954530d0e6f1fd99b89c03e313aa2086e8da4303701a09e1cf"
+checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3"
 
 [[package]]
 name = "bitvec"
@@ -255,9 +255,9 @@ dependencies = [
 
 [[package]]
 name = "block-padding"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a90ec2df9600c28a01c56c4784c9207a96d2451833aeceb8cc97e4c9548bb78"
+checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
 dependencies = [
  "generic-array",
 ]
@@ -345,9 +345,9 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.15.3"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07"
+checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
 dependencies = [
  "camino",
  "cargo-platform",
@@ -485,7 +485,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -539,9 +539,9 @@ dependencies = [
 
 [[package]]
 name = "coins-bip39"
-version = "0.8.3"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efb68f3b6c3fee83828ecd8d463f360a397c32aaeb35bd931c01e5ddf5631c69"
+checksum = "ad2a68a46b9d8cc90484f0689adc0e4c890eb215bf698ae52e5235bb88f40be7"
 dependencies = [
  "bitvec 0.17.4",
  "coins-bip32",
@@ -651,15 +651,6 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
 
-[[package]]
-name = "convert_case"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
-dependencies = [
- "unicode-segmentation",
-]
-
 [[package]]
 name = "core-foundation"
 version = "0.9.3"
@@ -672,15 +663,15 @@ dependencies = [
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
+checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181"
 dependencies = [
  "libc",
 ]
@@ -821,7 +812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
 dependencies = [
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -850,9 +841,9 @@ dependencies = [
 
 [[package]]
 name = "cxx"
-version = "1.0.92"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72"
+checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93"
 dependencies = [
  "cc",
  "cxxbridge-flags",
@@ -862,9 +853,9 @@ dependencies = [
 
 [[package]]
 name = "cxx-build"
-version = "1.0.92"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613"
+checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b"
 dependencies = [
  "cc",
  "codespan-reporting",
@@ -872,24 +863,24 @@ dependencies = [
  "proc-macro2",
  "quote",
  "scratch",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
 name = "cxxbridge-flags"
-version = "1.0.92"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97"
+checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb"
 
 [[package]]
 name = "cxxbridge-macro"
-version = "1.0.92"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56"
+checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -916,9 +907,9 @@ dependencies = [
 
 [[package]]
 name = "der"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc906908ea6458456e5eaa160a9c08543ec3d1e6f71e2235cedd660cb65f9df0"
+checksum = "19c5cb402c5c958281c7c0702edea7b780d03b86b606497ca3a10fcd3fc393ac"
 dependencies = [
  "const-oid",
  "zeroize",
@@ -932,7 +923,7 @@ checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -969,6 +960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
  "block-buffer 0.10.4",
+ "const-oid",
  "crypto-common",
  "subtle",
 ]
@@ -1002,11 +994,12 @@ checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c"
 
 [[package]]
 name = "ecdsa"
-version = "0.16.1"
+version = "0.16.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1b0a1222f8072619e8a6b667a854020a03d363738303203c09468b3424a420a"
+checksum = "106401dadc137d05cb0d4ab4d42be089746aefdfe8992df4d0edcf351c16ddca"
 dependencies = [
  "der",
+ "digest 0.10.6",
  "elliptic-curve",
  "rfc6979",
  "signature",
@@ -1014,9 +1007,9 @@ dependencies = [
 
 [[package]]
 name = "ed25519"
-version = "2.2.0"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be522bee13fa6d8059f4903a4084aa3bd50725e18150202f0238deb615cd6371"
+checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963"
 dependencies = [
  "pkcs8",
  "signature",
@@ -1044,9 +1037,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
 
 [[package]]
 name = "elliptic-curve"
-version = "0.13.2"
+version = "0.13.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ea5a92946e8614bb585254898bb7dd1ddad241ace60c52149e3765e34cc039d"
+checksum = "22cdacd4d6ed3f9b98680b679c0e52a823b8a2c7a97358d508fe247f2180c282"
 dependencies = [
  "base16ct",
  "crypto-bigint",
@@ -1063,9 +1056,9 @@ dependencies = [
 
 [[package]]
 name = "ena"
-version = "0.14.1"
+version = "0.14.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
+checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
 dependencies = [
  "log",
 ]
@@ -1118,13 +1111,13 @@ dependencies = [
 
 [[package]]
 name = "errno"
-version = "0.2.8"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0"
 dependencies = [
  "errno-dragonfly",
  "libc",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -1240,8 +1233,8 @@ dependencies = [
  "ethers-contract-abigen",
  "ethers-contract-derive",
  "ethers-core",
- "ethers-derive-eip712",
  "ethers-providers",
+ "ethers-signers",
  "ethers-solc",
  "futures-util",
  "hex",
@@ -1272,7 +1265,7 @@ dependencies = [
  "reqwest",
  "serde",
  "serde_json",
- "syn",
+ "syn 2.0.13",
  "tempfile",
  "tokio",
  "toml",
@@ -1284,12 +1277,14 @@ dependencies = [
 name = "ethers-contract-derive"
 version = "2.0.2"
 dependencies = [
+ "Inflector",
  "ethers-contract-abigen",
  "ethers-core",
  "hex",
  "proc-macro2",
  "quote",
- "syn",
+ "serde_json",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -1301,7 +1296,6 @@ dependencies = [
  "bytes",
  "cargo_metadata",
  "chrono",
- "convert_case",
  "elliptic-curve",
  "ethabi",
  "generic-array",
@@ -1312,31 +1306,18 @@ dependencies = [
  "num_enum",
  "once_cell",
  "open-fastrlp",
- "proc-macro2",
  "rand",
  "rlp",
  "serde",
  "serde_json",
  "strum",
- "syn",
+ "syn 2.0.13",
  "tempfile",
  "thiserror",
  "tiny-keccak",
  "unicode-xid",
 ]
 
-[[package]]
-name = "ethers-derive-eip712"
-version = "2.0.2"
-dependencies = [
- "ethers-contract-derive",
- "ethers-core",
- "hex",
- "quote",
- "serde_json",
- "syn",
-]
-
 [[package]]
 name = "ethers-etherscan"
 version = "2.0.2"
@@ -1436,7 +1417,6 @@ dependencies = [
  "eth-keystore",
  "ethers-contract-derive",
  "ethers-core",
- "ethers-derive-eip712",
  "futures-executor",
  "futures-util",
  "hex",
@@ -1667,9 +1647,9 @@ dependencies = [
 
 [[package]]
 name = "fiat-crypto"
-version = "0.1.19"
+version = "0.1.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955"
+checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
 
 [[package]]
 name = "fixed-hash"
@@ -1753,9 +1733,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
 
 [[package]]
 name = "futures"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549"
+checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -1768,9 +1748,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
+checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -1778,15 +1758,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
+checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83"
+checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -1795,9 +1775,9 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
+checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
 
 [[package]]
 name = "futures-locks"
@@ -1811,26 +1791,26 @@ dependencies = [
 
 [[package]]
 name = "futures-macro"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
+checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
+checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
 
 [[package]]
 name = "futures-task"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879"
+checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
 
 [[package]]
 name = "futures-timer"
@@ -1844,9 +1824,9 @@ dependencies = [
 
 [[package]]
 name = "futures-util"
-version = "0.3.27"
+version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
+checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -2000,9 +1980,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
 [[package]]
 name = "hex-literal"
-version = "0.3.4"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
+checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
 
 [[package]]
 name = "hidapi-rusb"
@@ -2138,16 +2118,16 @@ dependencies = [
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.53"
+version = "0.1.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
+checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
  "wasm-bindgen",
- "winapi",
+ "windows",
 ]
 
 [[package]]
@@ -2205,7 +2185,7 @@ checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -2216,9 +2196,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indexmap"
-version = "1.9.2"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
  "hashbrown",
@@ -2257,25 +2237,26 @@ dependencies = [
 
 [[package]]
 name = "io-lifetimes"
-version = "1.0.6"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3"
+checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
 dependencies = [
+ "hermit-abi 0.3.1",
  "libc",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "ipnet"
-version = "2.7.1"
+version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
+checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
 
 [[package]]
 name = "is-terminal"
-version = "0.4.4"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
+checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8"
 dependencies = [
  "hermit-abi 0.3.1",
  "io-lifetimes",
@@ -2341,15 +2322,15 @@ dependencies = [
 
 [[package]]
 name = "lalrpop"
-version = "0.19.8"
+version = "0.19.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823"
+checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87"
 dependencies = [
  "ascii-canvas",
- "atty",
  "bit-set",
  "diff",
  "ena",
+ "is-terminal",
  "itertools",
  "lalrpop-util",
  "petgraph",
@@ -2364,9 +2345,9 @@ dependencies = [
 
 [[package]]
 name = "lalrpop-util"
-version = "0.19.8"
+version = "0.19.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4"
+checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd"
 dependencies = [
  "regex",
 ]
@@ -2379,9 +2360,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.140"
+version = "0.2.141"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
+checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
 
 [[package]]
 name = "libm"
@@ -2412,9 +2393,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.1.4"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
 
 [[package]]
 name = "lock_api"
@@ -2496,9 +2477,9 @@ dependencies = [
 
 [[package]]
 name = "mime"
-version = "0.3.16"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
 
 [[package]]
 name = "miniz_oxide"
@@ -2600,23 +2581,23 @@ dependencies = [
 
 [[package]]
 name = "num_enum"
-version = "0.5.11"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
+checksum = "a0fa9d8a04aa0af7b5845b514a828f829ae3f0ec3f60d9842e1dfaeb49a0e68b"
 dependencies = [
  "num_enum_derive",
 ]
 
 [[package]]
 name = "num_enum_derive"
-version = "0.5.11"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
+checksum = "3e51dcc6bafb7f3ac88b65d2ad21f4b53d878e496712060e23011862ebd2d2d1"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -2665,14 +2646,14 @@ dependencies = [
  "bytes",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
 name = "openssl"
-version = "0.10.46"
+version = "0.10.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd2523381e46256e40930512c7fd25562b9eae4812cb52078f155e87217c9d1e"
+checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33"
 dependencies = [
  "bitflags 1.3.2",
  "cfg-if",
@@ -2685,13 +2666,13 @@ dependencies = [
 
 [[package]]
 name = "openssl-macros"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -2702,11 +2683,10 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.81"
+version = "0.9.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "176be2629957c157240f68f61f2d0053ad3a4ecfdd9ebf1e6521d18d9635cf67"
+checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
 dependencies = [
- "autocfg",
  "cc",
  "libc",
  "pkg-config",
@@ -2715,9 +2695,9 @@ dependencies = [
 
 [[package]]
 name = "os_str_bytes"
-version = "6.4.1"
+version = "6.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
+checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
 
 [[package]]
 name = "output_vt100"
@@ -2791,7 +2771,7 @@ dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -2812,7 +2792,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "smallvec",
  "windows-sys 0.45.0",
 ]
@@ -2912,7 +2892,7 @@ dependencies = [
  "phf_shared 0.11.1",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -2956,7 +2936,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -2973,9 +2953,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "pkcs8"
-version = "0.10.1"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d2820d87d2b008616e5c27212dd9e0e694fb4c6b522de06094106813328cb49"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
 dependencies = [
  "der",
  "spki",
@@ -3047,12 +3027,12 @@ dependencies = [
 
 [[package]]
 name = "prettyplease"
-version = "0.1.25"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86"
+checksum = "1ceca8aaf45b5c46ec7ed39fff75f57290368c1846d33d24a122ca81416ab058"
 dependencies = [
  "proc-macro2",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -3097,7 +3077,7 @@ dependencies = [
  "proc-macro-error-attr",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
  "version_check",
 ]
 
@@ -3114,9 +3094,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.52"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
 dependencies = [
  "unicode-ident",
 ]
@@ -3209,6 +3189,15 @@ dependencies = [
  "bitflags 1.3.2",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
 [[package]]
 name = "redox_users"
 version = "0.4.3"
@@ -3216,15 +3205,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
 dependencies = [
  "getrandom",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "thiserror",
 ]
 
 [[package]]
 name = "regex"
-version = "1.7.1"
+version = "1.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
+checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -3242,15 +3231,15 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.28"
+version = "0.6.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 
 [[package]]
 name = "reqwest"
-version = "0.11.14"
+version = "0.11.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9"
+checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254"
 dependencies = [
  "base64 0.21.0",
  "bytes",
@@ -3341,14 +3330,14 @@ checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
 name = "rusb"
-version = "0.9.1"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "703aa035c21c589b34fb5136b12e68fc8dcf7ea46486861381361dd8ebf5cee0"
+checksum = "44a8c36914f9b1a3be712c1dfa48c9b397131f9a75707e570a391735f785c5d1"
 dependencies = [
  "libc",
  "libusb1-sys",
@@ -3454,9 +3443,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.36.9"
+version = "0.37.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc"
+checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d"
 dependencies = [
  "bitflags 1.3.2",
  "errno",
@@ -3531,9 +3520,9 @@ dependencies = [
 
 [[package]]
 name = "scale-info"
-version = "2.3.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608"
+checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97"
 dependencies = [
  "cfg-if",
  "derive_more",
@@ -3543,14 +3532,14 @@ dependencies = [
 
 [[package]]
 name = "scale-info-derive"
-version = "2.3.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c"
+checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -3662,9 +3651,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
 
 [[package]]
 name = "serde"
-version = "1.0.156"
+version = "1.0.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4"
+checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
 dependencies = [
  "serde_derive",
 ]
@@ -3682,20 +3671,20 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.156"
+version = "1.0.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d"
+checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.94"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
+checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
 dependencies = [
  "itoa",
  "ryu",
@@ -3704,9 +3693,9 @@ dependencies = [
 
 [[package]]
 name = "serde_path_to_error"
-version = "0.1.10"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db0969fff533976baadd92e08b1d102c5a3d8a8049eadfd69d4d1e3c5b2ed189"
+checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0"
 dependencies = [
  "serde",
 ]
@@ -3734,9 +3723,9 @@ dependencies = [
 
 [[package]]
 name = "serial_test"
-version = "1.0.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "538c30747ae860d6fb88330addbbd3e0ddbe46d662d032855596d8a8ca260611"
+checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d"
 dependencies = [
  "dashmap",
  "futures",
@@ -3748,13 +3737,13 @@ dependencies = [
 
 [[package]]
 name = "serial_test_derive"
-version = "1.0.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "079a83df15f85d89a68d64ae1238f142f172b1fa915d0d76b26a7cba1b659a69"
+checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -3828,9 +3817,9 @@ dependencies = [
 
 [[package]]
 name = "signature"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
 dependencies = [
  "digest 0.10.6",
  "rand_core",
@@ -3845,7 +3834,7 @@ checksum = "ede930749cca4e3a3df7e37b5f0934a55693e01d028d7a4e506b44cbc059d95a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -3900,9 +3889,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
 
 [[package]]
 name = "spki"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0445c905640145c7ea8c1993555957f65e7c46d0535b91ba501bc9bfc85522f"
+checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e"
 dependencies = [
  "base64ct",
  "der",
@@ -3952,7 +3941,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rustversion",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -4017,15 +4006,14 @@ dependencies = [
 ]
 
 [[package]]
-name = "synstructure"
-version = "0.12.6"
+name = "syn"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
+checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
- "unicode-xid",
+ "unicode-ident",
 ]
 
 [[package]]
@@ -4036,15 +4024,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
 
 [[package]]
 name = "tempfile"
-version = "3.4.0"
+version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
+checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall",
+ "redox_syscall 0.3.5",
  "rustix",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -4085,22 +4073,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
 
 [[package]]
 name = "thiserror"
-version = "1.0.39"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.39"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -4175,14 +4163,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.26.0"
+version = "1.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
+checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001"
 dependencies = [
  "autocfg",
  "bytes",
  "libc",
- "memchr",
  "mio",
  "num_cpus",
  "parking_lot",
@@ -4195,13 +4182,13 @@ dependencies = [
 
 [[package]]
 name = "tokio-macros"
-version = "1.8.2"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
+checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -4280,9 +4267,9 @@ dependencies = [
 
 [[package]]
 name = "toml_edit"
-version = "0.19.7"
+version = "0.19.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274"
+checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
 dependencies = [
  "indexmap",
  "serde",
@@ -4317,7 +4304,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -4389,7 +4376,7 @@ checksum = "258bc1c4f8e2e73a977812ab339d503e6feeb92700f6d07a6de4d321522d5c08"
 dependencies = [
  "lazy_static",
  "quote",
- "syn",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -4455,9 +4442,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.11"
+version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c"
+checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
 
 [[package]]
 name = "unicode-ident"
@@ -4474,12 +4461,6 @@ dependencies = [
  "tinyvec",
 ]
 
-[[package]]
-name = "unicode-segmentation"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
-
 [[package]]
 name = "unicode-width"
 version = "0.1.10"
@@ -4601,7 +4582,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
  "wasm-bindgen-shared",
 ]
 
@@ -4635,7 +4616,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.109",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -4730,19 +4711,28 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
+[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
 ]
 
 [[package]]
@@ -4751,7 +4741,16 @@ version = "0.45.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.0",
 ]
 
 [[package]]
@@ -4760,13 +4759,28 @@ version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
 ]
 
 [[package]]
@@ -4775,47 +4789,89 @@ version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
 
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
 [[package]]
 name = "windows_i686_gnu"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
 
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
 [[package]]
 name = "windows_i686_msvc"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
 
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
 
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
 
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+
 [[package]]
 name = "winnow"
-version = "0.3.6"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966"
+checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
 dependencies = [
  "memchr",
 ]
@@ -4876,7 +4932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f6a89568917376ff46a3de7bd0abdac47e9cc8ded4e1018e4a36d071d43a54ad"
 dependencies = [
  "aes 0.8.2",
- "bitflags 2.0.1",
+ "bitflags 2.1.0",
  "cbc",
  "ccm",
  "cmac",
@@ -4905,23 +4961,22 @@ dependencies = [
 
 [[package]]
 name = "zeroize"
-version = "1.5.7"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
+checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
 dependencies = [
  "zeroize_derive",
 ]
 
 [[package]]
 name = "zeroize_derive"
-version = "1.3.3"
+version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
- "synstructure",
+ "syn 2.0.13",
 ]
 
 [[package]]
@@ -4965,9 +5020,9 @@ dependencies = [
 
 [[package]]
 name = "zstd-sys"
-version = "2.0.7+zstd.1.5.4"
+version = "2.0.8+zstd.1.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5"
+checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
 dependencies = [
  "cc",
  "libc",
diff --git a/Cargo.toml b/Cargo.toml
index aedc4933..cb839738 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -76,29 +76,28 @@ ethers-solc = { version = "2.0.2", path = "ethers-solc", default-features = fals
 
 ethers-contract-abigen = { version = "2.0.2", path = "ethers-contract/ethers-contract-abigen", default-features = false }
 ethers-contract-derive = { version = "2.0.2", path = "ethers-contract/ethers-contract-derive", default-features = false }
-ethers-derive-eip712 = { version = "2.0.2", path = "ethers-core/ethers-derive-eip712", default-features = false }
 
 # async / async utils
-tokio = "1.26"
+tokio = "1.27"
 tokio-tungstenite = { version = "0.18.0", default-features = false }
-futures = { version = "0.3.27", default-features = false, features = ["std"] }
-futures-core = "0.3.27"
-futures-util = "0.3.27"
-futures-executor = "0.3.27"
-futures-channel = "0.3.27"
+futures = { version = "0.3.28", default-features = false, features = ["std"] }
+futures-core = "0.3.28"
+futures-util = "0.3.28"
+futures-executor = "0.3.28"
+futures-channel = "0.3.28"
 futures-locks = { version = "0.7.1", default-features = false }
 futures-timer = { version = "3.0.2", default-features = false, features = ["wasm-bindgen"] }
 pin-project = "1.0"
-reqwest = { version = "0.11.14", default-features = false }
+reqwest = { version = "0.11.16", default-features = false }
 url = { version = "2.3", default-features = false }
 
 # crypto
-elliptic-curve = { version = "0.13.2", default-features = false }
-generic-array = { version = "0.14.6", default-features = false }
+elliptic-curve = { version = "0.13.3", default-features = false }
+generic-array = { version = "0.14.7", default-features = false }
 k256 = { version = "0.13.0", default-features = false, features = ["ecdsa", "std"] }
 sha2 = { version = "0.10.6", default-features = false }
 tiny-keccak = { version = "2.0.2", default-features = false }
-spki = { version = "0.7.0", default-features = false }
+spki = { version = "0.7.1", default-features = false }
 
 # serde
 serde = "1.0"
@@ -107,21 +106,22 @@ serde_json = "1.0"
 # macros
 proc-macro2 = "1.0"
 quote = "1.0"
-syn = { version = "1.0", features = ["extra-traits"] }
-async-trait = "0.1.66"
+syn = { version = "2.0", features = ["extra-traits"] }
+async-trait = "0.1.68"
 auto_impl = "1.0"
 
 # misc
+Inflector = "0.11"
 thiserror = "1.0"
 once_cell = "1.17"
 hex = "0.4"
 eyre = "0.6"
-tempfile = "3.4"
+tempfile = "3.5"
 dunce = "1.0"
 walkdir = "2.3"
 regex = "1.7"
 toml = "0.7"
-hex-literal = "0.3"
+hex-literal = "0.4"
 rand = "0.8"
 bytes = "1.4"
 semver = "1.0"
diff --git a/deny.toml b/deny.toml
index 49187a18..eef64229 100644
--- a/deny.toml
+++ b/deny.toml
@@ -15,7 +15,7 @@ notice = "warn"
 # Lint level for when multiple versions of the same crate are detected
 multiple-versions = "warn"
 # Lint level for when a crate version requirement is `*`
-wildcards = "allow"
+wildcards = "deny"
 highlight = "all"
 # List of crates to deny
 deny = [
@@ -33,6 +33,9 @@ skip-tree = []
 
 [licenses]
 unlicensed = "deny"
+confidence-threshold = 0.9
+# copyleft = "deny"
+
 # List of explicitly allowed licenses
 # See https://spdx.org/licenses/ for list of possible licenses
 # [possible values: any SPDX 3.7 short identifier (+ optional exception)].
@@ -45,8 +48,12 @@ allow = [
     "BSD-3-Clause",
     "ISC",
     "Unicode-DFS-2016",
-    "OpenSSL",
     "Unlicense",
+    "MPL-2.0",
+    # https://github.com/briansmith/ring/issues/902
+    "LicenseRef-ring",
+    # https://github.com/briansmith/webpki/issues/148
+    "LicenseRef-webpki",
 ]
 
 # Allow 1 or more licenses on a per-crate basis, so that particular licenses
@@ -55,34 +62,28 @@ exceptions = [
     # CC0 is a permissive license but somewhat unclear status for source code
     # so we prefer to not have dependencies using it
     # https://tldrlegal.com/license/creative-commons-cc0-1.0-universal
-    { allow = ["CC0-1.0"], name = "secp256k1" },
-    { allow = ["CC0-1.0"], name = "secp256k1-sys" },
     { allow = ["CC0-1.0"], name = "tiny-keccak" },
-    { allow = ["CC0-1.0"], name = "more-asserts" },
     { allow = ["CC0-1.0"], name = "trezor-client" },
     { allow = ["CC0-1.0"], name = "constant_time_eq" },
 ]
-#copyleft = "deny"
 
-# See note in unicode-ident's readme!
-[[licenses.clarify]]
-name = "unicode-ident"
-version = "*"
-expression = "(MIT OR Apache-2.0) AND Unicode-DFS-2016"
-license-files = [{ path = "LICENSE-UNICODE", hash = 0x3fb01745 }]
 [[licenses.clarify]]
 name = "ring"
-version = "*"
-expression = "OpenSSL"
+expression = "LicenseRef-ring"
 license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
 
+[[licenses.clarify]]
+name = "webpki"
+expression = "LicenseRef-webpki"
+license-files = [{ path = "LICENSE", hash = 0x001c7e6c }]
+
 # This section is considered when running `cargo deny check sources`.
 # More documentation about the 'sources' section can be found here:
 # https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
 [sources]
 # Lint level for what to happen when a crate from a crate registry that is not
 # in the allow list is encountered
-unknown-registry = "warn"
+unknown-registry = "deny"
 # Lint level for what to happen when a crate from a git repository that is not
 # in the allow list is encountered
-unknown-git = "allow"
+unknown-git = "deny"
diff --git a/ethers-contract/Cargo.toml b/ethers-contract/Cargo.toml
index dc0d5483..601fe1cb 100644
--- a/ethers-contract/Cargo.toml
+++ b/ethers-contract/Cargo.toml
@@ -39,10 +39,8 @@ hex.workspace = true
 ethers-contract-abigen = { workspace = true, optional = true }
 ethers-contract-derive = { workspace = true, optional = true }
 
-# eip712
-ethers-derive-eip712 = { workspace = true, optional = true }
-
 [dev-dependencies]
+ethers-signers.workspace = true
 ethers-solc.workspace = true
 ethers-providers = { workspace = true, features = ["ws"] }
 
@@ -52,8 +50,6 @@ tokio = { workspace = true, features = ["macros"] }
 [features]
 default = ["abigen"]
 
-eip712 = ["ethers-derive-eip712", "ethers-core/eip712"]
-
 abigen-offline = ["ethers-contract-abigen", "ethers-contract-derive"]
 abigen = ["abigen-offline", "ethers-contract-abigen/online"]
 
@@ -62,3 +58,6 @@ legacy = []
 
 rustls = ["ethers-contract-abigen/rustls"]
 openssl = ["ethers-contract-abigen/openssl"]
+
+# Deprecated
+eip712 = []
diff --git a/ethers-contract/ethers-contract-abigen/Cargo.toml b/ethers-contract/ethers-contract-abigen/Cargo.toml
index fdbb5a47..072b7a61 100644
--- a/ethers-contract/ethers-contract-abigen/Cargo.toml
+++ b/ethers-contract/ethers-contract-abigen/Cargo.toml
@@ -30,10 +30,10 @@ ethers-core = { workspace = true, features = ["macros"] }
 
 proc-macro2.workspace = true
 quote.workspace = true
-syn.workspace = true
-prettyplease = "0.1.25"
+syn = { workspace = true, features = ["full"] }
+prettyplease = "0.2.4"
 
-Inflector = "0.11"
+Inflector.workspace = true
 serde.workspace = true
 serde_json.workspace = true
 hex.workspace = true
diff --git a/ethers-contract/ethers-contract-derive/Cargo.toml b/ethers-contract/ethers-contract-derive/Cargo.toml
index 65348d4b..86226b07 100644
--- a/ethers-contract/ethers-contract-derive/Cargo.toml
+++ b/ethers-contract/ethers-contract-derive/Cargo.toml
@@ -28,4 +28,6 @@ proc-macro2.workspace = true
 quote.workspace = true
 syn.workspace = true
 
+Inflector.workspace = true
 hex.workspace = true
+serde_json.workspace = true
diff --git a/ethers-contract/ethers-contract-derive/src/abigen.rs b/ethers-contract/ethers-contract-derive/src/abigen.rs
index 18cb471c..a0106321 100644
--- a/ethers-contract/ethers-contract-derive/src/abigen.rs
+++ b/ethers-contract/ethers-contract-derive/src/abigen.rs
@@ -40,8 +40,7 @@ impl Contracts {
 
 impl Parse for Contracts {
     fn parse(input: ParseStream) -> Result<Self> {
-        let inner =
-            input.parse_terminated::<_, Token![;]>(ContractArgs::parse)?.into_iter().collect();
+        let inner = input.parse_terminated(ContractArgs::parse, Token![;])?.into_iter().collect();
         Ok(Self { inner })
     }
 }
@@ -122,7 +121,7 @@ impl Parse for Parameter {
             "methods" => {
                 let content;
                 braced!(content in input);
-                let parsed = content.parse_terminated::<_, Token![;]>(Spanned::<Method>::parse)?;
+                let parsed = content.parse_terminated(Spanned::<Method>::parse, Token![;])?;
 
                 let mut methods = Vec::with_capacity(parsed.len());
                 let mut signatures = HashSet::new();
@@ -141,7 +140,7 @@ impl Parse for Parameter {
             "derives" | "event_derives" => {
                 let content;
                 parenthesized!(content in input);
-                let derives = content.parse_terminated::<_, Token![,]>(Path::parse)?;
+                let derives = content.parse_terminated(Path::parse, Token![,])?;
                 Ok(Parameter::Derives(derives))
             }
             _ => Err(Error::new(name.span(), "unexpected named parameter")),
@@ -168,7 +167,7 @@ impl Parse for Method {
         // function params
         let content;
         parenthesized!(content in input);
-        let params = content.parse_terminated::<_, Token![,]>(Ident::parse)?;
+        let params = content.parse_terminated(Ident::parse, Token![,])?;
         let last_i = params.len().saturating_sub(1);
 
         signature.push('(');
diff --git a/ethers-contract/ethers-contract-derive/src/call.rs b/ethers-contract/ethers-contract-derive/src/call.rs
index f0ff15a0..fb941c59 100644
--- a/ethers-contract/ethers-contract-derive/src/call.rs
+++ b/ethers-contract/ethers-contract-derive/src/call.rs
@@ -11,12 +11,10 @@ use syn::{parse::Error, DeriveInput};
 
 /// Generates the `ethcall` trait support
 pub(crate) fn derive_eth_call_impl(input: DeriveInput) -> Result<TokenStream, Error> {
-    let attributes = parse_calllike_attributes(&input, "ethcall")?;
+    let attributes = parse_calllike_attributes!(input, "ethcall");
 
-    let function_call_name =
-        attributes.name.map(|(s, _)| s).unwrap_or_else(|| input.ident.to_string());
-
-    let mut function = if let Some((abi, span)) = attributes.abi {
+    let function_call_name = attributes.name(&input.ident);
+    let mut function = if let Some((abi, span)) = attributes.abi() {
         let sig = abi.trim_start_matches("function ").trim_start();
         // try to parse as solidity function
         match HumanReadableParser::parse_function(&abi) {
diff --git a/ethers-contract/ethers-contract-derive/src/calllike.rs b/ethers-contract/ethers-contract-derive/src/calllike.rs
index 23f8602a..4cbb28c8 100644
--- a/ethers-contract/ethers-contract-derive/src/calllike.rs
+++ b/ethers-contract/ethers-contract-derive/src/calllike.rs
@@ -7,97 +7,50 @@ use ethers_core::{
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::quote;
-use syn::{parse::Error, spanned::Spanned, AttrStyle, DeriveInput, Lit, Meta, NestedMeta};
+use syn::{DeriveInput, LitStr, Result};
 
 /// All the attributes the `EthCall`/`EthError` macro supports
 #[derive(Default)]
 pub struct EthCalllikeAttributes {
-    pub name: Option<(String, Span)>,
-    pub abi: Option<(String, Span)>,
+    pub name: Option<LitStr>,
+    pub abi: Option<LitStr>,
 }
 
-/// extracts the attributes from the struct annotated with the given attribute
-pub fn parse_calllike_attributes(
-    input: &DeriveInput,
-    attr_name: &str,
-) -> Result<EthCalllikeAttributes, Error> {
-    let mut result = EthCalllikeAttributes::default();
-    for a in input.attrs.iter() {
-        if let AttrStyle::Outer = a.style {
-            if let Ok(Meta::List(meta)) = a.parse_meta() {
-                if meta.path.is_ident(attr_name) {
-                    for n in meta.nested.iter() {
-                        if let NestedMeta::Meta(meta) = n {
-                            match meta {
-                                Meta::Path(path) => {
-                                    return Err(Error::new(
-                                        path.span(),
-                                        format!("unrecognized {attr_name} parameter"),
-                                    ))
-                                }
-                                Meta::List(meta) => {
-                                    return Err(Error::new(
-                                        meta.path.span(),
-                                        format!("unrecognized {attr_name} parameter"),
-                                    ))
-                                }
-                                Meta::NameValue(meta) => {
-                                    if meta.path.is_ident("name") {
-                                        if let Lit::Str(ref lit_str) = meta.lit {
-                                            if result.name.is_none() {
-                                                result.name =
-                                                    Some((lit_str.value(), lit_str.span()));
-                                            } else {
-                                                return Err(Error::new(
-                                                    meta.span(),
-                                                    "name already specified",
-                                                ))
-                                            }
-                                        } else {
-                                            return Err(Error::new(
-                                                meta.span(),
-                                                "name must be a string",
-                                            ))
-                                        }
-                                    } else if meta.path.is_ident("abi") {
-                                        if let Lit::Str(ref lit_str) = meta.lit {
-                                            if result.abi.is_none() {
-                                                result.abi =
-                                                    Some((lit_str.value(), lit_str.span()));
-                                            } else {
-                                                return Err(Error::new(
-                                                    meta.span(),
-                                                    "abi already specified",
-                                                ))
-                                            }
-                                        } else {
-                                            return Err(Error::new(
-                                                meta.span(),
-                                                "abi must be a string",
-                                            ))
-                                        }
-                                    } else {
-                                        return Err(Error::new(
-                                            meta.span(),
-                                            format!("unrecognized {attr_name} parameter"),
-                                        ))
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
+impl EthCalllikeAttributes {
+    pub fn name(&self, fallback: &Ident) -> String {
+        self.name.as_ref().map(|s| s.value()).unwrap_or_else(|| fallback.to_string())
+    }
+
+    pub fn abi(&self) -> Option<(String, Span)> {
+        self.abi.as_ref().map(|s| (s.value(), s.span()))
     }
-    Ok(result)
 }
 
+macro_rules! parse_calllike_attributes {
+    ($input:ident, $attr_ident:literal) => {{
+        let mut result = EthCalllikeAttributes::default();
+        $crate::utils::parse_attributes!($input.attrs.iter(), $attr_ident, meta,
+            "name", result.name => {
+                meta.input.parse::<::syn::Token![=]>()?;
+                let litstr: ::syn::LitStr = meta.input.parse()?;
+                result.name = Some(litstr);
+            }
+            "abi", result.abi => {
+                meta.input.parse::<::syn::Token![=]>()?;
+                let litstr: ::syn::LitStr = meta.input.parse()?;
+                result.abi = Some(litstr);
+            }
+        );
+        result
+    }};
+}
+pub(crate) use parse_calllike_attributes;
+
 /// Generates the decode implementation based on the type's runtime `AbiType` impl
 pub fn derive_decode_impl_with_abi_type(
     input: &DeriveInput,
     trait_ident: Ident,
-) -> Result<TokenStream, Error> {
+) -> Result<TokenStream> {
     let datatypes_array = utils::abi_parameters_array(input, &trait_ident.to_string())?;
     Ok(derive_decode_impl(datatypes_array, trait_ident))
 }
@@ -130,7 +83,7 @@ pub fn derive_codec_impls(
     input: &DeriveInput,
     decode_impl: TokenStream,
     trait_ident: Ident,
-) -> Result<TokenStream, Error> {
+) -> Result<TokenStream> {
     // the ethers crates to use
     let ethers_core = ethers_core_crate();
     let ethers_contract = ethers_contract_crate();
diff --git a/ethers-contract/ethers-contract-derive/src/eip712.rs b/ethers-contract/ethers-contract-derive/src/eip712.rs
new file mode 100644
index 00000000..ece0524e
--- /dev/null
+++ b/ethers-contract/ethers-contract-derive/src/eip712.rs
@@ -0,0 +1,181 @@
+use crate::utils;
+use ethers_core::{
+    abi::{Address, ParamType},
+    macros::ethers_core_crate,
+    types::transaction::eip712::EIP712Domain,
+    utils::keccak256,
+};
+use inflector::Inflector;
+use proc_macro2::{Literal, TokenStream};
+use quote::quote;
+use syn::{spanned::Spanned, Data, DeriveInput, Error, Fields, LitInt, LitStr, Result, Token};
+
+pub(crate) fn impl_derive_eip712(input: &DeriveInput) -> Result<TokenStream> {
+    // Primary type should match the type in the ethereum verifying contract;
+    let primary_type = &input.ident;
+
+    // Instantiate domain from parsed attributes
+    let domain = parse_attributes(input)?;
+
+    let domain_separator = into_tokens(domain.separator());
+
+    let domain_str = serde_json::to_string(&domain).unwrap();
+
+    // Must parse the AST at compile time.
+    let parsed_fields = parse_fields(input)?;
+
+    // Compute the type hash for the derived struct using the parsed fields from above.
+    let type_hash = into_tokens(make_type_hash(primary_type.to_string(), &parsed_fields));
+
+    // Use reference to ethers_core instead of directly using the crate itself.
+    let ethers_core = ethers_core_crate();
+
+    let tokens = quote! {
+        impl #ethers_core::types::transaction::eip712::Eip712 for #primary_type {
+            type Error = #ethers_core::types::transaction::eip712::Eip712Error;
+
+            #[inline]
+            fn type_hash() -> ::core::result::Result<[u8; 32], Self::Error> {
+                Ok([#(#type_hash),*])
+            }
+
+            #[inline]
+            fn domain_separator(&self) -> ::core::result::Result<[u8; 32], Self::Error> {
+                Ok([#(#domain_separator),*])
+            }
+
+            fn domain(&self) -> ::core::result::Result<#ethers_core::types::transaction::eip712::EIP712Domain, Self::Error> {
+                #ethers_core::utils::__serde_json::from_str(#domain_str).map_err(::core::convert::Into::into)
+            }
+
+            fn struct_hash(&self) -> ::core::result::Result<[u8; 32], Self::Error> {
+                let mut items = vec![#ethers_core::abi::Token::Uint(
+                    #ethers_core::types::U256::from(&Self::type_hash()?[..]),
+                )];
+
+                if let #ethers_core::abi::Token::Tuple(tokens) =
+                    #ethers_core::abi::Tokenizable::into_token(::core::clone::Clone::clone(self))
+                {
+                    items.reserve(tokens.len());
+                    for token in tokens {
+                        match &token {
+                            #ethers_core::abi::Token::Tuple(t) => {
+                                // TODO: check for nested Eip712 Type;
+                                // Challenge is determining the type hash
+                                return Err(Self::Error::NestedEip712StructNotImplemented);
+                            },
+                            _ => {
+                                items.push(#ethers_core::types::transaction::eip712::encode_eip712_type(token));
+                            }
+                        }
+                    }
+                }
+
+                let struct_hash = #ethers_core::utils::keccak256(#ethers_core::abi::encode(
+                    &items,
+                ));
+
+                Ok(struct_hash)
+            }
+        }
+    };
+
+    Ok(tokens)
+}
+
+fn parse_attributes(input: &DeriveInput) -> Result<EIP712Domain> {
+    let mut domain = EIP712Domain::default();
+    utils::parse_attributes!(input.attrs.iter(), "eip712", meta,
+        "name", domain.name => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            domain.name = Some(litstr.value());
+        }
+        "version", domain.version => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            domain.version = Some(litstr.value());
+        }
+        "chain_id", domain.chain_id => {
+            meta.input.parse::<Token![=]>()?;
+            let litint: LitInt = meta.input.parse()?;
+            let n: u64 = litint.base10_parse()?;
+            domain.chain_id = Some(n.into());
+        }
+        "verifying_contract", domain.verifying_contract => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            let addr: Address =
+                litstr.value().parse().map_err(|e| Error::new(litstr.span(), e))?;
+            domain.verifying_contract = Some(addr);
+        }
+        "salt", domain.salt => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            let hash = keccak256(litstr.value());
+            domain.salt = Some(hash);
+        }
+    );
+    Ok(domain)
+}
+
+/// Returns a Vec of `(name, param_type)`
+fn parse_fields(input: &DeriveInput) -> Result<Vec<(String, ParamType)>> {
+    let data = match &input.data {
+        Data::Struct(s) => s,
+        Data::Enum(e) => {
+            return Err(Error::new(e.enum_token.span, "Eip712 is not derivable for enums"))
+        }
+        Data::Union(u) => {
+            return Err(Error::new(u.union_token.span, "Eip712 is not derivable for unions"))
+        }
+    };
+
+    let named_fields = match &data.fields {
+        Fields::Named(fields) => fields,
+        _ => return Err(Error::new(input.span(), "unnamed fields are not supported")),
+    };
+
+    let mut fields = Vec::with_capacity(named_fields.named.len());
+    for f in named_fields.named.iter() {
+        let field_name = f.ident.as_ref().unwrap().to_string().to_camel_case();
+        let field_type =
+            match f.attrs.iter().find(|a| a.path().segments.iter().any(|s| s.ident == "eip712")) {
+                // Found nested Eip712 Struct
+                // TODO: Implement custom
+                Some(a) => {
+                    return Err(Error::new(a.span(), "nested Eip712 struct are not yet supported"))
+                }
+                // Not a nested eip712 struct, return the field param type;
+                None => crate::utils::find_parameter_type(&f.ty)?,
+            };
+
+        fields.push((field_name, field_type));
+    }
+
+    Ok(fields)
+}
+
+/// Convert hash map of field names and types into a type hash corresponding to enc types;
+fn make_type_hash(primary_type: String, fields: &[(String, ParamType)]) -> [u8; 32] {
+    let mut sig = String::with_capacity(256);
+
+    sig.push_str(&primary_type);
+
+    sig.push('(');
+    for (i, (name, ty)) in fields.iter().enumerate() {
+        sig.push_str(&ty.to_string());
+        sig.push(' ');
+        sig.push_str(name);
+        if i < fields.len() - 1 {
+            sig.push(',');
+        }
+    }
+    sig.push(')');
+
+    keccak256(sig)
+}
+
+fn into_tokens(bytes: [u8; 32]) -> impl Iterator<Item = Literal> {
+    bytes.into_iter().map(Literal::u8_suffixed)
+}
diff --git a/ethers-contract/ethers-contract-derive/src/error.rs b/ethers-contract/ethers-contract-derive/src/error.rs
index b6f988ff..832b64e4 100644
--- a/ethers-contract/ethers-contract-derive/src/error.rs
+++ b/ethers-contract/ethers-contract-derive/src/error.rs
@@ -11,11 +11,10 @@ use syn::{parse::Error, DeriveInput};
 
 /// Generates the `EthError` trait support
 pub(crate) fn derive_eth_error_impl(input: DeriveInput) -> Result<TokenStream, Error> {
-    let attributes = parse_calllike_attributes(&input, "etherror")?;
+    let attributes = parse_calllike_attributes!(input, "etherror");
 
-    let error_name = attributes.name.map(|(s, _)| s).unwrap_or_else(|| input.ident.to_string());
-
-    let mut error = if let Some((src, span)) = attributes.abi {
+    let error_name = attributes.name(&input.ident);
+    let mut error = if let Some((src, span)) = attributes.abi() {
         let raw_function_sig = src.trim_start_matches("error ").trim_start();
         // try to parse as solidity error
         match HumanReadableParser::parse_error(&src) {
diff --git a/ethers-contract/ethers-contract-derive/src/event.rs b/ethers-contract/ethers-contract-derive/src/event.rs
index 39056187..7beac097 100644
--- a/ethers-contract/ethers-contract-derive/src/event.rs
+++ b/ethers-contract/ethers-contract-derive/src/event.rs
@@ -6,16 +6,12 @@ use ethers_core::{
     abi::{Event, EventExt, EventParam, HumanReadableParser},
     macros::{ethers_contract_crate, ethers_core_crate},
 };
-use hex::FromHex;
 use proc_macro2::{Span, TokenStream};
 use quote::quote;
-use syn::{
-    parse::Error, spanned::Spanned, AttrStyle, Data, DeriveInput, Field, Fields, Lit, Meta,
-    NestedMeta,
-};
+use syn::{spanned::Spanned, Data, DeriveInput, Error, Field, Fields, LitStr, Result, Token};
 
 /// Generates the `EthEvent` trait support
-pub(crate) fn derive_eth_event_impl(input: DeriveInput) -> Result<TokenStream, Error> {
+pub(crate) fn derive_eth_event_impl(input: DeriveInput) -> Result<TokenStream> {
     let name = &input.ident;
     let attributes = parse_event_attributes(&input)?;
 
@@ -64,7 +60,7 @@ pub(crate) fn derive_eth_event_impl(input: DeriveInput) -> Result<TokenStream, E
 
     let (abi, event_sig) = (event.abi_signature(), event.signature());
 
-    let signature = if let Some((hash, _)) = attributes.signature_hash {
+    let signature = if let Some((hash, _)) = attributes.signature {
         utils::signature(&hash)
     } else {
         utils::signature(event_sig.as_bytes())
@@ -122,7 +118,7 @@ impl EventField {
     }
 }
 
-fn derive_decode_from_log_impl(input: &DeriveInput, event: &Event) -> Result<TokenStream, Error> {
+fn derive_decode_from_log_impl(input: &DeriveInput, event: &Event) -> Result<TokenStream> {
     let ethers_core = ethers_core_crate();
 
     let fields: Vec<_> = match input.data {
@@ -291,7 +287,7 @@ fn derive_decode_from_log_impl(input: &DeriveInput, event: &Event) -> Result<Tok
 }
 
 /// Determine the event's ABI by parsing the AST
-fn derive_abi_event_from_fields(input: &DeriveInput) -> Result<Event, Error> {
+fn derive_abi_event_from_fields(input: &DeriveInput) -> Result<Event> {
     let event = Event {
         name: input.ident.to_string(),
         inputs: utils::derive_abi_inputs_from_fields(input, "EthEvent")?
@@ -303,53 +299,18 @@ fn derive_abi_event_from_fields(input: &DeriveInput) -> Result<Event, Error> {
     Ok(event)
 }
 
-fn parse_field_attributes(field: &Field) -> Result<(Option<String>, bool), Error> {
-    let mut indexed = false;
-    let mut topic_name = None;
-    for a in field.attrs.iter() {
-        if let AttrStyle::Outer = a.style {
-            if let Ok(Meta::List(meta)) = a.parse_meta() {
-                if meta.path.is_ident("ethevent") {
-                    for n in meta.nested.iter() {
-                        if let NestedMeta::Meta(meta) = n {
-                            match meta {
-                                Meta::Path(path) => {
-                                    if path.is_ident("indexed") {
-                                        indexed = true;
-                                    } else {
-                                        return Err(Error::new(
-                                            path.span(),
-                                            "unrecognized ethevent parameter",
-                                        ))
-                                    }
-                                }
-                                Meta::List(meta) => {
-                                    return Err(Error::new(
-                                        meta.path.span(),
-                                        "unrecognized ethevent parameter",
-                                    ))
-                                }
-                                Meta::NameValue(meta) => {
-                                    if meta.path.is_ident("name") {
-                                        if let Lit::Str(ref lit_str) = meta.lit {
-                                            topic_name = Some(lit_str.value());
-                                        } else {
-                                            return Err(Error::new(
-                                                meta.span(),
-                                                "name attribute must be a string",
-                                            ))
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
+fn parse_field_attributes(field: &Field) -> Result<(Option<String>, bool)> {
+    let mut indexed = None::<bool>;
+    let mut topic_name = None::<String>;
+    utils::parse_attributes!(field.attrs.iter(), "ethevent", meta,
+        "indexed", indexed => { indexed = Some(true) }
+        "name", topic_name => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            topic_name = Some(litstr.value());
         }
-    }
-
-    Ok((topic_name, indexed))
+    );
+    Ok((topic_name, indexed.unwrap_or_default()))
 }
 
 /// All the attributes the `EthEvent` macro supports
@@ -357,139 +318,32 @@ fn parse_field_attributes(field: &Field) -> Result<(Option<String>, bool), Error
 struct EthEventAttributes {
     name: Option<(String, Span)>,
     abi: Option<(String, Span)>,
-    signature_hash: Option<(Vec<u8>, Span)>,
+    signature: Option<(Vec<u8>, Span)>,
     anonymous: Option<(bool, Span)>,
 }
 
 /// extracts the attributes from the struct annotated with `EthEvent`
-fn parse_event_attributes(input: &DeriveInput) -> Result<EthEventAttributes, Error> {
+fn parse_event_attributes(input: &DeriveInput) -> Result<EthEventAttributes> {
     let mut result = EthEventAttributes::default();
-    for a in input.attrs.iter() {
-        if let AttrStyle::Outer = a.style {
-            if let Ok(Meta::List(meta)) = a.parse_meta() {
-                if meta.path.is_ident("ethevent") {
-                    for n in meta.nested.iter() {
-                        if let NestedMeta::Meta(meta) = n {
-                            match meta {
-                                Meta::Path(path) => {
-                                    if let Some(name) = path.get_ident() {
-                                        if &*name.to_string() == "anonymous" {
-                                            if result.anonymous.is_none() {
-                                                result.anonymous = Some((true, name.span()));
-                                                continue
-                                            } else {
-                                                return Err(Error::new(
-                                                    name.span(),
-                                                    "anonymous already specified",
-                                                ))
-                                            }
-                                        }
-                                    }
-                                    return Err(Error::new(
-                                        path.span(),
-                                        "unrecognized ethevent parameter",
-                                    ))
-                                }
-                                Meta::List(meta) => {
-                                    return Err(Error::new(
-                                        meta.path.span(),
-                                        "unrecognized ethevent parameter",
-                                    ))
-                                }
-                                Meta::NameValue(meta) => {
-                                    if meta.path.is_ident("anonymous") {
-                                        if let Lit::Bool(ref bool_lit) = meta.lit {
-                                            if result.anonymous.is_none() {
-                                                result.anonymous =
-                                                    Some((bool_lit.value, bool_lit.span()));
-                                            } else {
-                                                return Err(Error::new(
-                                                    meta.span(),
-                                                    "anonymous already specified",
-                                                ))
-                                            }
-                                        } else {
-                                            return Err(Error::new(
-                                                meta.span(),
-                                                "name must be a string",
-                                            ))
-                                        }
-                                    } else if meta.path.is_ident("name") {
-                                        if let Lit::Str(ref lit_str) = meta.lit {
-                                            if result.name.is_none() {
-                                                result.name =
-                                                    Some((lit_str.value(), lit_str.span()));
-                                            } else {
-                                                return Err(Error::new(
-                                                    meta.span(),
-                                                    "name already specified",
-                                                ))
-                                            }
-                                        } else {
-                                            return Err(Error::new(
-                                                meta.span(),
-                                                "name must be a string",
-                                            ))
-                                        }
-                                    } else if meta.path.is_ident("abi") {
-                                        if let Lit::Str(ref lit_str) = meta.lit {
-                                            if result.abi.is_none() {
-                                                result.abi =
-                                                    Some((lit_str.value(), lit_str.span()));
-                                            } else {
-                                                return Err(Error::new(
-                                                    meta.span(),
-                                                    "abi already specified",
-                                                ))
-                                            }
-                                        } else {
-                                            return Err(Error::new(
-                                                meta.span(),
-                                                "abi must be a string",
-                                            ))
-                                        }
-                                    } else if meta.path.is_ident("signature") {
-                                        if let Lit::Str(ref lit_str) = meta.lit {
-                                            if result.signature_hash.is_none() {
-                                                match Vec::from_hex(lit_str.value()) {
-                                                    Ok(sig) => {
-                                                        result.signature_hash =
-                                                            Some((sig, lit_str.span()))
-                                                    }
-                                                    Err(err) => {
-                                                        return Err(Error::new(
-                                                            meta.span(),
-                                                            format!(
-                                                                "Expected hex signature: {err:?}"
-                                                            ),
-                                                        ))
-                                                    }
-                                                }
-                                            } else {
-                                                return Err(Error::new(
-                                                    meta.span(),
-                                                    "signature already specified",
-                                                ))
-                                            }
-                                        } else {
-                                            return Err(Error::new(
-                                                meta.span(),
-                                                "signature must be a hex string",
-                                            ))
-                                        }
-                                    } else {
-                                        return Err(Error::new(
-                                            meta.span(),
-                                            "unrecognized ethevent parameter",
-                                        ))
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
+    utils::parse_attributes!(input.attrs.iter(), "ethevent", meta,
+        "name", result.name => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            result.name = Some((litstr.value(), litstr.span()));
         }
-    }
+        "abi", result.abi => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            result.abi = Some((litstr.value(), litstr.span()));
+        }
+        "signature", result.signature => {
+            meta.input.parse::<Token![=]>()?;
+            let litstr: LitStr = meta.input.parse()?;
+            let s = litstr.value();
+            let b = hex::decode(s.strip_prefix("0x").unwrap_or(&s)).map_err(|e| meta.error(e))?;
+            result.signature = Some((b, litstr.span()));
+        }
+        "anonymous", result.anonymous => { result.anonymous = Some((true, meta.path.span())); }
+    );
     Ok(result)
 }
diff --git a/ethers-contract/ethers-contract-derive/src/lib.rs b/ethers-contract/ethers-contract-derive/src/lib.rs
index 126a9076..d259c12f 100644
--- a/ethers-contract/ethers-contract-derive/src/lib.rs
+++ b/ethers-contract/ethers-contract-derive/src/lib.rs
@@ -14,6 +14,7 @@ mod call;
 pub(crate) mod calllike;
 mod codec;
 mod display;
+mod eip712;
 mod error;
 mod event;
 mod spanned;
@@ -362,3 +363,75 @@ pub fn derive_abi_error(input: TokenStream) -> TokenStream {
     }
     .into()
 }
+
+/// EIP-712 derive macro.
+///
+/// This crate provides a derive macro `Eip712` that is used to encode a rust struct
+/// into a payload hash, according to <https://eips.ethereum.org/EIPS/eip-712>
+///
+/// The trait used to derive the macro is found in `ethers_core::transaction::eip712::Eip712`
+/// Both the derive macro and the trait must be in context when using
+///
+/// This derive macro requires the `#[eip712]` attributes to be included
+/// for specifying the domain separator used in encoding the hash.
+///
+/// NOTE: In addition to deriving `Eip712` trait, the `EthAbiType` trait must also be derived.
+/// This allows the struct to be parsed into `ethers_core::abi::Token` for encoding.
+///
+/// # Optional Eip712 Parameters
+///
+/// The only optional parameter is `salt`, which accepts a string
+/// that is hashed using keccak256 and stored as bytes.
+///
+/// # Example Usage
+///
+/// ```ignore
+/// use ethers_contract::EthAbiType;
+/// use ethers_derive_eip712::*;
+/// use ethers_core::types::{transaction::eip712::Eip712, H160};
+///
+/// #[derive(Debug, Eip712, EthAbiType)]
+/// #[eip712(
+///     name = "Radicle",
+///     version = "1",
+///     chain_id = 1,
+///     verifying_contract = "0x0000000000000000000000000000000000000000"
+///     // salt is an optional parameter
+///     salt = "my-unique-spice"
+/// )]
+/// pub struct Puzzle {
+///     pub organization: H160,
+///     pub contributor: H160,
+///     pub commit: String,
+///     pub project: String,
+/// }
+///
+/// let puzzle = Puzzle {
+///     organization: "0000000000000000000000000000000000000000"
+///         .parse::<H160>()
+///         .expect("failed to parse address"),
+///     contributor: "0000000000000000000000000000000000000000"
+///         .parse::<H160>()
+///         .expect("failed to parse address"),
+///     commit: "5693b7019eb3e4487a81273c6f5e1832d77acb53".to_string(),
+///     project: "radicle-reward".to_string(),
+/// };
+///
+/// let hash = puzzle.encode_eip712().unwrap();
+/// ```
+///
+/// # Limitations
+///
+/// At the moment, the derive macro does not recursively encode nested Eip712 structs.
+///
+/// There is an Inner helper attribute `#[eip712]` for fields that will eventually be used to
+/// determine if there is a nested eip712 struct. However, this work is not yet complete.
+#[proc_macro_derive(Eip712, attributes(eip712))]
+pub fn derive_eip712(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    match eip712::impl_derive_eip712(&input) {
+        Ok(tokens) => tokens,
+        Err(e) => e.to_compile_error(),
+    }
+    .into()
+}
diff --git a/ethers-contract/ethers-contract-derive/src/utils.rs b/ethers-contract/ethers-contract-derive/src/utils.rs
index 33bb2a40..dfb49513 100644
--- a/ethers-contract/ethers-contract-derive/src/utils.rs
+++ b/ethers-contract/ethers-contract-derive/src/utils.rs
@@ -6,6 +6,35 @@ use syn::{
     PathArguments, Type,
 };
 
+/// Parses the specified attributes from a `syn::Attribute` iterator.
+macro_rules! parse_attributes {
+    ($attrs:expr, $attr_ident:literal, $meta:ident, $($field:pat, $opt:expr => $block:block)*) => {
+        const ERROR: &str = concat!("unrecognized ", $attr_ident, " attribute");
+        const ALREADY_SPECIFIED: &str = concat!($attr_ident, " attribute already specified");
+
+        for attr in $attrs {
+            if !attr.path().is_ident($attr_ident) {
+                continue;
+            }
+
+            attr.parse_nested_meta(|$meta| {
+                let ident = $meta.path.get_ident().ok_or_else(|| $meta.error(ERROR))?.to_string();
+                match ident.as_str() {
+                    $(
+                        $field if $opt.is_none() => $block,
+                        $field => return Err($meta.error(ALREADY_SPECIFIED)),
+                    )*
+
+                    _ => return Err($meta.error(ERROR)),
+                }
+
+                Ok(())
+            })?;
+        }
+    };
+}
+pub(crate) use parse_attributes;
+
 pub fn ident(name: &str) -> Ident {
     Ident::new(name, Span::call_site())
 }
@@ -104,17 +133,22 @@ pub fn param_type_quote(kind: &ParamType) -> TokenStream {
 /// Tries to find the corresponding `ParamType` used for tokenization for the
 /// given type
 pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
+    const ERROR: &str = "Failed to derive proper ABI from array field";
+
     match ty {
         Type::Array(arr) => {
             let ty = find_parameter_type(&arr.elem)?;
             if let Expr::Lit(ref expr) = arr.len {
                 if let Lit::Int(ref len) = expr.lit {
-                    if let Ok(size) = len.base10_parse::<usize>() {
-                        return Ok(ParamType::FixedArray(Box::new(ty), size))
+                    if let Ok(len) = len.base10_parse::<usize>() {
+                        return match (ty, len) {
+                            (ParamType::Uint(8), 32) => Ok(ParamType::FixedBytes(32)),
+                            (ty, len) => Ok(ParamType::FixedArray(Box::new(ty), len)),
+                        }
                     }
                 }
             }
-            Err(Error::new(arr.span(), "Failed to derive proper ABI from array field"))
+            Err(Error::new(arr.span(), ERROR))
         }
 
         Type::Path(ty) => {
@@ -151,7 +185,7 @@ pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
                         s => parse_param_type(s),
                     }
                 })
-                .ok_or_else(|| Error::new(ty.span(), "Failed to derive proper ABI from fields"))
+                .ok_or_else(|| Error::new(ty.span(), ERROR))
         }
 
         Type::Tuple(ty) => ty
@@ -161,7 +195,7 @@ pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
             .collect::<Result<Vec<_>, _>>()
             .map(ParamType::Tuple),
 
-        _ => Err(Error::new(ty.span(), "Failed to derive proper ABI from fields")),
+        _ => Err(Error::new(ty.span(), ERROR)),
     }
 }
 
diff --git a/ethers-contract/src/lib.rs b/ethers-contract/src/lib.rs
index ecb5944b..1d8b6213 100644
--- a/ethers-contract/src/lib.rs
+++ b/ethers-contract/src/lib.rs
@@ -59,16 +59,13 @@ pub use ethers_contract_abigen::{
 #[cfg(any(test, feature = "abigen"))]
 #[cfg_attr(docsrs, doc(cfg(feature = "abigen")))]
 pub use ethers_contract_derive::{
-    abigen, EthAbiCodec, EthAbiType, EthCall, EthDisplay, EthError, EthEvent,
+    abigen, Eip712, EthAbiCodec, EthAbiType, EthCall, EthDisplay, EthError, EthEvent,
 };
 
 // Hide the Lazy re-export, it's just for convenience
 #[doc(hidden)]
 pub use once_cell::sync::Lazy;
 
-#[cfg(feature = "eip712")]
-pub use ethers_derive_eip712::*;
-
 // For macro expansions only, not public API.
 // See: [#2235](https://github.com/gakonst/ethers-rs/pull/2235)
 
diff --git a/ethers-core/Cargo.toml b/ethers-core/Cargo.toml
index fd5211ec..03cc9d41 100644
--- a/ethers-core/Cargo.toml
+++ b/ethers-core/Cargo.toml
@@ -47,15 +47,11 @@ hex.workspace = true
 once_cell = { workspace = true, optional = true }
 unicode-xid = "0.2"
 strum = { version = "0.24", features = ["derive"] }
-num_enum = "0.5"
+num_enum = "0.6"
 
 # macros feature enabled dependencies
-cargo_metadata = { version = "0.15.3", optional = true }
-
-# eip712 feature enabled dependencies
-convert_case = { version = "0.6.0", optional = true }
+cargo_metadata = { version = "0.15.4", optional = true }
 syn = { workspace = true, optional = true }
-proc-macro2 = { workspace = true, optional = true }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 tempfile.workspace = true
@@ -73,5 +69,7 @@ rand.workspace = true
 [features]
 celo = ["legacy"] # celo support extends the transaction format with extra fields
 legacy = []
-eip712 = ["convert_case", "syn", "proc-macro2"]
 macros = ["syn", "cargo_metadata", "once_cell"]
+
+# Deprecated
+eip712 = []
diff --git a/ethers-core/ethers-derive-eip712/Cargo.toml b/ethers-core/ethers-derive-eip712/Cargo.toml
deleted file mode 100644
index 5f2e320a..00000000
--- a/ethers-core/ethers-derive-eip712/Cargo.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[package]
-name = "ethers-derive-eip712"
-authors = ["Ryan Tate <ryan.michael.tate@gmail.com>"]
-description = "Derive procedural macro for EIP-712 typed data"
-
-version.workspace = true
-edition.workspace = true
-rust-version.workspace = true
-license.workspace = true
-documentation.workspace = true
-repository.workspace = true
-homepage.workspace = true
-categories.workspace = true
-keywords.workspace = true
-
-[lib]
-proc-macro = true
-
-[dependencies]
-ethers-core = { workspace = true, features = ["eip712", "macros"] }
-
-quote.workspace = true
-syn.workspace = true
-
-hex.workspace = true
-serde_json.workspace = true
-
-[dev-dependencies]
-ethers-contract-derive.workspace = true
diff --git a/ethers-core/ethers-derive-eip712/src/lib.rs b/ethers-core/ethers-derive-eip712/src/lib.rs
deleted file mode 100644
index e1c1272a..00000000
--- a/ethers-core/ethers-derive-eip712/src/lib.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-//! # EIP-712 Derive Macro
-//!
-//! This crate provides a derive macro `Eip712` that is used to encode a rust struct
-//! into a payload hash, according to [https://eips.ethereum.org/EIPS/eip-712](https://eips.ethereum.org/EIPS/eip-712)
-//!
-//! The trait used to derive the macro is found in `ethers_core::transaction::eip712::Eip712`
-//! Both the derive macro and the trait must be in context when using
-//!
-//! This derive macro requires the `#[eip712]` attributes to be included
-//! for specifying the domain separator used in encoding the hash.
-//!
-//! NOTE: In addition to deriving `Eip712` trait, the `EthAbiType` trait must also be derived.
-//! This allows the struct to be parsed into `ethers_core::abi::Token` for encoding.
-//!
-//! # Optional Eip712 Parameters
-//!
-//! The only optional parameter is `salt`, which accepts a string
-//! that is hashed using keccak256 and stored as bytes.
-//!
-//! # Example Usage
-//!
-//! ```ignore
-//! use ethers_contract::EthAbiType;
-//! use ethers_derive_eip712::*;
-//! use ethers_core::types::{transaction::eip712::Eip712, H160};
-//!
-//! #[derive(Debug, Eip712, EthAbiType)]
-//! #[eip712(
-//!     name = "Radicle",
-//!     version = "1",
-//!     chain_id = 1,
-//!     verifying_contract = "0x0000000000000000000000000000000000000000"
-//!     // salt is an optional parameter
-//!     salt = "my-unique-spice"
-//! )]
-//! pub struct Puzzle {
-//!     pub organization: H160,
-//!     pub contributor: H160,
-//!     pub commit: String,
-//!     pub project: String,
-//! }
-//!
-//! let puzzle = Puzzle {
-//!     organization: "0000000000000000000000000000000000000000"
-//!         .parse::<H160>()
-//!         .expect("failed to parse address"),
-//!     contributor: "0000000000000000000000000000000000000000"
-//!         .parse::<H160>()
-//!         .expect("failed to parse address"),
-//!     commit: "5693b7019eb3e4487a81273c6f5e1832d77acb53".to_string(),
-//!     project: "radicle-reward".to_string(),
-//! };
-//!
-//! let hash = puzzle.encode_eip712().unwrap();
-//! ```
-//!
-//! # Limitations
-//!
-//! At the moment, the derive macro does not recursively encode nested Eip712 structs.
-//!
-//! There is an Inner helper attribute `#[eip712]` for fields that will eventually be used to
-//! determine if there is a nested eip712 struct. However, this work is not yet complete.
-
-#![deny(missing_docs, unsafe_code, rustdoc::broken_intra_doc_links)]
-use ethers_core::{macros::ethers_core_crate, types::transaction::eip712};
-use proc_macro::TokenStream;
-use quote::quote;
-use std::convert::TryFrom;
-use syn::parse_macro_input;
-
-/// Derive macro for `Eip712`
-#[proc_macro_derive(Eip712, attributes(eip712))]
-pub fn eip_712_derive(input: TokenStream) -> TokenStream {
-    let ast = parse_macro_input!(input);
-
-    impl_eip_712_macro(&ast)
-}
-
-// Main implementation macro, used to compute static values and define
-// method for encoding the final eip712 payload;
-fn impl_eip_712_macro(ast: &syn::DeriveInput) -> TokenStream {
-    // Primary type should match the type in the ethereum verifying contract;
-    let primary_type = &ast.ident;
-
-    // Instantiate domain from parsed attributes
-    let domain = match eip712::EIP712Domain::try_from(ast) {
-        Ok(attributes) => attributes,
-        Err(e) => return TokenStream::from(e),
-    };
-
-    let domain_separator = hex::encode(domain.separator());
-
-    //
-    let domain_str = match serde_json::to_string(&domain) {
-        Ok(s) => s,
-        Err(e) => {
-            return TokenStream::from(
-                syn::Error::new(ast.ident.span(), e.to_string()).to_compile_error(),
-            )
-        }
-    };
-
-    // Must parse the AST at compile time.
-    let parsed_fields = match eip712::parse_fields(ast) {
-        Ok(fields) => fields,
-        Err(e) => return TokenStream::from(e),
-    };
-
-    // Compute the type hash for the derived struct using the parsed fields from above.
-    let type_hash =
-        hex::encode(eip712::make_type_hash(primary_type.clone().to_string(), &parsed_fields));
-
-    // Use reference to ethers_core instead of directly using the crate itself.
-    let ethers_core = ethers_core_crate();
-
-    let implementation = quote! {
-        impl Eip712 for #primary_type {
-            type Error = #ethers_core::types::transaction::eip712::Eip712Error;
-
-            fn type_hash() -> Result<[u8; 32], Self::Error> {
-                use std::convert::TryFrom;
-                let decoded = #ethers_core::utils::hex::decode(#type_hash)?;
-                let byte_array: [u8; 32] = <[u8; 32]>::try_from(&decoded[..])?;
-                Ok(byte_array)
-            }
-
-            // Return the pre-computed domain separator from compile time;
-            fn domain_separator(&self) -> Result<[u8; 32], Self::Error> {
-                use std::convert::TryFrom;
-                let decoded = #ethers_core::utils::hex::decode(#domain_separator)?;
-                let byte_array: [u8; 32] = <[u8; 32]>::try_from(&decoded[..])?;
-                Ok(byte_array)
-            }
-
-            fn domain(&self) -> Result<#ethers_core::types::transaction::eip712::EIP712Domain, Self::Error> {
-                let domain: #ethers_core::types::transaction::eip712::EIP712Domain = # ethers_core::utils::__serde_json::from_str(#domain_str)?;
-
-                Ok(domain)
-            }
-
-            fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
-                use #ethers_core::abi::Tokenizable;
-                let mut items = vec![#ethers_core::abi::Token::Uint(
-                    #ethers_core::types::U256::from(&Self::type_hash()?[..]),
-                )];
-
-                if let #ethers_core::abi::Token::Tuple(tokens) = self.clone().into_token() {
-                    for token in tokens {
-                        match &token {
-                            #ethers_core::abi::Token::Tuple(t) => {
-                                // TODO: check for nested Eip712 Type;
-                                // Challenge is determining the type hash
-                                return Err(Self::Error::NestedEip712StructNotImplemented);
-                            },
-                            _ => {
-                                items.push(#ethers_core::types::transaction::eip712::encode_eip712_type(token));
-                            }
-                        }
-                    }
-                }
-
-                let struct_hash = #ethers_core::utils::keccak256(#ethers_core::abi::encode(
-                    &items,
-                ));
-
-                Ok(struct_hash)
-            }
-        }
-    };
-
-    implementation.into()
-}
diff --git a/ethers-core/src/macros/ethers_crate.rs b/ethers-core/src/macros/ethers_crate.rs
index 83b20b5c..f30d2fe5 100644
--- a/ethers-core/src/macros/ethers_crate.rs
+++ b/ethers-core/src/macros/ethers_crate.rs
@@ -220,7 +220,6 @@ pub enum EthersCrate {
     EthersContractAbigen,
     EthersContractDerive,
     EthersCore,
-    EthersDeriveEip712,
     EthersEtherscan,
     EthersMiddleware,
     EthersProviders,
@@ -250,7 +249,6 @@ impl EthersCrate {
             Self::EthersContractAbigen => "ethers-contract-abigen",
             Self::EthersContractDerive => "ethers-contract-derive",
             Self::EthersCore => "ethers-core",
-            Self::EthersDeriveEip712 => "ethers-derive-eip712",
             Self::EthersEtherscan => "ethers-etherscan",
             Self::EthersMiddleware => "ethers-middleware",
             Self::EthersProviders => "ethers-providers",
@@ -268,7 +266,6 @@ impl EthersCrate {
             Self::EthersContractAbigen => "::ethers_contract_abigen",
             Self::EthersContractDerive => "::ethers_contract_derive",
             Self::EthersCore => "::ethers_core",
-            Self::EthersDeriveEip712 => "::ethers_derive_eip712",
             Self::EthersEtherscan => "::ethers_etherscan",
             Self::EthersMiddleware => "::ethers_middleware",
             Self::EthersProviders => "::ethers_providers",
@@ -284,7 +281,6 @@ impl EthersCrate {
             // re-exported in ethers::contract
             Self::EthersContractAbigen => "::ethers::contract", // partially
             Self::EthersContractDerive => "::ethers::contract",
-            Self::EthersDeriveEip712 => "::ethers::contract",
 
             Self::EthersAddressbook => "::ethers::addressbook",
             Self::EthersContract => "::ethers::contract",
@@ -303,7 +299,6 @@ impl EthersCrate {
         match self {
             Self::EthersContractAbigen => "ethers-contract/ethers-contract-abigen",
             Self::EthersContractDerive => "ethers-contract/ethers-contract-derive",
-            Self::EthersDeriveEip712 => "ethers-core/ethers-derive-eip712",
             _ => self.crate_name(),
         }
     }
diff --git a/ethers-core/src/types/chain.rs b/ethers-core/src/types/chain.rs
index 76bc50f3..60138ae8 100644
--- a/ethers-core/src/types/chain.rs
+++ b/ethers-core/src/types/chain.rs
@@ -321,13 +321,13 @@ impl Chain {
             PolygonMumbai |
             Avalanche |
             AvalancheFuji |
+            FilecoinMainnet |
             FilecoinHyperspaceTestnet => false,
 
             // Unknown / not applicable, default to false for backwards compatibility
             Dev | AnvilHardhat | Morden | Ropsten | Rinkeby | Cronos | CronosTestnet | Kovan |
             Sokol | Poa | XDai | Moonbeam | MoonbeamDev | Moonriver | Moonbase | Evmos |
-            EvmosTestnet | Chiado | Aurora | AuroraTestnet | Canto | CantoTestnet |
-            FilecoinMainnet => false,
+            EvmosTestnet | Chiado | Aurora | AuroraTestnet | Canto | CantoTestnet => false,
         }
     }
 
diff --git a/ethers-core/src/types/transaction/eip712.rs b/ethers-core/src/types/transaction/eip712.rs
index b608652a..d3df08a8 100644
--- a/ethers-core/src/types/transaction/eip712.rs
+++ b/ethers-core/src/types/transaction/eip712.rs
@@ -4,43 +4,35 @@ use crate::{
     types::{serde_helpers::StringifiedNumeric, Address, Bytes, U256},
     utils::keccak256,
 };
-use convert_case::{Case, Casing};
-use core::convert::TryFrom;
 use ethabi::encode;
-use proc_macro2::TokenStream;
 use serde::{Deserialize, Deserializer, Serialize};
 use std::{
     collections::{BTreeMap, HashSet},
-    convert::TryInto,
     iter::FromIterator,
 };
-use syn::{
-    parse::Error, spanned::Spanned as _, AttrStyle, Data, DeriveInput, Expr, Fields,
-    GenericArgument, Lit, NestedMeta, PathArguments, Type,
-};
 
 /// Custom types for `TypedData`
 pub type Types = BTreeMap<String, Vec<Eip712DomainType>>;
 
-/// Pre-computed value of the following statement:
+/// Pre-computed value of the following expression:
 ///
-/// `ethers_core::utils::keccak256("EIP712Domain(string name,string version,uint256 chainId,address
+/// `keccak256("EIP712Domain(string name,string version,uint256 chainId,address
 /// verifyingContract)")`
 pub const EIP712_DOMAIN_TYPE_HASH: [u8; 32] = [
     139, 115, 195, 198, 155, 184, 254, 61, 81, 46, 204, 76, 247, 89, 204, 121, 35, 159, 123, 23,
     155, 15, 250, 202, 169, 167, 93, 82, 43, 57, 64, 15,
 ];
 
-/// Pre-computed value of the following statement:
+/// Pre-computed value of the following expression:
 ///
-/// `ethers_core::utils::keccak256("EIP712Domain(string name,string version,uint256 chainId,address
+/// `keccak256("EIP712Domain(string name,string version,uint256 chainId,address
 /// verifyingContract,bytes32 salt)")`
 pub const EIP712_DOMAIN_TYPE_HASH_WITH_SALT: [u8; 32] = [
     216, 124, 214, 239, 121, 212, 226, 185, 94, 21, 206, 138, 191, 115, 45, 181, 30, 199, 113, 241,
     202, 46, 220, 207, 34, 164, 108, 114, 154, 197, 100, 114,
 ];
 
-/// Error typed used by Eip712 derive macro
+/// An EIP-712 error.
 #[derive(Debug, thiserror::Error)]
 pub enum Eip712Error {
     #[error("Failed to serialize serde JSON object")]
@@ -57,8 +49,7 @@ pub enum Eip712Error {
     Message(String),
 }
 
-/// The Eip712 trait provides helper methods for computing
-/// the typed data hash used in `eth_signTypedData`.
+/// Helper methods for computing the typed data hash used in `eth_signTypedData`.
 ///
 /// The ethers-rs `derive_eip712` crate provides a derive macro to
 /// implement the trait for a given struct. See documentation
@@ -245,233 +236,40 @@ impl<T: Eip712 + Clone> Eip712 for EIP712WithDomain<T> {
     }
 }
 
-// Parse the AST of the struct to determine the domain attributes
-impl TryFrom<&syn::DeriveInput> for EIP712Domain {
-    type Error = TokenStream;
-    fn try_from(input: &syn::DeriveInput) -> Result<EIP712Domain, Self::Error> {
-        let mut domain = EIP712Domain::default();
-
-        let mut found_eip712_attribute = false;
-
-        'attribute_search: for attribute in input.attrs.iter() {
-            if let AttrStyle::Outer = attribute.style {
-                if let Ok(syn::Meta::List(meta)) = attribute.parse_meta() {
-                    if meta.path.is_ident("eip712") {
-                        found_eip712_attribute = true;
-
-                        for n in meta.nested.iter() {
-                            if let NestedMeta::Meta(meta) = n {
-                                match meta {
-                                    syn::Meta::NameValue(meta) => {
-                                        let ident = meta.path.get_ident().ok_or_else(|| {
-                                            Error::new(
-                                                meta.path.span(),
-                                                "unrecognized eip712 parameter",
-                                            )
-                                            .to_compile_error()
-                                        })?;
-
-                                        match ident.to_string().as_ref() {
-                                            "name" => match meta.lit {
-                                                syn::Lit::Str(ref lit_str) => {
-                                                    if domain.name.is_some() {
-                                                        return Err(Error::new(
-                                                            meta.path.span(),
-                                                            "domain name already specified",
-                                                        )
-                                                        .to_compile_error())
-                                                    }
-
-                                                    domain.name = Some(lit_str.value());
-                                                }
-                                                _ => {
-                                                    return Err(Error::new(
-                                                        meta.path.span(),
-                                                        "domain name must be a string",
-                                                    )
-                                                    .to_compile_error())
-                                                }
-                                            },
-                                            "version" => match meta.lit {
-                                                syn::Lit::Str(ref lit_str) => {
-                                                    if domain.version.is_some() {
-                                                        return Err(Error::new(
-                                                            meta.path.span(),
-                                                            "domain version already specified",
-                                                        )
-                                                        .to_compile_error())
-                                                    }
-
-                                                    domain.version = Some(lit_str.value());
-                                                }
-                                                _ => {
-                                                    return Err(Error::new(
-                                                        meta.path.span(),
-                                                        "domain version must be a string",
-                                                    )
-                                                    .to_compile_error())
-                                                }
-                                            },
-                                            "chain_id" => match meta.lit {
-                                                syn::Lit::Int(ref lit_int) => {
-                                                    if domain.chain_id.is_some() {
-                                                        return Err(Error::new(
-                                                            meta.path.span(),
-                                                            "domain chain_id already specified",
-                                                        )
-                                                        .to_compile_error())
-                                                    }
-
-                                                    domain.chain_id = Some(U256::from(
-                                                        lit_int.base10_parse::<u64>().map_err(
-                                                            |_| {
-                                                                Error::new(
-                                                                    meta.path.span(),
-                                                                    "failed to parse chain id",
-                                                                )
-                                                                .to_compile_error()
-                                                            },
-                                                        )?,
-                                                    ));
-                                                }
-                                                _ => {
-                                                    return Err(Error::new(
-                                                        meta.path.span(),
-                                                        "domain chain_id must be a positive integer",
-                                                    )
-                                                    .to_compile_error());
-                                                }
-                                            },
-                                            "verifying_contract" => match meta.lit {
-                                                syn::Lit::Str(ref lit_str) => {
-                                                    if domain.verifying_contract.is_some() {
-                                                        return Err(Error::new(
-                                                            meta.path.span(),
-                                                            "domain verifying_contract already specified",
-                                                        )
-                                                        .to_compile_error());
-                                                    }
-
-                                                    domain.verifying_contract = Some(lit_str.value().parse().map_err(|_| {
-                                                            Error::new(
-                                                                meta.path.span(),
-                                                                "failed to parse verifying contract into Address",
-                                                            )
-                                                            .to_compile_error()
-                                                        })?);
-                                                }
-                                                _ => {
-                                                    return Err(Error::new(
-                                                        meta.path.span(),
-                                                        "domain verifying_contract must be a string",
-                                                    )
-                                                    .to_compile_error());
-                                                }
-                                            },
-                                            "salt" => match meta.lit {
-                                                syn::Lit::Str(ref lit_str) => {
-                                                    if domain.salt.is_some() {
-                                                        return Err(Error::new(
-                                                            meta.path.span(),
-                                                            "domain salt already specified",
-                                                        )
-                                                        .to_compile_error())
-                                                    }
-
-                                                    // keccak256(<string>) to compute bytes32
-                                                    // encoded domain salt
-                                                    let salt = keccak256(lit_str.value());
-
-                                                    domain.salt = Some(salt);
-                                                }
-                                                _ => {
-                                                    return Err(Error::new(
-                                                        meta.path.span(),
-                                                        "domain salt must be a string",
-                                                    )
-                                                    .to_compile_error())
-                                                }
-                                            },
-                                            _ => {
-                                                return Err(Error::new(
-                                                    meta.path.span(),
-                                                    "unrecognized eip712 parameter; must be one of 'name', 'version', 'chain_id', or 'verifying_contract'",
-                                                )
-                                                .to_compile_error());
-                                            }
-                                        }
-                                    }
-                                    syn::Meta::Path(path) => {
-                                        return Err(Error::new(
-                                            path.span(),
-                                            "unrecognized eip712 parameter",
-                                        )
-                                        .to_compile_error())
-                                    }
-                                    syn::Meta::List(meta) => {
-                                        return Err(Error::new(
-                                            meta.path.span(),
-                                            "unrecognized eip712 parameter",
-                                        )
-                                        .to_compile_error())
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-                    break 'attribute_search
-                }
-            }
-        }
-
-        if !found_eip712_attribute {
-            return Err(Error::new_spanned(
-                input,
-                "missing required derive attribute: '#[eip712( ... )]'".to_string(),
-            )
-            .to_compile_error())
-        }
-
-        Ok(domain)
-    }
-}
-
 /// Represents the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data object.
 ///
 /// Typed data is a JSON object containing type information, domain separator parameters and the
 /// message object which has the following schema
 ///
-/// ```js
+/// ```json
 /// {
-//   type: 'object',
-//   properties: {
-//     types: {
-//       type: 'object',
-//       properties: {
-//         EIP712Domain: {type: 'array'},
-//       },
-//       additionalProperties: {
-//         type: 'array',
-//         items: {
-//           type: 'object',
-//           properties: {
-//             name: {type: 'string'},
-//             type: {type: 'string'}
-//           },
-//           required: ['name', 'type']
-//         }
-//       },
-//       required: ['EIP712Domain']
-//     },
-//     primaryType: {type: 'string'},
-//     domain: {type: 'object'},
-//     message: {type: 'object'}
-//   },
-//   required: ['types', 'primaryType', 'domain', 'message']
-// }
+///     "type": "object",
+///     "properties": {
+///         "types": {
+///             "type": "object",
+///             "properties": {
+///                 "EIP712Domain": { "type": "array" }
+///             },
+///             "additionalProperties": {
+///                 "type": "array",
+///                 "items": {
+///                     "type": "object",
+///                     "properties": {
+///                         "name": { "type": "string" },
+///                         "type": { "type": "string" }
+///                     },
+///                     "required": ["name", "type"]
+///                 }
+///             },
+///             "required": ["EIP712Domain"]
+///         },
+///         "primaryType": { "type": "string" },
+///         "domain": { "type": "object" },
+///         "message": { "type": "object" }
+///     },
+///     "required": ["types", "primaryType", "domain", "message"]
+/// }
 /// ```
-///
 #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
 #[serde(deny_unknown_fields)]
 pub struct TypedData {
@@ -772,137 +570,6 @@ pub fn encode_field(
     Ok(token)
 }
 
-/// Parse the eth abi parameter type based on the syntax type;
-/// this method is copied from <https://github.com/gakonst/ethers-rs/blob/master/ethers-contract/ethers-contract-derive/src/lib.rs#L600>
-/// with additional modifications for finding byte arrays
-pub fn find_parameter_type(ty: &Type) -> Result<ParamType, TokenStream> {
-    match ty {
-        Type::Array(ty) => {
-            let param = find_parameter_type(ty.elem.as_ref())?;
-            if let Expr::Lit(ref expr) = ty.len {
-                if let Lit::Int(ref len) = expr.lit {
-                    if let Ok(size) = len.base10_parse::<usize>() {
-                        if let ParamType::Uint(_) = param {
-                            return Ok(ParamType::FixedBytes(size))
-                        }
-
-                        return Ok(ParamType::FixedArray(Box::new(param), size))
-                    }
-                }
-            }
-            Err(Error::new(ty.span(), "Failed to derive proper ABI from array field")
-                .to_compile_error())
-        }
-        Type::Path(ty) => {
-            if let Some(ident) = ty.path.get_ident() {
-                let ident = ident.to_string().to_lowercase();
-                return match ident.as_str() {
-                    "address" => Ok(ParamType::Address),
-                    "string" => Ok(ParamType::String),
-                    "bool" => Ok(ParamType::Bool),
-                    "int256" | "int" | "uint" | "uint256" => Ok(ParamType::Uint(256)),
-                    "h160" => Ok(ParamType::FixedBytes(20)),
-                    "h256" | "secret" | "hash" => Ok(ParamType::FixedBytes(32)),
-                    "h512" | "public" => Ok(ParamType::FixedBytes(64)),
-                    "bytes" => Ok(ParamType::Bytes),
-                    s => parse_int_param_type(s).ok_or_else(|| {
-                        Error::new(
-                            ty.span(),
-                            format!("Failed to derive proper ABI from field: {s})"),
-                        )
-                        .to_compile_error()
-                    }),
-                }
-            }
-            // check for `Vec`
-            if ty.path.segments.len() == 1 && ty.path.segments[0].ident == "Vec" {
-                if let PathArguments::AngleBracketed(ref args) = ty.path.segments[0].arguments {
-                    if args.args.len() == 1 {
-                        if let GenericArgument::Type(ref ty) = args.args.iter().next().unwrap() {
-                            let kind = find_parameter_type(ty)?;
-
-                            // Check if byte array is found
-                            if let ParamType::Uint(size) = kind {
-                                if size == 8 {
-                                    return Ok(ParamType::Bytes)
-                                }
-                            }
-
-                            return Ok(ParamType::Array(Box::new(kind)))
-                        }
-                    }
-                }
-            }
-
-            Err(Error::new(ty.span(), "Failed to derive proper ABI from fields").to_compile_error())
-        }
-        Type::Tuple(ty) => {
-            let params = ty.elems.iter().map(find_parameter_type).collect::<Result<Vec<_>, _>>()?;
-            Ok(ParamType::Tuple(params))
-        }
-        _ => {
-            Err(Error::new(ty.span(), "Failed to derive proper ABI from fields").to_compile_error())
-        }
-    }
-}
-
-fn parse_int_param_type(s: &str) -> Option<ParamType> {
-    let size = s.chars().skip(1).collect::<String>().parse::<usize>().ok()?;
-    if s.starts_with('u') {
-        Some(ParamType::Uint(size))
-    } else if s.starts_with('i') {
-        Some(ParamType::Int(size))
-    } else {
-        None
-    }
-}
-
-/// Return HashMap of the field name and the field type;
-pub fn parse_fields(ast: &DeriveInput) -> Result<Vec<(String, ParamType)>, TokenStream> {
-    let mut fields = Vec::new();
-
-    let data = match &ast.data {
-        Data::Struct(s) => s,
-        _ => {
-            return Err(Error::new(
-                ast.span(),
-                "invalid data type. can only derive Eip712 for a struct",
-            )
-            .to_compile_error())
-        }
-    };
-
-    let named_fields = match &data.fields {
-        Fields::Named(name) => name,
-        _ => {
-            return Err(Error::new(ast.span(), "unnamed fields are not supported").to_compile_error())
-        }
-    };
-
-    for f in named_fields.named.iter() {
-        let field_name =
-            f.ident.clone().map(|i| i.to_string().to_case(Case::Camel)).ok_or_else(|| {
-                Error::new(named_fields.span(), "fields must be named").to_compile_error()
-            })?;
-
-        let field_type =
-            match f.attrs.iter().find(|a| a.path.segments.iter().any(|s| s.ident == "eip712")) {
-                // Found nested Eip712 Struct
-                // TODO: Implement custom
-                Some(a) => {
-                    return Err(Error::new(a.span(), "nested Eip712 struct are not yet supported")
-                        .to_compile_error())
-                }
-                // Not a nested eip712 struct, return the field param type;
-                None => find_parameter_type(&f.ty)?,
-            };
-
-        fields.push((field_name, field_type));
-    }
-
-    Ok(fields)
-}
-
 /// Convert hash map of field names and types into a type hash corresponding to enc types;
 pub fn make_type_hash(primary_type: String, fields: &[(String, ParamType)]) -> [u8; 32] {
     let parameters =
diff --git a/ethers-core/src/types/transaction/mod.rs b/ethers-core/src/types/transaction/mod.rs
index 816f4539..41c277cb 100644
--- a/ethers-core/src/types/transaction/mod.rs
+++ b/ethers-core/src/types/transaction/mod.rs
@@ -5,7 +5,6 @@ pub mod eip1559;
 pub mod eip2718;
 pub mod eip2930;
 
-#[cfg(feature = "eip712")]
 pub mod eip712;
 
 pub(crate) const BASE_NUM_TX_FIELDS: usize = 9;
diff --git a/ethers-core/src/utils/mod.rs b/ethers-core/src/utils/mod.rs
index bda3e97e..7ec7e9ba 100644
--- a/ethers-core/src/utils/mod.rs
+++ b/ethers-core/src/utils/mod.rs
@@ -52,11 +52,9 @@ const OVERFLOW_I256_UNITS: usize = 77;
 /// U256 overflows for numbers wider than 78 units.
 const OVERFLOW_U256_UNITS: usize = 78;
 
-/// Re-export of serde-json
+// Re-export serde-json for macro usage
 #[doc(hidden)]
-pub mod __serde_json {
-    pub use serde_json::*;
-}
+pub use serde_json as __serde_json;
 
 #[derive(Error, Debug)]
 pub enum ConversionError {
diff --git a/ethers-etherscan/Cargo.toml b/ethers-etherscan/Cargo.toml
index b402810b..6e503985 100644
--- a/ethers-etherscan/Cargo.toml
+++ b/ethers-etherscan/Cargo.toml
@@ -47,7 +47,7 @@ ethers-solc.workspace = true
 
 tempfile.workspace = true
 tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] }
-serial_test = "1.0.0"
+serial_test = "2.0.0"
 tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
 
 [features]
diff --git a/ethers-providers/Cargo.toml b/ethers-providers/Cargo.toml
index 210ffedd..82f7b344 100644
--- a/ethers-providers/Cargo.toml
+++ b/ethers-providers/Cargo.toml
@@ -75,7 +75,7 @@ getrandom.workspace = true
 
 [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
 tokio = { workspace = true, features = ["rt", "macros", "time"] }
-tempfile = "3.4.0"
+tempfile = "3.5.0"
 
 [features]
 default = ["ws", "rustls"]
diff --git a/ethers-signers/Cargo.toml b/ethers-signers/Cargo.toml
index cd23c776..e6a77af1 100644
--- a/ethers-signers/Cargo.toml
+++ b/ethers-signers/Cargo.toml
@@ -24,11 +24,11 @@ rustdoc-args = ["--cfg", "docsrs"]
 all-features = true
 
 [dependencies]
-ethers-core = { workspace = true, features = ["eip712"] }
+ethers-core.workspace = true
 
 # crypto
 coins-bip32 = "0.8.3"
-coins-bip39 = "0.8.3"
+coins-bip39 = "0.8.5"
 elliptic-curve.workspace = true
 sha2.workspace = true
 rand.workspace = true
@@ -66,7 +66,6 @@ yubihsm = { version = "0.42.0-pre.0", features = ["secp256k1", "http", "usb"], o
 
 [dev-dependencies]
 ethers-contract-derive.workspace = true
-ethers-derive-eip712.workspace = true
 
 serde_json.workspace = true
 tempfile.workspace = true
diff --git a/ethers-signers/src/ledger/app.rs b/ethers-signers/src/ledger/app.rs
index 05adbc2f..bed0741c 100644
--- a/ethers-signers/src/ledger/app.rs
+++ b/ethers-signers/src/ledger/app.rs
@@ -293,11 +293,10 @@ impl LedgerEthereum {
 mod tests {
     use super::*;
     use crate::Signer;
-    use ethers_contract_derive::EthAbiType;
+    use ethers_contract_derive::{Eip712, EthAbiType};
     use ethers_core::types::{
         transaction::eip712::Eip712, Address, TransactionRequest, I256, U256,
     };
-    use ethers_derive_eip712::*;
     use std::str::FromStr;
 
     #[derive(Debug, Clone, Eip712, EthAbiType)]
diff --git a/ethers-signers/src/trezor/app.rs b/ethers-signers/src/trezor/app.rs
index a9e7b555..471e4e58 100644
--- a/ethers-signers/src/trezor/app.rs
+++ b/ethers-signers/src/trezor/app.rs
@@ -233,7 +233,7 @@ impl TrezorEthereum {
 mod tests {
     use super::*;
     use crate::Signer;
-    use ethers_contract_derive::EthAbiType;
+    use ethers_contract_derive::{Eip712, EthAbiType};
     use ethers_core::types::{
         transaction::{
             eip2930::{AccessList, AccessListItem},
@@ -241,7 +241,6 @@ mod tests {
         },
         Address, Eip1559TransactionRequest, TransactionRequest, I256, U256,
     };
-    use ethers_derive_eip712::*;
     use std::str::FromStr;
 
     #[derive(Debug, Clone, Eip712, EthAbiType)]
diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml
index d4102ceb..7dfc1792 100644
--- a/ethers-solc/Cargo.toml
+++ b/ethers-solc/Cargo.toml
@@ -53,7 +53,7 @@ rayon.workspace = true
 path-slash = "0.2.1"
 cfg-if = "1.0.0"
 
-tempfile = { version = "3.4.0", optional = true }
+tempfile = { version = "3.5.0", optional = true }
 fs_extra = { version = "1.3.0", optional = true }
 rand = { workspace = true, optional = true }
 futures-util = { workspace = true, optional = true }
@@ -77,7 +77,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
 rand.workspace = true
 pretty_assertions = "1.3.0"
 tempfile.workspace = true
-serde_path_to_error = "0.1.10"
+serde_path_to_error = "0.1.11"
 
 [[bench]]
 name = "compile_many"
diff --git a/ethers-solc/src/artifacts/mod.rs b/ethers-solc/src/artifacts/mod.rs
index 37eb52b1..4ef62da8 100644
--- a/ethers-solc/src/artifacts/mod.rs
+++ b/ethers-solc/src/artifacts/mod.rs
@@ -103,67 +103,13 @@ impl CompilerInput {
 
     /// This will remove/adjust values in the `CompilerInput` that are not compatible with this
     /// version
-    pub fn sanitized(mut self, version: &Version) -> Self {
-        static PRE_V0_6_0: once_cell::sync::Lazy<VersionReq> =
-            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.6.0").unwrap());
-        static PRE_V0_7_5: once_cell::sync::Lazy<VersionReq> =
-            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.7.5").unwrap());
-        static PRE_V0_8_7: once_cell::sync::Lazy<VersionReq> =
-            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.8.7").unwrap());
-        static PRE_V0_8_10: once_cell::sync::Lazy<VersionReq> =
-            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.8.10").unwrap());
-        static PRE_V0_8_18: once_cell::sync::Lazy<VersionReq> =
-            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.8.18").unwrap());
-
-        if PRE_V0_6_0.matches(version) {
-            if let Some(ref mut meta) = self.settings.metadata {
-                // introduced in <https://docs.soliditylang.org/en/v0.6.0/using-the-compiler.html#compiler-api>
-                // missing in <https://docs.soliditylang.org/en/v0.5.17/using-the-compiler.html#compiler-api>
-                meta.bytecode_hash.take();
-            }
-            // introduced in <https://docs.soliditylang.org/en/v0.6.0/using-the-compiler.html#compiler-api>
-            let _ = self.settings.debug.take();
-        }
-
-        if PRE_V0_7_5.matches(version) {
-            // introduced in 0.7.5 <https://github.com/ethereum/solidity/releases/tag/v0.7.5>
-            self.settings.via_ir.take();
-        }
-
-        if PRE_V0_8_7.matches(version) {
-            // lower the disable version from 0.8.10 to 0.8.7, due to `divModNoSlacks`,
-            // `showUnproved` and `solvers` are implemented
-            // introduced in <https://github.com/ethereum/solidity/releases/tag/v0.8.7>
-            self.settings.model_checker = None;
-        }
-
-        if PRE_V0_8_10.matches(version) {
-            if let Some(ref mut debug) = self.settings.debug {
-                // introduced in <https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html#compiler-api>
-                // <https://github.com/ethereum/solidity/releases/tag/v0.8.10>
-                debug.debug_info.clear();
-            }
-
-            if let Some(ref mut model_checker) = self.settings.model_checker {
-                // introduced in <https://github.com/ethereum/solidity/releases/tag/v0.8.10>
-                model_checker.invariants = None;
-            }
-        }
-
-        if PRE_V0_8_18.matches(version) {
-            // introduced in 0.8.18 <https://github.com/ethereum/solidity/releases/tag/v0.8.18>
-            if let Some(ref mut meta) = self.settings.metadata {
-                meta.cbor_metadata = None;
-            }
-
-            if let Some(ref mut model_checker) = self.settings.model_checker {
-                if let Some(ref mut solvers) = model_checker.solvers {
-                    // elf solver introduced in 0.8.18 <https://github.com/ethereum/solidity/releases/tag/v0.8.18>
-                    solvers.retain(|solver| *solver != ModelCheckerSolver::Eld);
-                }
-            }
-        }
+    pub fn sanitize(&mut self, version: &Version) {
+        self.settings.sanitize(version)
+    }
 
+    /// Consumes the type and returns a [CompilerInput::sanitized] version
+    pub fn sanitized(mut self, version: &Version) -> Self {
+        self.settings.sanitize(version);
         self
     }
 
@@ -353,6 +299,76 @@ impl Settings {
         Self { output_selection: output_selection.into(), ..Default::default() }
     }
 
+    /// Consumes the type and returns a [Settings::sanitize] version
+    pub fn sanitized(mut self, version: &Version) -> Self {
+        self.sanitize(version);
+        self
+    }
+
+    /// This will remove/adjust values in the settings that are not compatible with this
+    /// version
+    pub fn sanitize(&mut self, version: &Version) {
+        static PRE_V0_6_0: once_cell::sync::Lazy<VersionReq> =
+            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.6.0").unwrap());
+        static PRE_V0_7_5: once_cell::sync::Lazy<VersionReq> =
+            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.7.5").unwrap());
+        static PRE_V0_8_7: once_cell::sync::Lazy<VersionReq> =
+            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.8.7").unwrap());
+        static PRE_V0_8_10: once_cell::sync::Lazy<VersionReq> =
+            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.8.10").unwrap());
+        static PRE_V0_8_18: once_cell::sync::Lazy<VersionReq> =
+            once_cell::sync::Lazy::new(|| VersionReq::parse("<0.8.18").unwrap());
+
+        if PRE_V0_6_0.matches(version) {
+            if let Some(ref mut meta) = self.metadata {
+                // introduced in <https://docs.soliditylang.org/en/v0.6.0/using-the-compiler.html#compiler-api>
+                // missing in <https://docs.soliditylang.org/en/v0.5.17/using-the-compiler.html#compiler-api>
+                meta.bytecode_hash.take();
+            }
+            // introduced in <https://docs.soliditylang.org/en/v0.6.0/using-the-compiler.html#compiler-api>
+            let _ = self.debug.take();
+        }
+
+        if PRE_V0_7_5.matches(version) {
+            // introduced in 0.7.5 <https://github.com/ethereum/solidity/releases/tag/v0.7.5>
+            self.via_ir.take();
+        }
+
+        if PRE_V0_8_7.matches(version) {
+            // lower the disable version from 0.8.10 to 0.8.7, due to `divModNoSlacks`,
+            // `showUnproved` and `solvers` are implemented
+            // introduced in <https://github.com/ethereum/solidity/releases/tag/v0.8.7>
+            self.model_checker = None;
+        }
+
+        if PRE_V0_8_10.matches(version) {
+            if let Some(ref mut debug) = self.debug {
+                // introduced in <https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html#compiler-api>
+                // <https://github.com/ethereum/solidity/releases/tag/v0.8.10>
+                debug.debug_info.clear();
+            }
+
+            if let Some(ref mut model_checker) = self.model_checker {
+                // introduced in <https://github.com/ethereum/solidity/releases/tag/v0.8.10>
+                model_checker.invariants = None;
+            }
+        }
+
+        if PRE_V0_8_18.matches(version) {
+            // introduced in 0.8.18 <https://github.com/ethereum/solidity/releases/tag/v0.8.18>
+            if let Some(ref mut meta) = self.metadata {
+                meta.cbor_metadata = None;
+            }
+
+            if let Some(ref mut model_checker) = self.model_checker {
+                if let Some(ref mut solvers) = model_checker.solvers {
+                    // elf solver introduced in 0.8.18 <https://github.com/ethereum/solidity/releases/tag/v0.8.18>
+                    solvers.retain(|solver| *solver != ModelCheckerSolver::Eld);
+                }
+            }
+        }
+    }
+
     /// Inserts a set of `ContractOutputSelection`
     pub fn push_all(&mut self, settings: impl IntoIterator<Item = ContractOutputSelection>) {
         for value in settings {
diff --git a/ethers/Cargo.toml b/ethers/Cargo.toml
index 9db13a3e..c25379da 100644
--- a/ethers/Cargo.toml
+++ b/ethers/Cargo.toml
@@ -26,18 +26,36 @@ all-features = true
 [features]
 default = ["abigen", "rustls"]
 
-celo = ["ethers-core/celo", "ethers-providers/celo", "ethers-signers/celo", "ethers-contract/celo", "ethers-middleware/celo", "legacy"]
+celo = [
+    "ethers-core/celo",
+    "ethers-providers/celo",
+    "ethers-signers/celo",
+    "ethers-contract/celo",
+    "ethers-middleware/celo",
+    "legacy",
+]
 
 legacy = ["ethers-core/legacy", "ethers-contract/legacy"]
 
 # individual features per sub-crate
-## core
-eip712 = ["ethers-contract/eip712", "ethers-core/eip712"]
 ## providers
 ws = ["ethers-providers/ws"]
+legacy-ws = ["ethers-providers/legacy-ws"]
 ipc = ["ethers-providers/ipc"]
-rustls = ["ethers-middleware/rustls", "ethers-providers/rustls", "ethers-etherscan/rustls", "ethers-contract/rustls", "ethers-solc/rustls"]
-openssl = ["ethers-middleware/openssl", "ethers-providers/openssl", "ethers-etherscan/openssl", "ethers-contract/openssl", "ethers-solc/openssl"]
+rustls = [
+    "ethers-middleware/rustls",
+    "ethers-providers/rustls",
+    "ethers-etherscan/rustls",
+    "ethers-contract/rustls",
+    "ethers-solc/rustls",
+]
+openssl = [
+    "ethers-middleware/openssl",
+    "ethers-providers/openssl",
+    "ethers-etherscan/openssl",
+    "ethers-contract/openssl",
+    "ethers-solc/openssl",
+]
 dev-rpc = ["ethers-providers/dev-rpc"]
 ## signers
 ledger = ["ethers-signers/ledger"]
@@ -53,6 +71,7 @@ solc-tests = ["ethers-solc/tests"]
 
 # Deprecated
 solc-sha2-asm = []
+eip712 = []
 
 [dependencies]
 ethers-addressbook.workspace = true
@@ -67,6 +86,6 @@ ethers-solc.workspace = true
 [dev-dependencies]
 serde.workspace = true
 tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
-ethers-contract = { workspace = true, features = ["eip712"] }
+ethers-contract.workspace = true
 ethers-providers = { workspace = true, features = ["rustls"] } # allow https connections
 ethers-solc = { workspace = true, features = ["svm-solc"] }
diff --git a/examples/wallets/Cargo.toml b/examples/wallets/Cargo.toml
index 483c46d8..8c82e345 100644
--- a/examples/wallets/Cargo.toml
+++ b/examples/wallets/Cargo.toml
@@ -15,7 +15,7 @@ trezor = ["ethers/trezor"]
 yubi = ["ethers/yubi"]
 
 [dev-dependencies]
-ethers = { workspace = true, features = ["abigen", "eip712", "ws", "rustls"] }
+ethers = { workspace = true, features = ["abigen", "ws", "rustls"] }
 
 tokio = { workspace = true, features = ["macros"] }
 


Test patch:
diff --git a/ethers-contract/tests/it/contract.rs b/ethers-contract/tests/it/contract.rs
index 88f04ed5..eb5b0c8b 100644
--- a/ethers-contract/tests/it/contract.rs
+++ b/ethers-contract/tests/it/contract.rs
@@ -1,14 +1,18 @@
 use crate::common::*;
 use ethers_contract::{
-    abigen, ContractFactory, ContractInstance, EthEvent, LogMeta, Multicall, MulticallError,
-    MulticallVersion,
+    abigen, ContractFactory, ContractInstance, Eip712, EthAbiType, EthEvent, LogMeta, Multicall,
+    MulticallError, MulticallVersion,
 };
 use ethers_core::{
     abi::{encode, AbiEncode, Token, Tokenizable},
-    types::{Address, BlockId, Bytes, Filter, ValueOrArray, H160, H256, U256},
+    types::{
+        transaction::eip712::*, Address, BlockId, Bytes, Filter, ValueOrArray, H160, H256, I256,
+        U256,
+    },
     utils::{keccak256, Anvil},
 };
-use ethers_providers::{Http, Middleware, MiddlewareError, Provider, StreamExt};
+use ethers_providers::{Http, Middleware, MiddlewareError, Provider, StreamExt, Ws};
+use ethers_signers::{LocalWallet, Signer};
 use std::{sync::Arc, time::Duration};
 
 #[derive(Debug)]
@@ -337,7 +341,7 @@ async fn watch_events() {
     let mut stream = event.stream().await.unwrap();
 
     // Also set up a subscription for the same thing
-    let ws = Provider::connect(anvil.ws_endpoint()).await.unwrap();
+    let ws = Provider::<Ws>::connect(anvil.ws_endpoint()).await.unwrap();
     let contract2 = ethers_contract::Contract::new(contract.address(), abi, ws.into());
     let event2 = contract2.event::<ValueChanged>();
     let mut subscription = event2.subscribe().await.unwrap();
@@ -376,7 +380,7 @@ async fn watch_subscription_events_multiple_addresses() {
     let contract_1 = deploy(client.clone(), abi.clone(), bytecode.clone()).await;
     let contract_2 = deploy(client.clone(), abi.clone(), bytecode).await;
 
-    let ws = Provider::connect(anvil.ws_endpoint()).await.unwrap();
+    let ws = Provider::<Ws>::connect(anvil.ws_endpoint()).await.unwrap();
     let filter = Filter::new()
         .address(ValueOrArray::Array(vec![contract_1.address(), contract_2.address()]));
     let mut stream = ws.subscribe_logs(&filter).await.unwrap();
@@ -779,3 +783,129 @@ async fn multicall_aggregate() {
     assert_eq!(bytes[..4], keccak256("CustomErrorWithData(string)")[..4]);
     assert_eq!(bytes[4..], encode(&[Token::String("Data".to_string())]));
 }
+
+#[tokio::test]
+async fn test_derive_eip712() {
+    // Generate Contract ABI Bindings
+    mod contract {
+        ethers_contract::abigen!(
+            DeriveEip712Test,
+            "./ethers-contract/tests/solidity-contracts/DeriveEip712Test.json",
+            derives(serde::Deserialize, serde::Serialize)
+        );
+    }
+
+    // Create derived structs
+
+    #[derive(Debug, Clone, Eip712, EthAbiType)]
+    #[eip712(
+        name = "Eip712Test",
+        version = "1",
+        chain_id = 1,
+        verifying_contract = "0x0000000000000000000000000000000000000001",
+        salt = "eip712-test-75F0CCte"
+    )]
+    struct FooBar {
+        foo: I256,
+        bar: U256,
+        fizz: Bytes,
+        buzz: [u8; 32],
+        far: String,
+        out: Address,
+    }
+
+    // launch the network & connect to it
+    let anvil = Anvil::new().spawn();
+    let wallet: LocalWallet = anvil.keys()[0].clone().into();
+    let provider = Provider::try_from(anvil.endpoint())
+        .unwrap()
+        .with_sender(wallet.address())
+        .interval(std::time::Duration::from_millis(10));
+    let client = Arc::new(provider);
+
+    let contract: contract::DeriveEip712Test<_> =
+        contract::DeriveEip712Test::deploy(client.clone(), ()).unwrap().send().await.unwrap();
+
+    let foo_bar = FooBar {
+        foo: I256::from(10u64),
+        bar: U256::from(20u64),
+        fizz: b"fizz".into(),
+        buzz: keccak256("buzz"),
+        far: String::from("space"),
+        out: Address::zero(),
+    };
+
+    let derived_foo_bar = contract::FooBar {
+        foo: foo_bar.foo,
+        bar: foo_bar.bar,
+        fizz: foo_bar.fizz.clone(),
+        buzz: foo_bar.buzz,
+        far: foo_bar.far.clone(),
+        out: foo_bar.out,
+    };
+
+    let sig = wallet.sign_typed_data(&foo_bar).await.expect("failed to sign typed data");
+
+    let mut r = [0; 32];
+    sig.r.to_big_endian(&mut r);
+    let mut s = [0; 32];
+    sig.s.to_big_endian(&mut s);
+    let v = sig.v as u8;
+
+    let domain_separator = contract
+        .domain_separator()
+        .call()
+        .await
+        .expect("failed to retrieve domain_separator from contract");
+    let type_hash =
+        contract.type_hash().call().await.expect("failed to retrieve type_hash from contract");
+    let struct_hash = contract
+        .struct_hash(derived_foo_bar.clone())
+        .call()
+        .await
+        .expect("failed to retrieve struct_hash from contract");
+    let encoded = contract
+        .encode_eip_712(derived_foo_bar.clone())
+        .call()
+        .await
+        .expect("failed to retrieve eip712 encoded hash from contract");
+    let verify = contract
+        .verify_foo_bar(wallet.address(), derived_foo_bar, r, s, v)
+        .call()
+        .await
+        .expect("failed to verify signed typed data eip712 payload");
+
+    assert_eq!(
+        domain_separator,
+        foo_bar
+            .domain()
+            .expect("failed to return domain_separator from Eip712 implemented struct")
+            .separator(),
+        "domain separator does not match contract domain separator!"
+    );
+
+    assert_eq!(
+        type_hash,
+        FooBar::type_hash().expect("failed to return type_hash from Eip712 implemented struct"),
+        "type hash does not match contract struct type hash!"
+    );
+
+    assert_eq!(
+        struct_hash,
+        foo_bar
+            .clone()
+            .struct_hash()
+            .expect("failed to return struct_hash from Eip712 implemented struct"),
+        "struct hash does not match contract struct hash!"
+    );
+
+    assert_eq!(
+        encoded,
+        foo_bar
+            .encode_eip712()
+            .expect("failed to return domain_separator from Eip712 implemented struct"),
+        "Encoded value does not match!"
+    );
+
+    assert!(verify, "typed data signature failed!");
+}
diff --git a/ethers-core/ethers-derive-eip712/tests/derive_eip712.rs b/ethers-contract/tests/it/eip712.rs
similarity index 97%
rename from ethers-core/ethers-derive-eip712/tests/derive_eip712.rs
rename to ethers-contract/tests/it/eip712.rs
index 7018f1dc..82ded36a 100644
--- a/ethers-core/ethers-derive-eip712/tests/derive_eip712.rs
+++ b/ethers-contract/tests/it/eip712.rs
@@ -1,6 +1,4 @@
-#![allow(clippy::extra_unused_type_parameters)]
-
-use ethers_contract_derive::EthAbiType;
+use ethers_contract_derive::{Eip712, EthAbiType};
 use ethers_core::{
     types::{
         transaction::eip712::{
@@ -11,7 +9,6 @@ use ethers_core::{
     },
     utils::{keccak256, parse_ether},
 };
-use ethers_derive_eip712::*;
 
 #[test]
 fn test_derive_eip712() {
diff --git a/ethers-contract/tests/it/main.rs b/ethers-contract/tests/it/main.rs
index 135d053a..9e1f2888 100644
--- a/ethers-contract/tests/it/main.rs
+++ b/ethers-contract/tests/it/main.rs
@@ -7,6 +7,8 @@ mod derive;
 
 mod contract_call;
 
+mod eip712;
+
 #[cfg(all(not(target_arch = "wasm32"), not(feature = "celo")))]
 mod common;
 
diff --git a/ethers-contract/tests/solidity-contracts/DeriveEip712Test.json b/ethers-contract/tests/solidity-contracts/DeriveEip712Test.json
new file mode 100644
index 00000000..c9865358
--- /dev/null
+++ b/ethers-contract/tests/solidity-contracts/DeriveEip712Test.json
@@ -0,0 +1,1 @@
+{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"foo","type":"int256"},{"internalType":"uint256","name":"bar","type":"uint256"},{"internalType":"bytes","name":"fizz","type":"bytes"},{"internalType":"bytes32","name":"buzz","type":"bytes32"},{"internalType":"string","name":"far","type":"string"},{"internalType":"address","name":"out","type":"address"}],"internalType":"struct DeriveEip712Test.FooBar","name":"fooBar","type":"tuple"}],"name":"encodeEip712","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"foo","type":"int256"},{"internalType":"uint256","name":"bar","type":"uint256"},{"internalType":"bytes","name":"fizz","type":"bytes"},{"internalType":"bytes32","name":"buzz","type":"bytes32"},{"internalType":"string","name":"far","type":"string"},{"internalType":"address","name":"out","type":"address"}],"internalType":"struct DeriveEip712Test.FooBar","name":"fooBar","type":"tuple"}],"name":"structHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"typeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"components":[{"internalType":"int256","name":"foo","type":"int256"},{"internalType":"uint256","name":"bar","type":"uint256"},{"internalType":"bytes","name":"fizz","type":"bytes"},{"internalType":"bytes32","name":"buzz","type":"bytes32"},{"internalType":"string","name":"far","type":"string"},{"internalType":"address","name":"out","type":"address"}],"internalType":"struct DeriveEip712Test.FooBar","name":"fooBar","type":"tuple"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"name":"verifyFooBar","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b50610588806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630e81d1ea1461005c5780631a82ff96146100825780634992602814610095578063d8ef409b146100bb578063f698da25146100de575b600080fd5b61006f61006a366004610499565b6100e6565b6040519081526020015b60405180910390f35b61006f610090366004610499565b610135565b7f444a4f3bd4b9709dad515de69ec13a80dfaf37cdaff8705e0b7ad3b050f8a05d61006f565b6100ce6100c93660046104d6565b6101c2565b6040519015158152602001610079565b61006f610246565b60006100f0610246565b6100f983610135565b60405161190160f01b6020820152602281019290925260428201526062015b604051602081830303815290604052805190602001209050919050565b60007f444a4f3bd4b9709dad515de69ec13a80dfaf37cdaff8705e0b7ad3b050f8a05d82516020808501516040808701518051908401206060808901516080808b015180519088012060a0808d01518751998a019b909b52958801989098529186019490945284015282015260c08101919091526001600160a01b0390911660e082015261010001610118565b600060016101cf866100e6565b6040805160008152602081018083529290925260ff851690820152606081018690526080810185905260a0016020604051602081039080840390855afa15801561021d573d6000803e3d6000fd5b505050602060405103516001600160a01b0316866001600160a01b031614905095945050505050565b604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647260208201527f980de4e67a47e184738cefeb37eafc9ae849b00443ea6d49487ca4488633f4fd918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260016080820181905260a08201527f6f6f42aa4c3c5871ad1af387553372290fd350e98f6d38559f840f21b79da02e60c082015260009060e00160405160208183030381529060405280519060200120905090565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561034c5761034c610313565b60405290565b600082601f83011261036357600080fd5b813567ffffffffffffffff8082111561037e5761037e610313565b604051601f8301601f19908116603f011681019082821181831017156103a6576103a6610313565b816040528381528660208588010111156103bf57600080fd5b836020870160208301376000602085830101528094505050505092915050565b80356001600160a01b03811681146103f657600080fd5b919050565b600060c0828403121561040d57600080fd5b610415610329565b90508135815260208201356020820152604082013567ffffffffffffffff8082111561044057600080fd5b61044c85838601610352565b604084015260608401356060840152608084013591508082111561046f57600080fd5b5061047c84828501610352565b60808301525061048e60a083016103df565b60a082015292915050565b6000602082840312156104ab57600080fd5b813567ffffffffffffffff8111156104c257600080fd5b6104ce848285016103fb565b949350505050565b600080600080600060a086880312156104ee57600080fd5b6104f7866103df565b9450602086013567ffffffffffffffff81111561051357600080fd5b61051f888289016103fb565b9450506040860135925060608601359150608086013560ff8116811461054457600080fd5b80915050929550929590935056fea2646970667358221220cf29bf472d8a14fac807f7e952af4f1e27c3ec66e38093f54930dfc99f473b3264736f6c63430008130033","sourceMap":"101:2177:0:-:0;;;737:23;;;;;;;;;;101:2177;;;;;;","linkReferences":{}}}
diff --git a/ethers/tests/DeriveEip712Test.sol b/ethers-contract/tests/solidity-contracts/DeriveEip712Test.sol
similarity index 97%
rename from ethers/tests/DeriveEip712Test.sol
rename to ethers-contract/tests/solidity-contracts/DeriveEip712Test.sol
index 0aced88b..311c8e38 100644
--- a/ethers/tests/DeriveEip712Test.sol
+++ b/ethers-contract/tests/solidity-contracts/DeriveEip712Test.sol
@@ -2,6 +2,7 @@
 pragma solidity >=0.6.0;
 pragma experimental ABIEncoderV2;
 
+// note that this file is not synced with DeriveEip712Test.json
 contract DeriveEip712Test {
     uint256 constant chainId = 1;
     bytes32 constant salt = keccak256("eip712-test-75F0CCte");
diff --git a/ethers-contract/tests/solidity-contracts/derive_eip712_abi.json b/ethers-contract/tests/solidity-contracts/derive_eip712_abi.json
deleted file mode 100644
index a978024e..00000000
--- a/ethers-contract/tests/solidity-contracts/derive_eip712_abi.json
+++ /dev/null
@@ -1,206 +0,0 @@
-[
-	{
-		"inputs": [],
-		"stateMutability": "nonpayable",
-		"type": "constructor"
-	},
-	{
-		"inputs": [],
-		"name": "domainSeparator",
-		"outputs": [
-			{
-				"internalType": "bytes32",
-				"name": "",
-				"type": "bytes32"
-			}
-		],
-		"stateMutability": "pure",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"components": [
-					{
-						"internalType": "int256",
-						"name": "foo",
-						"type": "int256"
-					},
-					{
-						"internalType": "uint256",
-						"name": "bar",
-						"type": "uint256"
-					},
-					{
-						"internalType": "bytes",
-						"name": "fizz",
-						"type": "bytes"
-					},
-					{
-						"internalType": "bytes32",
-						"name": "buzz",
-						"type": "bytes32"
-					},
-					{
-						"internalType": "string",
-						"name": "far",
-						"type": "string"
-					},
-					{
-						"internalType": "address",
-						"name": "out",
-						"type": "address"
-					}
-				],
-				"internalType": "struct DeriveEip712Test.FooBar",
-				"name": "fooBar",
-				"type": "tuple"
-			}
-		],
-		"name": "encodeEip712",
-		"outputs": [
-			{
-				"internalType": "bytes32",
-				"name": "",
-				"type": "bytes32"
-			}
-		],
-		"stateMutability": "pure",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"components": [
-					{
-						"internalType": "int256",
-						"name": "foo",
-						"type": "int256"
-					},
-					{
-						"internalType": "uint256",
-						"name": "bar",
-						"type": "uint256"
-					},
-					{
-						"internalType": "bytes",
-						"name": "fizz",
-						"type": "bytes"
-					},
-					{
-						"internalType": "bytes32",
-						"name": "buzz",
-						"type": "bytes32"
-					},
-					{
-						"internalType": "string",
-						"name": "far",
-						"type": "string"
-					},
-					{
-						"internalType": "address",
-						"name": "out",
-						"type": "address"
-					}
-				],
-				"internalType": "struct DeriveEip712Test.FooBar",
-				"name": "fooBar",
-				"type": "tuple"
-			}
-		],
-		"name": "structHash",
-		"outputs": [
-			{
-				"internalType": "bytes32",
-				"name": "",
-				"type": "bytes32"
-			}
-		],
-		"stateMutability": "pure",
-		"type": "function"
-	},
-	{
-		"inputs": [],
-		"name": "typeHash",
-		"outputs": [
-			{
-				"internalType": "bytes32",
-				"name": "",
-				"type": "bytes32"
-			}
-		],
-		"stateMutability": "pure",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "signer",
-				"type": "address"
-			},
-			{
-				"components": [
-					{
-						"internalType": "int256",
-						"name": "foo",
-						"type": "int256"
-					},
-					{
-						"internalType": "uint256",
-						"name": "bar",
-						"type": "uint256"
-					},
-					{
-						"internalType": "bytes",
-						"name": "fizz",
-						"type": "bytes"
-					},
-					{
-						"internalType": "bytes32",
-						"name": "buzz",
-						"type": "bytes32"
-					},
-					{
-						"internalType": "string",
-						"name": "far",
-						"type": "string"
-					},
-					{
-						"internalType": "address",
-						"name": "out",
-						"type": "address"
-					}
-				],
-				"internalType": "struct DeriveEip712Test.FooBar",
-				"name": "fooBar",
-				"type": "tuple"
-			},
-			{
-				"internalType": "bytes32",
-				"name": "r",
-				"type": "bytes32"
-			},
-			{
-				"internalType": "bytes32",
-				"name": "s",
-				"type": "bytes32"
-			},
-			{
-				"internalType": "uint8",
-				"name": "v",
-				"type": "uint8"
-			}
-		],
-		"name": "verifyFooBar",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "pure",
-		"type": "function"
-	}
-]
\ No newline at end of file
diff --git a/ethers/tests/eip712.rs b/ethers/tests/eip712.rs
deleted file mode 100644
index 869bb635..00000000
--- a/ethers/tests/eip712.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-use ethers::{
-    contract::{abigen, ContractFactory, Eip712, EthAbiType},
-    core::{
-        types::{transaction::eip712::Eip712, Address, Bytes, I256, U256},
-        utils::{keccak256, Anvil},
-    },
-    providers::Provider,
-    signers::LocalWallet,
-    solc::Solc,
-};
-use std::{path::PathBuf, sync::Arc};
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_derive_eip712() {
-    // Generate Contract ABI Bindings
-    abigen!(
-        DeriveEip712Test,
-        "./ethers-contract/tests/solidity-contracts/derive_eip712_abi.json",
-        event_derives(serde::Deserialize, serde::Serialize)
-    );
-
-    // Create derived structs
-
-    #[derive(Debug, Clone, Eip712, EthAbiType)]
-    #[eip712(
-        name = "Eip712Test",
-        version = "1",
-        chain_id = 1,
-        verifying_contract = "0x0000000000000000000000000000000000000001",
-        salt = "eip712-test-75F0CCte"
-    )]
-    struct FooBar {
-        foo: I256,
-        bar: U256,
-        fizz: Bytes,
-        buzz: [u8; 32],
-        far: String,
-        out: Address,
-    }
-
-    // get ABI and bytecode for the DeriveEip712Test contract
-    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests");
-    Solc::find_or_install_svm_version("0.6.0").unwrap(); // install solc
-    let result = Solc::default().compile_source(path).unwrap();
-    let (abi, bytecode, _) = result
-        .find("DeriveEip712Test")
-        .expect("failed to get DeriveEip712Test contract")
-        .into_parts_or_default();
-
-    // launch the network & connect to it
-    let anvil = Anvil::new().spawn();
-    let from = anvil.addresses()[0];
-    let provider = Provider::try_from(anvil.endpoint())
-        .unwrap()
-        .with_sender(from)
-        .interval(std::time::Duration::from_millis(10));
-    let client = Arc::new(provider);
-
-    let factory = ContractFactory::new(abi.clone(), bytecode.clone(), client.clone());
-
-    let contract = factory
-        .deploy(())
-        .expect("failed to deploy DeriveEip712Test contract")
-        .legacy()
-        .send()
-        .await
-        .expect("failed to instantiate factory for DeriveEip712 contract");
-
-    let addr = contract.address();
-
-    let contract = DeriveEip712Test::new(addr, client.clone());
-
-    let foo_bar = FooBar {
-        foo: I256::from(10u64),
-        bar: U256::from(20u64),
-        fizz: b"fizz".into(),
-        buzz: keccak256("buzz"),
-        far: String::from("space"),
-        out: Address::from([0; 20]),
-    };
-
-    let derived_foo_bar = derive_eip_712_test::FooBar {
-        foo: foo_bar.foo,
-        bar: foo_bar.bar,
-        fizz: foo_bar.fizz.clone(),
-        buzz: foo_bar.buzz,
-        far: foo_bar.far.clone(),
-        out: foo_bar.out,
-    };
-
-    use ethers::signers::Signer;
-
-    let wallet: LocalWallet = anvil.keys()[0].clone().into();
-    let sig = wallet.sign_typed_data(&foo_bar).await.expect("failed to sign typed data");
-
-    let r = <[u8; 32]>::try_from(sig.r)
-        .expect("failed to parse 'r' value from signature into [u8; 32]");
-    let s = <[u8; 32]>::try_from(sig.s)
-        .expect("failed to parse 's' value from signature into [u8; 32]");
-    let v = u8::try_from(sig.v).expect("failed to parse 'v' value from signature into u8");
-
-    let domain_separator = contract
-        .domain_separator()
-        .call()
-        .await
-        .expect("failed to retrieve domain_separator from contract");
-    let type_hash =
-        contract.type_hash().call().await.expect("failed to retrieve type_hash from contract");
-    let struct_hash = contract
-        .struct_hash(derived_foo_bar.clone())
-        .call()
-        .await
-        .expect("failed to retrieve struct_hash from contract");
-    let encoded = contract
-        .encode_eip_712(derived_foo_bar.clone())
-        .call()
-        .await
-        .expect("failed to retrieve eip712 encoded hash from contract");
-    let verify = contract
-        .verify_foo_bar(wallet.address(), derived_foo_bar, r, s, v)
-        .call()
-        .await
-        .expect("failed to verify signed typed data eip712 payload");
-
-    assert_eq!(
-        domain_separator,
-        foo_bar
-            .domain()
-            .expect("failed to return domain_separator from Eip712 implemented struct")
-            .separator(),
-        "domain separator does not match contract domain separator!"
-    );
-
-    assert_eq!(
-        type_hash,
-        FooBar::type_hash().expect("failed to return type_hash from Eip712 implemented struct"),
-        "type hash does not match contract struct type hash!"
-    );
-
-    assert_eq!(
-        struct_hash,
-        foo_bar
-            .clone()
-            .struct_hash()
-            .expect("failed to return struct_hash from Eip712 implemented struct"),
-        "struct hash does not match contract struct hash!"
-    );
-
-    assert_eq!(
-        encoded,
-        foo_bar
-            .encode_eip712()
-            .expect("failed to return domain_separator from Eip712 implemented struct"),
-        "Encoded value does not match!"
-    );
-
-    assert!(verify, "typed data signature failed!");
-}
diff --git a/ethers/tests/main.rs b/ethers/tests/main.rs
deleted file mode 100644
index d4845162..00000000
--- a/ethers/tests/main.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//! Ethers integration tests.
-#![cfg(not(target_arch = "wasm32"))]
-
-mod eip712;