Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove Ethers #14

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ keywords = ["crypto", "ethers", "ethereum", "web3", "etherscan"]
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
Expand All @@ -18,23 +16,20 @@ rustdoc-args = ["--cfg", "docsrs"]
all-features = true

[dependencies]
ethers-core = { version = "2", default-features = false }

foundry-compilers = { version = "0.1", optional = true }

alloy-chains = "0.1"
alloy-json-abi = { version = "0.4", default-features = false, features = ["std", "serde_json"] }
alloy-primitives = { version = "0.4", default-features = false, features = ["std", "serde"] }

reqwest = { version = "0.11.19", default-features = false, features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tracing = "0.1.37"
semver = "1.0"

alloy-primitives = { version = "0.4", default-features = false, features = ["std", "serde"]}
alloy-json-abi = { version = "0.4", default-features = false, features = ["std", "serde_json"] }

[dev-dependencies]
foundry-compilers = { version = "0.1" }

tempfile = "3.8"
tokio = { version = "1.32", features = ["macros", "rt-multi-thread", "time"] }
serial_test = "2.0.0"
Expand All @@ -48,6 +43,3 @@ openssl = ["reqwest/native-tls"]
foundry-compilers = ["dep:foundry-compilers"]
compilers-full = ["foundry-compilers?/full"]
compilers-tests = ["foundry-compilers?/tests"]

[patch.crates-io]
ethers-core = { git = "https://github.com/gakonst/ethers-rs", rev = "841ff8c47980798fbb47991e047f8481b1d5eb39" }
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ release.
## Examples

```rust,no_run
use ethers_core::types::Chain;
use alloy_chains::Chain;
use foundry_block_explorers::Client;

async fn foo() -> Result<(), Box<dyn std::error::Error>> {
Expand Down
2 changes: 1 addition & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alloy_chains::Chain;
use alloy_primitives::Address;
use ethers_core::types::Chain;
use std::env::VarError;

#[derive(Debug, thiserror::Error)]
Expand Down
80 changes: 43 additions & 37 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

use crate::errors::{is_blocked_by_cloudflare_response, is_cloudflare_security_challenge};
use alloy_chains::{Chain, ChainKind, NamedChain};
use alloy_json_abi::JsonAbi;
use alloy_primitives::{Address, B256};
use contract::ContractMetadata;
use errors::EtherscanError;
use ethers_core::types::Chain;
use reqwest::{header, IntoUrl, Url};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
Expand Down Expand Up @@ -65,9 +65,9 @@ impl Client {
/// # Example
///
/// ```rust
/// use ethers_core::types::Chain;
/// use alloy_chains::Chain;
/// use foundry_block_explorers::Client;
/// let client = Client::builder().with_api_key("<API KEY>").chain(Chain::Mainnet).unwrap().build().unwrap();
/// let client = Client::builder().with_api_key("<API KEY>").chain(NamedChain::mainnet()).unwrap().build().unwrap();
/// ```
pub fn builder() -> ClientBuilder {
ClientBuilder::default()
Expand All @@ -93,30 +93,35 @@ impl Client {
/// Create a new client with the correct endpoints based on the chain and API key
/// from the default environment variable defined in [`Chain`].
pub fn new_from_env(chain: Chain) -> Result<Self> {
let api_key = match chain {
// Extra aliases
Chain::Fantom | Chain::FantomTestnet => std::env::var("FMTSCAN_API_KEY")
.or_else(|_| std::env::var("FANTOMSCAN_API_KEY"))
.map_err(Into::into),

// Backwards compatibility, ideally these should return an error.
Chain::Gnosis |
Chain::Chiado |
Chain::Sepolia |
Chain::Rsk |
Chain::Sokol |
Chain::Poa |
Chain::Oasis |
Chain::Emerald |
Chain::EmeraldTestnet |
Chain::Evmos |
Chain::EvmosTestnet => Ok(String::new()),
Chain::AnvilHardhat | Chain::Dev => Err(EtherscanError::LocalNetworksNotSupported),

_ => chain
.etherscan_api_key_name()
.ok_or_else(|| EtherscanError::ChainNotSupported(chain))
.and_then(|key_name| std::env::var(key_name).map_err(Into::into)),
let api_key = match chain.kind() {
ChainKind::Named(named) => match named {
// Extra aliases
NamedChain::Fantom | NamedChain::FantomTestnet => std::env::var("FMTSCAN_API_KEY")
.or_else(|_| std::env::var("FANTOMSCAN_API_KEY"))
.map_err(Into::into),

// Backwards compatibility, ideally these should return an error.
NamedChain::Gnosis |
NamedChain::Chiado |
NamedChain::Sepolia |
NamedChain::Rsk |
NamedChain::Sokol |
NamedChain::Poa |
NamedChain::Oasis |
NamedChain::Emerald |
NamedChain::EmeraldTestnet |
NamedChain::Evmos |
NamedChain::EvmosTestnet => Ok(String::new()),
NamedChain::AnvilHardhat | NamedChain::Dev => {
Err(EtherscanError::LocalNetworksNotSupported)
}

_ => named
.etherscan_api_key_name()
.ok_or_else(|| EtherscanError::ChainNotSupported(chain))
.and_then(|key_name| std::env::var(key_name).map_err(Into::into)),
},
ChainKind::Id(_) => Err(EtherscanError::ChainNotSupported(chain)),
}?;
Self::new(chain, api_key)
}
Expand Down Expand Up @@ -280,14 +285,15 @@ impl ClientBuilder {
/// Fails if the chain is not supported by etherscan
pub fn chain(self, chain: Chain) -> Result<Self> {
fn urls(
api: impl IntoUrl,
url: impl IntoUrl,
(api, url): (impl IntoUrl, impl IntoUrl),
) -> (reqwest::Result<Url>, reqwest::Result<Url>) {
(api.into_url(), url.into_url())
}
let (etherscan_api_url, etherscan_url) = chain
.named()
.ok_or_else(|| EtherscanError::ChainNotSupported(chain))?
.etherscan_urls()
.map(|(api, base)| urls(api, base))
.map(urls)
.ok_or_else(|| EtherscanError::ChainNotSupported(chain))?;
self.with_api_url(etherscan_api_url?)?.with_url(etherscan_url?)
}
Expand Down Expand Up @@ -473,8 +479,8 @@ fn into_url(url: impl IntoUrl) -> std::result::Result<Url, reqwest::Error> {
#[cfg(test)]
mod tests {
use crate::{Client, EtherscanError, ResponseData};
use alloy_chains::Chain;
use alloy_primitives::{Address, B256};
use ethers_core::types::Chain;

// <https://github.com/foundry-rs/foundry/issues/4406>
#[test]
Expand All @@ -486,47 +492,47 @@ mod tests {

#[test]
fn test_api_paths() {
let client = Client::new(Chain::Goerli, "").unwrap();
let client = Client::new(Chain::goerli(), "").unwrap();
assert_eq!(client.etherscan_api_url.as_str(), "https://api-goerli.etherscan.io/api/");

assert_eq!(client.block_url(100), "https://goerli.etherscan.io/block/100");
}

#[test]
fn stringifies_block_url() {
let etherscan = Client::new(Chain::Mainnet, "").unwrap();
let etherscan = Client::new(Chain::mainnet(), "").unwrap();
let block: u64 = 1;
let block_url: String = etherscan.block_url(block);
assert_eq!(block_url, format!("https://etherscan.io/block/{block}"));
}

#[test]
fn stringifies_address_url() {
let etherscan = Client::new(Chain::Mainnet, "").unwrap();
let etherscan = Client::new(Chain::mainnet(), "").unwrap();
let addr: Address = Address::ZERO;
let address_url: String = etherscan.address_url(addr);
assert_eq!(address_url, format!("https://etherscan.io/address/{addr:?}"));
}

#[test]
fn stringifies_transaction_url() {
let etherscan = Client::new(Chain::Mainnet, "").unwrap();
let etherscan = Client::new(Chain::mainnet(), "").unwrap();
let tx_hash = B256::ZERO;
let tx_url: String = etherscan.transaction_url(tx_hash);
assert_eq!(tx_url, format!("https://etherscan.io/tx/{tx_hash:?}"));
}

#[test]
fn stringifies_token_url() {
let etherscan = Client::new(Chain::Mainnet, "").unwrap();
let etherscan = Client::new(Chain::mainnet(), "").unwrap();
let token_hash = Address::ZERO;
let token_url: String = etherscan.token_url(token_hash);
assert_eq!(token_url, format!("https://etherscan.io/token/{token_hash:?}"));
}

#[test]
fn local_networks_not_supported() {
let err = Client::new_from_env(Chain::Dev).unwrap_err();
let err = Client::new_from_env(Chain::dev()).unwrap_err();
assert!(matches!(err, EtherscanError::LocalNetworksNotSupported));
}
}
21 changes: 11 additions & 10 deletions tests/it/account.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::*;
use alloy_chains::NamedChain;
use alloy_primitives::{U256, U64};
use foundry_block_explorers::{
account::{InternalTxQueryOption, TokenQueryOption},
Expand All @@ -9,7 +10,7 @@ use serial_test::serial;
#[tokio::test]
#[serial]
async fn get_ether_balance_single_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let balance = client
.get_ether_balance_single(
&"0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse().unwrap(),
Expand All @@ -24,7 +25,7 @@ async fn get_ether_balance_single_success() {
#[tokio::test]
#[serial]
async fn get_ether_balance_multi_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let balances = client
.get_ether_balance_multi(
&["0x58eB28A67731c570Ef827C365c89B5751F9E6b0a".parse().unwrap()],
Expand All @@ -41,7 +42,7 @@ async fn get_ether_balance_multi_success() {
#[tokio::test]
#[serial]
async fn get_transactions_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let txs = client
.get_transactions(&"0x4F26FfBe5F04ED43630fdC30A87638d53D0b0876".parse().unwrap(), None)
.await;
Expand All @@ -53,7 +54,7 @@ async fn get_transactions_success() {
#[tokio::test]
#[serial]
async fn get_internal_transactions_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let txs = client
.get_internal_transactions(
InternalTxQueryOption::ByAddress(
Expand All @@ -70,7 +71,7 @@ async fn get_internal_transactions_success() {
#[tokio::test]
#[serial]
async fn get_internal_transactions_by_tx_hash_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let txs = client
.get_internal_transactions(
InternalTxQueryOption::ByTransactionHash(
Expand All @@ -89,7 +90,7 @@ async fn get_internal_transactions_by_tx_hash_success() {
#[tokio::test]
#[serial]
async fn get_erc20_transfer_events_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let txs = client
.get_erc20_token_transfer_events(
TokenQueryOption::ByAddress(
Expand All @@ -110,7 +111,7 @@ async fn get_erc20_transfer_events_success() {
#[tokio::test]
#[serial]
async fn get_erc721_transfer_events_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let txs = client
.get_erc721_token_transfer_events(
TokenQueryOption::ByAddressAndContract(
Expand All @@ -128,7 +129,7 @@ async fn get_erc721_transfer_events_success() {
#[tokio::test]
#[serial]
async fn get_erc1155_transfer_events_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let txs = client
.get_erc1155_token_transfer_events(
TokenQueryOption::ByAddressAndContract(
Expand All @@ -146,7 +147,7 @@ async fn get_erc1155_transfer_events_success() {
#[tokio::test]
#[serial]
async fn get_mined_blocks_success() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
client
.get_mined_blocks(
&"0x9dd134d14d1e65f84b706d6f205cd5b1cd03a46b".parse().unwrap(),
Expand All @@ -162,7 +163,7 @@ async fn get_mined_blocks_success() {
#[tokio::test]
#[serial]
async fn get_avalanche_transactions() {
run_with_client(Chain::Avalanche, |client| async move {
run_with_client(Chain::from_named(NamedChain::Avalanche), |client| async move {
let txs = client
.get_transactions(&"0x1549ea9b546ba9ffb306d78a1e1f304760cc4abf".parse().unwrap(), None)
.await;
Expand Down
4 changes: 2 additions & 2 deletions tests/it/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serial_test::serial;
#[tokio::test]
#[serial]
async fn check_get_block_by_timestamp_before() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let block_no = client.get_block_by_timestamp(1577836800, "before").await;
assert!(block_no.is_ok());

Expand All @@ -18,7 +18,7 @@ async fn check_get_block_by_timestamp_before() {
#[tokio::test]
#[serial]
async fn check_get_block_by_timestamp_after() {
run_with_client(Chain::Mainnet, |client| async move {
run_with_client(Chain::mainnet(), |client| async move {
let block_no = client.get_block_by_timestamp(1577836800, "after").await;

let block_no = block_no.unwrap().block_number;
Expand Down
Loading