Repository: gakonst/ethers-rs (rust)

Issue:
sha2-asm build failure on wasm target
**Version**
`master`

**Platform**
Darwin

**Description**

sha2-asm build fails on wasm target. It should not be active at all. It appears to be pulled in by k256 and coins-bip32 via the sha2 package

```
> $ cargo tree -i -p sha2-asm --target wasm32-unknown-unknown
sha2-asm v0.6.2
└── sha2 v0.9.8
    └── k256 v0.9.6
        └── ethers-core v0.6.0 (/Users/james/devel/ethers-rs/ethers-core)
            ├── ethers-contract-abigen v0.6.0 (/Users/james/devel/ethers-rs/ethers-contract/ethers-contract-abigen)
            │   └── ethers-contract-derive v0.6.0 (proc-macro) (/Users/james/devel/ethers-rs/ethers-contract/ethers-contract-derive)
            │       └── ethers-contract v0.6.0 (/Users/james/devel/ethers-rs/ethers-contract)
            │           ├── ethers v0.6.0 (/Users/james/devel/ethers-rs)
            │           │   └── ethers-middleware-experimental v0.1.0 (/Users/james/devel/ethers-middleware-experimental)
            │           └── ethers-middleware v0.6.0 (/Users/james/devel/ethers-rs/ethers-middleware)
            │               └── ethers v0.6.0 (/Users/james/devel/ethers-rs) (*)
            └── ethers-contract-derive v0.6.0 (proc-macro) (/Users/james/devel/ethers-rs/ethers-contract/ethers-contract-derive) (*)

sha2-asm v0.6.2
└── sha2 v0.9.8
    ├── coins-bip32 v0.3.0
    │   ├── coins-bip39 v0.3.0
    │   │   └── ethers-signers v0.6.0 (/Users/james/devel/ethers-rs/ethers-signers)
    │   │       ├── ethers v0.6.0 (/Users/james/devel/ethers-rs) (*)
    │   │       └── ethers-middleware v0.6.0 (/Users/james/devel/ethers-rs/ethers-middleware) (*)
    │   └── ethers-signers v0.6.0 (/Users/james/devel/ethers-rs/ethers-signers) (*)
    ├── coins-bip39 v0.3.0 (*)
    ├── coins-core v0.2.2
    │   └── coins-bip32 v0.3.0 (*)
    ├── ethers-signers v0.6.0 (/Users/james/devel/ethers-rs/ethers-signers) (*)
    ├── ethers-solc v0.1.0 (/Users/james/devel/ethers-rs/ethers-solc)
    │   └── ethers v0.6.0 (/Users/james/devel/ethers-rs) (*)
    ├── k256 v0.9.6
    │   ├── coins-bip32 v0.3.0 (*)
    │   └── ethers-core v0.6.0 (/Users/james/devel/ethers-rs/ethers-core)
    │       ├── ethers v0.6.0 (/Users/james/devel/ethers-rs) (*)
    │       ├── ethers-contract v0.6.0 (/Users/james/devel/ethers-rs/ethers-contract) (*)
    │       ├── ethers-contract-abigen v0.6.0 (/Users/james/devel/ethers-rs/ethers-contract/ethers-contract-abigen)
    │       │   └── ethers-contract v0.6.0 (/Users/james/devel/ethers-rs/ethers-contract) (*)
    │       ├── ethers-etherscan v0.2.0 (/Users/james/devel/ethers-rs/ethers-etherscan)
    │       │   ├── ethers v0.6.0 (/Users/james/devel/ethers-rs) (*)
    │       │   └── ethers-middleware v0.6.0 (/Users/james/devel/ethers-rs/ethers-middleware) (*)
    │       ├── ethers-middleware v0.6.0 (/Users/james/devel/ethers-rs/ethers-middleware) (*)
    │       ├── ethers-providers v0.6.0 (/Users/james/devel/ethers-rs/ethers-providers)
    │       │   ├── ethers v0.6.0 (/Users/james/devel/ethers-rs) (*)
    │       │   ├── ethers-contract v0.6.0 (/Users/james/devel/ethers-rs/ethers-contract) (*)
    │       │   └── ethers-middleware v0.6.0 (/Users/james/devel/ethers-rs/ethers-middleware) (*)
    │       ├── ethers-signers v0.6.0 (/Users/james/devel/ethers-rs/ethers-signers) (*)
    │       └── ethers-solc v0.1.0 (/Users/james/devel/ethers-rs/ethers-solc) (*)
    └── pbkdf2 v0.8.0
        └── coins-bip39 v0.3.0 (*)```

