diff --git a/ethers-etherscan/Cargo.toml b/ethers-etherscan/Cargo.toml index ed9dd2a9..dae64a8f 100644 --- a/ethers-etherscan/Cargo.toml +++ b/ethers-etherscan/Cargo.toml @@ -22,7 +22,7 @@ serde-aux = { version = "3.0.1", default-features = false } thiserror = "1.0.29" [dev-dependencies] -tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.5", features = ["macros", "rt-multi-thread", "time"] } serial_test = "0.5.1" [package.metadata.docs.rs] diff --git a/ethers-etherscan/src/contract.rs b/ethers-etherscan/src/contract.rs index d9e18bd3..1e3c7a4b 100644 --- a/ethers-etherscan/src/contract.rs +++ b/ethers-etherscan/src/contract.rs @@ -1,8 +1,11 @@ -use crate::{Client, Response, Result}; -use ethers_core::abi::{Abi, Address}; -use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use serde::{Deserialize, Serialize}; + +use ethers_core::abi::{Abi, Address}; + +use crate::{Client, Response, Result}; + /// Arguments for verifying contracts #[derive(Debug, Clone, Serialize)] pub struct VerifyContract { @@ -251,55 +254,66 @@ impl Client { #[cfg(test)] mod tests { - use crate::{contract::VerifyContract, Client}; - use ethers_core::types::Chain; + use std::time::Duration; use serial_test::serial; + use ethers_core::types::Chain; + + use crate::{contract::VerifyContract, tests::run_at_least_duration, Client}; + #[tokio::test] #[serial] #[ignore] async fn can_fetch_contract_abi() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let _abi = client - .contract_abi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap()) - .await - .unwrap(); + let _abi = client + .contract_abi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap()) + .await + .unwrap(); + }) + .await; } #[tokio::test] #[serial] #[ignore] async fn can_fetch_contract_source_code() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let _meta = client - .contract_source_code("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap()) - .await - .unwrap(); + let _meta = client + .contract_source_code("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap()) + .await + .unwrap(); + }) + .await } #[tokio::test] #[serial] #[ignore] async fn can_verify_contract() { - // TODO this needs further investigation + run_at_least_duration(Duration::from_millis(200), async { + // TODO this needs further investigation - // https://etherscan.io/address/0x9e744c9115b74834c0f33f4097f40c02a9ac5c33#code - let contract = include_str!("../resources/UniswapExchange.sol"); - let address = "0x9e744c9115b74834c0f33f4097f40c02a9ac5c33".parse().unwrap(); - let compiler_version = "v0.5.17+commit.d19bba13"; - let constructor_args = "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000007596179537761700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035941590000000000000000000000000000000000000000000000000000000000"; + // https://etherscan.io/address/0x9e744c9115b74834c0f33f4097f40c02a9ac5c33#code + let contract = include_str!("../resources/UniswapExchange.sol"); + let address = "0x9e744c9115b74834c0f33f4097f40c02a9ac5c33".parse().unwrap(); + let compiler_version = "v0.5.17+commit.d19bba13"; + let constructor_args = "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000007596179537761700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035941590000000000000000000000000000000000000000000000000000000000"; - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let contract = - VerifyContract::new(address, contract.to_string(), compiler_version.to_string()) - .constructor_arguments(Some(constructor_args)) - .optimization(true) - .runs(200); + let contract = + VerifyContract::new(address, contract.to_string(), compiler_version.to_string()) + .constructor_arguments(Some(constructor_args)) + .optimization(true) + .runs(200); - let _resp = client.submit_contract_verification(&contract).await; + let _resp = client.submit_contract_verification(&contract).await; + }).await } } diff --git a/ethers-etherscan/src/gas.rs b/ethers-etherscan/src/gas.rs index 4d3c66dd..7d4ce4d0 100644 --- a/ethers-etherscan/src/gas.rs +++ b/ethers-etherscan/src/gas.rs @@ -70,48 +70,61 @@ impl Client { #[cfg(test)] mod tests { + use std::time::Duration; + use serial_test::serial; use ethers_core::types::Chain; + use crate::tests::run_at_least_duration; + use super::*; #[tokio::test] #[serial] async fn gas_estimate_success() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let result = client.gas_estimate(2000000000u32.into()).await; + let result = client.gas_estimate(2000000000u32.into()).await; - assert!(result.is_ok()); + assert!(result.is_ok()); + }) + .await } #[tokio::test] #[serial] async fn gas_estimate_error() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let err = client.gas_estimate(7123189371829732819379218u128.into()).await.unwrap_err(); + let err = client.gas_estimate(7123189371829732819379218u128.into()).await.unwrap_err(); - assert!(matches!(err, EtherscanError::GasEstimationFailed)); + assert!(matches!(err, EtherscanError::GasEstimationFailed)); + }) + .await } #[tokio::test] #[serial] async fn gas_oracle_success() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let result = client.gas_oracle().await; + let result = client.gas_oracle().await; - assert!(result.is_ok()); + assert!(result.is_ok()); - let oracle = result.unwrap(); + let oracle = result.unwrap(); - assert!(oracle.safe_gas_price > 0); - assert!(oracle.propose_gas_price > 0); - assert!(oracle.fast_gas_price > 0); - assert!(oracle.last_block > 0); - assert!(oracle.suggested_base_fee > 0.0); - assert!(oracle.gas_used_ratio.len() > 0); + assert!(oracle.safe_gas_price > 0); + assert!(oracle.propose_gas_price > 0); + assert!(oracle.fast_gas_price > 0); + assert!(oracle.last_block > 0); + assert!(oracle.suggested_base_fee > 0.0); + assert!(oracle.gas_used_ratio.len() > 0); + }) + .await } } diff --git a/ethers-etherscan/src/lib.rs b/ethers-etherscan/src/lib.rs index 689e8358..5d6e0701 100644 --- a/ethers-etherscan/src/lib.rs +++ b/ethers-etherscan/src/lib.rs @@ -78,8 +78,7 @@ impl Client { Chain::Mainnet | Chain::Ropsten | Chain::Kovan | Chain::Rinkeby | Chain::Goerli => { std::env::var("ETHERSCAN_API_KEY")? } - Chain::XDai => String::default(), - chain => return Err(EtherscanError::ChainNotSupported(chain)), + _ => String::default(), }; Self::new(chain, api_key) } @@ -176,6 +175,11 @@ struct Query<'a, T: Serialize> { #[cfg(test)] mod tests { + use std::{ + future::Future, + time::{Duration, SystemTime}, + }; + use ethers_core::types::Chain; use crate::{Client, EtherscanError}; @@ -187,4 +191,12 @@ mod tests { assert!(matches!(err, EtherscanError::ChainNotSupported(_))); assert_eq!(err.to_string(), "chain XDai not supported"); } + + pub async fn run_at_least_duration(duration: Duration, block: impl Future) { + let start = SystemTime::now(); + block.await; + if let Some(sleep) = duration.checked_sub(start.elapsed().unwrap()) { + tokio::time::sleep(sleep).await; + } + } } diff --git a/ethers-etherscan/src/transaction.rs b/ethers-etherscan/src/transaction.rs index 69b1564b..92df9d10 100644 --- a/ethers-etherscan/src/transaction.rs +++ b/ethers-etherscan/src/transaction.rs @@ -52,68 +52,82 @@ impl Client { #[cfg(test)] mod tests { + use std::time::Duration; + use serial_test::serial; - use crate::Chain; + use crate::{tests::run_at_least_duration, Chain}; use super::*; #[tokio::test] #[serial] async fn check_contract_execution_status_success() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let status = client - .check_contract_execution_status( - "0x16197e2a0eacc44c1ebdfddcfcfcafb3538de557c759a66e0ba95263b23d9007", - ) - .await; + let status = client + .check_contract_execution_status( + "0x16197e2a0eacc44c1ebdfddcfcfcafb3538de557c759a66e0ba95263b23d9007", + ) + .await; - assert!(status.is_ok()); + assert!(status.is_ok()); + }) + .await } #[tokio::test] #[serial] async fn check_contract_execution_status_error() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let err = client - .check_contract_execution_status( - "0x15f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a", - ) - .await - .unwrap_err(); + let err = client + .check_contract_execution_status( + "0x15f8e5ea1079d9a0bb04a4c58ae5fe7654b5b2b4463375ff7ffb490aa0032f3a", + ) + .await + .unwrap_err(); - assert!(matches!(err, EtherscanError::ExecutionFailed(_))); - assert_eq!(err.to_string(), "contract execution call failed: Bad jump destination"); + assert!(matches!(err, EtherscanError::ExecutionFailed(_))); + assert_eq!(err.to_string(), "contract execution call failed: Bad jump destination"); + }) + .await } #[tokio::test] #[serial] async fn check_transaction_receipt_status_success() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let success = client - .check_transaction_receipt_status( - "0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76", - ) - .await; + let success = client + .check_transaction_receipt_status( + "0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76", + ) + .await; - assert!(success.is_ok()); + assert!(success.is_ok()); + }) + .await } #[tokio::test] #[serial] async fn check_transaction_receipt_status_failed() { - let client = Client::new_from_env(Chain::Mainnet).unwrap(); + run_at_least_duration(Duration::from_millis(200), async { + let client = Client::new_from_env(Chain::Mainnet).unwrap(); - let err = client - .check_transaction_receipt_status( - "0x21a29a497cb5d4bf514c0cca8d9235844bd0215c8fab8607217546a892fd0758", - ) - .await - .unwrap_err(); + let err = client + .check_transaction_receipt_status( + "0x21a29a497cb5d4bf514c0cca8d9235844bd0215c8fab8607217546a892fd0758", + ) + .await + .unwrap_err(); - assert!(matches!(err, EtherscanError::TransactionReceiptFailed)); + assert!(matches!(err, EtherscanError::TransactionReceiptFailed)); + }) + .await } }