Pull request:
fix: make ethers-wasm workspace member
<!--
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
Fix #637

this appears to be a cargo issue that only occurs because the ethers-wasm package was excluded, replicating ethers-wasm outside of the workspace compiled fine, so somehow cargo gets mixed up when pulling in the sha2 crate...
  
<!--
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
make ethers-wasm a workspace member instead
<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

## PR Checklist

- [ ] Added Tests
- [ ] Added Documentation
- [ ] Updated the changelog


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3e0c2324..d8f551e7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -129,7 +129,7 @@ jobs:
       - name: cargo fmt
         run: cargo +nightly fmt --all -- --check
       - name: cargo clippy
-        run: cargo +nightly clippy --all --all-features -- -D warnings
+        run: cargo +nightly clippy --all-features -- -D warnings
 
   wasm:
     name: WASM
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3bb4800..c9884ccb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -61,6 +61,8 @@
 - Fix `http Provider` data race when generating new request `id`s.
 - Add support for `net_version` RPC method.
   [595](https://github.com/gakonst/ethers-rs/pull/595)
+- Add support for `evm_snapshot` and `evm_revert` dev RPC methods.
+  [640](https://github.com/gakonst/ethers-rs/pull/640)
 
 ### Unreleased
 
diff --git a/Cargo.lock b/Cargo.lock
index 344c9fd1..55c0a183 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -78,9 +78,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.48"
+version = "1.0.51"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62e1f47f7dc0422027a4e370dd4548d4d66b26782e513e98dca1e689e058a80e"
+checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
 
 [[package]]
 name = "arrayref"
@@ -196,9 +196,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
 
 [[package]]
 name = "base64ct"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "392c772b012d685a640cdad68a5a21f4a45e696f85a2c2c907aab2fe49a91e19"
+checksum = "43a46022bae2c3bc5a17c2d45d59c1233ce0e2cca9ae9b92e92e9ce529874177"
 
 [[package]]
 name = "bech32"
@@ -437,9 +437,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "2.33.3"
+version = "2.34.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
 dependencies = [
  "bitflags",
  "textwrap",
@@ -575,6 +575,16 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if 1.0.0",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "const-oid"
 version = "0.6.2"
@@ -583,9 +593,9 @@ checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
 
 [[package]]
 name = "const-oid"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d355758f44afa81c21e66e1301d47cbffbbcde4b405cbe46b8b19f213abf9f60"
+checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
 
 [[package]]
 name = "constant_time_eq"
@@ -626,9 +636,9 @@ dependencies = [
 
 [[package]]
 name = "crc32fast"
-version = "1.2.2"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3825b1e8580894917dc4468cb634a1b4e9745fddc854edad72d9c04644c0319f"
+checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836"
 dependencies = [
  "cfg-if 1.0.0",
 ]
@@ -726,9 +736,9 @@ dependencies = [
 
 [[package]]
 name = "der"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
+checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4"
 dependencies = [
  "const-oid 0.6.2",
 ]
@@ -739,7 +749,7 @@ version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c"
 dependencies = [
- "const-oid 0.7.0",
+ "const-oid 0.7.1",
 ]
 
 [[package]]
@@ -799,7 +809,7 @@ version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
 dependencies = [
- "der 0.4.4",
+ "der 0.4.5",
  "elliptic-curve 0.10.6",
  "hmac",
  "signature",
@@ -1179,6 +1189,7 @@ dependencies = [
  "colored",
  "ethers-core",
  "futures-util",
+ "getrandom 0.2.3",
  "glob",
  "hex",
  "home",
@@ -1197,6 +1208,23 @@ dependencies = [
  "walkdir",
 ]
 
+[[package]]
+name = "ethers-wasm"
+version = "0.1.0"
+dependencies = [
+ "console_error_panic_hook",
+ "ethers",
+ "hex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-bindgen-test",
+ "web-sys",
+ "wee_alloc",
+]
+
 [[package]]
 name = "fake-simd"
 version = "0.1.2"
@@ -1801,6 +1829,12 @@ version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 
+[[package]]
+name = "memory_units"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
+
 [[package]]
 name = "mime"
 version = "0.3.16"
@@ -2124,7 +2158,7 @@ version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447"
 dependencies = [
- "der 0.4.4",
+ "der 0.4.5",
  "spki",
 ]
 
@@ -2629,9 +2663,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.5"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
 
 [[package]]
 name = "salsa20"
@@ -2661,6 +2695,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "scoped-tls"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
+
 [[package]]
 name = "scopeguard"
 version = "1.1.0"
@@ -2771,9 +2811,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.71"
+version = "1.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
+checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
 dependencies = [
  "itoa",
  "ryu",
@@ -2955,7 +2995,7 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
 dependencies = [
- "der 0.4.4",
+ "der 0.4.5",
 ]
 
 [[package]]
@@ -3507,6 +3547,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
 dependencies = [
  "cfg-if 1.0.0",
+ "serde",
+ "serde_json",
  "wasm-bindgen-macro",
 ]
 
@@ -3566,6 +3608,30 @@ version = "0.2.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
 
+[[package]]
+name = "wasm-bindgen-test"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96f1aa7971fdf61ef0f353602102dbea75a56e225ed036c1e3740564b91e6b7e"
+dependencies = [
+ "console_error_panic_hook",
+ "js-sys",
+ "scoped-tls",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-bindgen-test-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-test-macro"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6006f79628dfeb96a86d4db51fbf1344cd7fd8408f06fc9aa3c84913a4789688"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
 [[package]]
 name = "wasm-timer"
 version = "0.2.5"
@@ -3620,6 +3686,18 @@ dependencies = [
  "webpki 0.21.4",
 ]
 
+[[package]]
+name = "wee_alloc"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "memory_units",
+ "winapi",
+]
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
diff --git a/Cargo.toml b/Cargo.toml
index 7877c4cf..12434931 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,7 +20,8 @@ members = [
     "ethers-core",
     "ethers-middleware",
     "ethers-etherscan",
-    "ethers-solc"
+    "ethers-solc",
+    "examples/ethers-wasm",
 ]
 
 default-members = [
@@ -30,11 +31,7 @@ default-members = [
     "ethers-core",
     "ethers-middleware",
     "ethers-etherscan",
-    "ethers-solc"
-]
-
-exclude = [
-    "examples/ethers-wasm",
+    "ethers-solc",
 ]
 
 [package.metadata.docs.rs]
@@ -67,6 +64,7 @@ ws = ["ethers-providers/ws"]
 ipc = ["ethers-providers/ipc"]
 rustls = ["ethers-providers/rustls"]
 openssl = ["ethers-providers/openssl"]
+dev-rpc = ["ethers-providers/dev-rpc"]
 ## signers
 ledger = ["ethers-signers/ledger"]
 yubi = ["ethers-signers/yubi"]
@@ -101,3 +99,9 @@ serde_json = "1.0.64"
 tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }
 hex = "0.4.3"
 bytes = "1.1.0"
+
+
+# profile for the wasm example
+[profile.release.package.ethers-wasm]
+# Tell `rustc` to optimize for small code size.
+opt-level = "s"
\ No newline at end of file
diff --git a/ethers-providers/Cargo.toml b/ethers-providers/Cargo.toml
index d5b0618b..c2d7e164 100644
--- a/ethers-providers/Cargo.toml
+++ b/ethers-providers/Cargo.toml
@@ -65,3 +65,4 @@ ipc = ["tokio", "tokio/io-util", "tokio-util", "bytes"]
 
 openssl = ["tokio-tungstenite/native-tls", "reqwest/native-tls"]
 rustls = ["tokio-tungstenite/rustls-tls", "reqwest/rustls-tls"]
+dev-rpc = []
diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs
index 99dd869d..ba538a8a 100644
--- a/ethers-providers/src/lib.rs
+++ b/ethers-providers/src/lib.rs
@@ -32,6 +32,10 @@ use std::{error::Error, fmt::Debug, future::Future, pin::Pin, str::FromStr};
 
 pub use provider::{FilterKind, Provider, ProviderError};
 
+// feature-enabled support for dev-rpc methods
+#[cfg(feature = "dev-rpc")]
+pub use provider::dev_rpc::DevRpcMiddleware;
+
 /// A simple gas escalation policy
 pub type EscalationPolicy = Box<dyn Fn(U256, usize) -> U256 + Send + Sync>;
 
diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs
index b4b8a12b..01c9b678 100644
--- a/ethers-providers/src/provider.rs
+++ b/ethers-providers/src/provider.rs
@@ -1021,6 +1021,183 @@ impl TryFrom<String> for Provider<HttpProvider> {
     }
 }
 
+/// A middleware supporting development-specific JSON RPC methods
+///
+/// # Example
+///
+///```
+/// use ethers_providers::{Provider, Http, Middleware, DevRpcMiddleware};
+/// use ethers_core::types::TransactionRequest;
+/// use ethers_core::utils::Ganache;
+/// use std::convert::TryFrom;
+///
+/// # #[tokio::main]
+/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// let ganache = Ganache::new().spawn();
+/// let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap();
+/// let client = DevRpcMiddleware::new(provider);
+///
+/// // snapshot the initial state
+/// let block0 = client.get_block_number().await.unwrap();
+/// let snap_id = client.snapshot().await.unwrap();
+///
+/// // send a transaction
+/// let accounts = client.get_accounts().await?;
+/// let from = accounts[0];
+/// let to = accounts[1];
+/// let balance_before = client.get_balance(to, None).await?;
+/// let tx = TransactionRequest::new().to(to).value(1000).from(from);
+/// client.send_transaction(tx, None).await?.await?;
+/// let balance_after = client.get_balance(to, None).await?;
+/// assert_eq!(balance_after, balance_before + 1000);
+///
+/// // revert to snapshot
+/// client.revert_to_snapshot(snap_id).await.unwrap();
+/// let balance_after_revert = client.get_balance(to, None).await?;
+/// assert_eq!(balance_after_revert, balance_before);
+/// # Ok(())
+/// # }
+/// ```
+#[cfg(feature = "dev-rpc")]
+pub mod dev_rpc {
+    use crate::{FromErr, Middleware, ProviderError};
+    use async_trait::async_trait;
+    use ethers_core::types::U256;
+    use thiserror::Error;
+
+    use std::fmt::Debug;
+
+    #[derive(Clone, Debug)]
+    pub struct DevRpcMiddleware<M>(M);
+
+    #[derive(Error, Debug)]
+    pub enum DevRpcMiddlewareError<M: Middleware> {
+        #[error("{0}")]
+        MiddlewareError(M::Error),
+
+        #[error("{0}")]
+        ProviderError(ProviderError),
+
+        #[error("Could not revert to snapshot")]
+        NoSnapshot,
+    }
+
+    #[async_trait]
+    impl<M: Middleware> Middleware for DevRpcMiddleware<M> {
+        type Error = DevRpcMiddlewareError<M>;
+        type Provider = M::Provider;
+        type Inner = M;
+
+        fn inner(&self) -> &M {
+            &self.0
+        }
+    }
+
+    impl<M: Middleware> FromErr<M::Error> for DevRpcMiddlewareError<M> {
+        fn from(src: M::Error) -> DevRpcMiddlewareError<M> {
+            DevRpcMiddlewareError::MiddlewareError(src)
+        }
+    }
+
+    impl<M> From<ProviderError> for DevRpcMiddlewareError<M>
+    where
+        M: Middleware,
+    {
+        fn from(src: ProviderError) -> Self {
+            Self::ProviderError(src)
+        }
+    }
+
+    impl<M: Middleware> DevRpcMiddleware<M> {
+        pub fn new(inner: M) -> Self {
+            Self(inner)
+        }
+
+        // both ganache and hardhat increment snapshot id even if no state has changed
+        pub async fn snapshot(&self) -> Result<U256, DevRpcMiddlewareError<M>> {
+            self.provider().request::<(), U256>("evm_snapshot", ()).await.map_err(From::from)
+        }
+
+        pub async fn revert_to_snapshot(&self, id: U256) -> Result<(), DevRpcMiddlewareError<M>> {
+            let ok = self
+                .provider()
+                .request::<[U256; 1], bool>("evm_revert", [id])
+                .await
+                .map_err(DevRpcMiddlewareError::ProviderError)?;
+            if ok {
+                Ok(())
+            } else {
+                Err(DevRpcMiddlewareError::NoSnapshot)
+            }
+        }
+    }
+    #[cfg(test)]
+    // Celo blocks can not get parsed when used with Ganache
+    #[cfg(not(feature = "celo"))]
+    mod tests {
+        use super::*;
+        use crate::{Http, Provider};
+        use ethers_core::utils::Ganache;
+        use std::convert::TryFrom;
+
+        #[tokio::test]
+        async fn test_snapshot() {
+            // launch ganache
+            let ganache = Ganache::new().spawn();
+            let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap();
+            let client = DevRpcMiddleware::new(provider);
+
+            // snapshot initial state
+            let block0 = client.get_block_number().await.unwrap();
+            let time0 = client.get_block(block0).await.unwrap().unwrap().timestamp;
+            let snap_id0 = client.snapshot().await.unwrap();
+
+            // mine a new block
+            client.provider().mine(1).await.unwrap();
+
+            // snapshot state
+            let block1 = client.get_block_number().await.unwrap();
+            let time1 = client.get_block(block1).await.unwrap().unwrap().timestamp;
+            let snap_id1 = client.snapshot().await.unwrap();
+
+            // mine some blocks
+            client.provider().mine(5).await.unwrap();
+
+            // snapshot state
+            let block2 = client.get_block_number().await.unwrap();
+            let time2 = client.get_block(block2).await.unwrap().unwrap().timestamp;
+            let snap_id2 = client.snapshot().await.unwrap();
+
+            // mine some blocks
+            client.provider().mine(5).await.unwrap();
+
+            // revert_to_snapshot should reset state to snap id
+            client.revert_to_snapshot(snap_id2).await.unwrap();
+            let block = client.get_block_number().await.unwrap();
+            let time = client.get_block(block).await.unwrap().unwrap().timestamp;
+            assert_eq!(block, block2);
+            assert_eq!(time, time2);
+
+            client.revert_to_snapshot(snap_id1).await.unwrap();
+            let block = client.get_block_number().await.unwrap();
+            let time = client.get_block(block).await.unwrap().unwrap().timestamp;
+            assert_eq!(block, block1);
+            assert_eq!(time, time1);
+
+            // revert_to_snapshot should throw given non-existent or
+            // previously used snapshot
+            let result = client.revert_to_snapshot(snap_id1).await;
+            assert!(result.is_err());
+
+            client.revert_to_snapshot(snap_id0).await.unwrap();
+            let block = client.get_block_number().await.unwrap();
+            let time = client.get_block(block).await.unwrap().unwrap().timestamp;
+            assert_eq!(block, block0);
+            assert_eq!(time, time0);
+        }
+    }
+}
+
 #[cfg(test)]
 #[cfg(not(target_arch = "wasm32"))]
 mod tests {
diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml
index 743afd9a..296b002b 100644
--- a/ethers-solc/Cargo.toml
+++ b/ethers-solc/Cargo.toml
@@ -31,12 +31,16 @@ svm = { package = "svm-rs", version = "0.2.0", optional = true }
 glob = "0.3.0"
 tracing = "0.1.29"
 
-[target.'cfg(target_arch = "wasm32")'.dependencies]
-sha2 = { version = "0.9.8" }
+[target.'cfg(not(any(target_arch = "x86", target_arch = "x86_64")))'.dependencies]
+sha2 = { version = "0.9.8", default-features = false }
 
-[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
+[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
 home = "0.5.3"
-sha2 = { version = "0.9.8", features = ["asm"] }
+sha2 = { version = "0.9.8", default-features = false, features = ["asm"] }
+
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+# NOTE: this enables wasm compatibility for getrandom indirectly
+getrandom = { version = "0.2", features = ["js"] }
 
 [dev-dependencies]
 tokio = { version = "1.12.0", features = ["full"] }
diff --git a/examples/ethers-wasm/Cargo.toml b/examples/ethers-wasm/Cargo.toml
index 24b2164b..34e71d86 100644
--- a/examples/ethers-wasm/Cargo.toml
+++ b/examples/ethers-wasm/Cargo.toml
@@ -43,10 +43,4 @@ hex = "0.4.3"
 web-sys = "0.3.51"
 
 [dev-dependencies]
-wasm-bindgen-test = "0.3.24"
-
-# profile for the wasm example
-[profile.release.package.ethers-wasm]
-# Tell `rustc` to optimize for small code size.
-opt-level = "s"
-
+wasm-bindgen-test = "0.3.24"
\ No newline at end of file
diff --git a/examples/ethers-wasm/src/lib.rs b/examples/ethers-wasm/src/lib.rs
index 84be0071..e4816a55 100644
--- a/examples/ethers-wasm/src/lib.rs
+++ b/examples/ethers-wasm/src/lib.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::all)]
+
 use std::sync::Arc;
 
 use wasm_bindgen::prelude::*;
@@ -51,12 +53,7 @@ pub async fn deploy() {
     let factory = ContractFactory::new(SIMPLECONTRACT_ABI.clone(), bytecode.into(), client.clone());
 
     log!("Deploying contract...");
-    let contract = factory
-        .deploy("hello WASM!".to_string())
-        .unwrap()
-        .send()
-        .await
-        .unwrap();
+    let contract = factory.deploy("hello WASM!".to_string()).unwrap().send().await.unwrap();
     let addr = contract.address();
     log!("Deployed contract with address: {:?}", addr);
 
@@ -64,25 +61,11 @@ pub async fn deploy() {
 
     let value = "bye from WASM!";
     log!("Setting value... `{}`", value);
-    let receipt = contract
-        .set_value(value.to_owned())
-        .send()
-        .await
-        .unwrap()
-        .await
-        .unwrap();
-    console::log_2(
-        &"Set value receipt: ".into(),
-        &JsValue::from_serde(&receipt).unwrap(),
-    );
+    let receipt = contract.set_value(value.to_owned()).send().await.unwrap().await.unwrap();
+    console::log_2(&"Set value receipt: ".into(), &JsValue::from_serde(&receipt).unwrap());
 
     log!("Fetching logs...");
-    let logs = contract
-        .value_changed_filter()
-        .from_block(0u64)
-        .query()
-        .await
-        .unwrap();
+    let logs = contract.value_changed_filter().from_block(0u64).query().await.unwrap();
 
     let value = contract.get_value().call().await.unwrap();
 
diff --git a/examples/ethers-wasm/src/utils.rs b/examples/ethers-wasm/src/utils.rs
index 091ca848..70bdd53e 100644
--- a/examples/ethers-wasm/src/utils.rs
+++ b/examples/ethers-wasm/src/utils.rs
@@ -1,5 +1,7 @@
-use ethers::prelude::{LocalWallet, MnemonicBuilder};
-use ethers::signers::coins_bip39::English;
+use ethers::{
+    prelude::{LocalWallet, MnemonicBuilder},
+    signers::coins_bip39::English,
+};
 
 pub fn set_panic_hook() {
     // When the `console_error_panic_hook` feature is enabled, we can call the
@@ -17,12 +19,7 @@ pub const PHRASE: &str =
     "stuff inherit faith park genre spread huge knee ecology private marble supreme";
 
 pub fn key(index: u32) -> LocalWallet {
-    MnemonicBuilder::<English>::default()
-        .phrase(PHRASE)
-        .index(index)
-        .unwrap()
-        .build()
-        .unwrap()
+    MnemonicBuilder::<English>::default().phrase(PHRASE).index(index).unwrap().build().unwrap()
 }
 
 /// Bytecode of the `SimpleContract`


Test patch:
diff --git a/examples/ethers-wasm/tests/contract_with_abi.rs b/examples/ethers-wasm/tests/contract_with_abi.rs
index 8dc61db6..678f54b2 100644
--- a/examples/ethers-wasm/tests/contract_with_abi.rs
+++ b/examples/ethers-wasm/tests/contract_with_abi.rs
@@ -6,8 +6,7 @@ use ethers::prelude::{
     abigen, ContractFactory, Http, JsonRpcClient, LocalWallet, Provider, SignerMiddleware, Ws,
 };
 
-use std::convert::TryFrom;
-use std::sync::Arc;
+use std::{convert::TryFrom, sync::Arc};
 
 wasm_bindgen_test_configure!(run_in_browser);
 
@@ -38,12 +37,8 @@ async fn deploy<T: JsonRpcClient>(provider: Provider<T>, wallet: LocalWallet) {
 
     let bytecode = hex::decode(ethers_wasm::utils::SIMPLECONTRACT_BIN).unwrap();
     let factory = ContractFactory::new(SIMPLECONTRACT_ABI.clone(), bytecode.into(), client.clone());
-    let contract = factory
-        .deploy("Hello from Contract!".to_string())
-        .unwrap()
-        .send()
-        .await
-        .unwrap();
+    let contract =
+        factory.deploy("Hello from Contract!".to_string()).unwrap().send().await.unwrap();
     let addr = contract.address();
     console_log!("deployed to {}", addr);