Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
feat(core): Chain enum
Browse files Browse the repository at this point in the history
  • Loading branch information
shekhirin committed Oct 24, 2021
1 parent 35f7d67 commit dcb20f7
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 41 deletions.
16 changes: 6 additions & 10 deletions ethers-contract/src/multicall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ethers_core::{
};
use ethers_providers::Middleware;

use ethers_core::types::Chain;
use std::{collections::HashMap, str::FromStr, sync::Arc};

use crate::{
Expand All @@ -22,29 +23,24 @@ pub static ADDRESS_BOOK: Lazy<HashMap<U256, Address>> = Lazy::new(|| {
}

[
// mainnet
(
1.into(),
Chain::Mainnet.into(),
decode_address("eefba1e63905ef1d7acba5a8513c70307c1ce441"),
),
// rinkeby
(
4.into(),
Chain::Rinkeby.into(),
decode_address("42ad527de7d4e9d9d011ac45b31d8551f8fe9821"),
),
// goerli
(
5.into(),
Chain::Goerli.into(),
decode_address("77dca2c955b15e9de4dbbcf1246b4b85b651e50e"),
),
// kovan
(
42.into(),
Chain::Kovan.into(),
decode_address("2cc8688c5f75e365aaeeb4ea8d6a480405a48d2a"),
),
// xdai
(
100.into(),
Chain::XDai.into(),
decode_address("b5b692a88bdfc81ca69dcb1d924f59f0413a602a"),
),
]
Expand Down
38 changes: 38 additions & 0 deletions ethers-core/src/types/chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::fmt;

use crate::types::U256;

#[derive(Debug)]
pub enum Chain {
Mainnet,
Ropsten,
Rinkeby,
Goerli,
Kovan,
XDai,
}

impl fmt::Display for Chain {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?}", self)
}
}

impl From<Chain> for u32 {
fn from(chain: Chain) -> Self {
match chain {
Chain::Mainnet => 1,
Chain::Ropsten => 3,
Chain::Rinkeby => 4,
Chain::Goerli => 5,
Chain::Kovan => 42,
Chain::XDai => 100,
}
}
}

impl From<Chain> for U256 {
fn from(chain: Chain) -> Self {
u32::from(chain).into()
}
}
4 changes: 4 additions & 0 deletions ethers-core/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,9 @@ pub use txpool::*;
mod trace;
pub use trace::*;

mod chain;
pub use chain::*;

mod proof;

pub use proof::*;
14 changes: 8 additions & 6 deletions ethers-etherscan/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,12 @@ impl Client {
/// Returns the contract ABI of a verified contract
///
/// ```no_run
/// # use ethers_etherscan::{Chain, Client};
/// # use ethers_etherscan::Client;
/// # use ethers_core::types::Chain;
///
/// # #[tokio::main]
/// # async fn main() {
/// let client = Client::new(Chain::Mainnet, "API_KEY");
/// let client = Client::new(Chain::Mainnet, "API_KEY")?;
/// let abi = client
/// .contract_abi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap())
/// .await.unwrap();
Expand All @@ -235,11 +236,12 @@ impl Client {

/// Get Contract Source Code for Verified Contract Source Codes
/// ```no_run
/// # use ethers_etherscan::{Chain, Client};
/// # use ethers_etherscan::Client;
/// # use ethers_core::types::Chain;
///
/// # #[tokio::main]
/// # async fn main() {
/// let client = Client::new(Chain::Mainnet, "API_KEY");
/// let client = Client::new(Chain::Mainnet, "API_KEY")?;
/// let meta = client
/// .contract_source_code("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".parse().unwrap())
/// .await.unwrap();
Expand All @@ -261,8 +263,8 @@ impl Client {

#[cfg(test)]
mod tests {
use crate::contract::VerifyContract;
use crate::{Chain, Client};
use crate::{contract::VerifyContract, Client};
use ethers_core::types::Chain;

#[tokio::test]
#[ignore]
Expand Down
3 changes: 3 additions & 0 deletions ethers-etherscan/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use ethers_core::types::Chain;
use std::env::VarError;

#[derive(Debug, thiserror::Error)]
pub enum EtherscanError {
#[error("unknown chain {0}")]
UnknownChain(Chain),
#[error("contract execution call failed: {0}")]
ExecutionFailed(String),
#[error("tx receipt failed")]
Expand Down
55 changes: 30 additions & 25 deletions ethers-etherscan/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ mod transaction;

use errors::EtherscanError;
use ethers_core::abi::Address;
use ethers_core::types::Chain;
use reqwest::{header, Url};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{borrow::Cow, fmt};
use std::borrow::Cow;

pub type Result<T> = std::result::Result<T, EtherscanError>;

/// The Etherscan.io API client.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Client {
/// Client that executes HTTP requests
client: reqwest::Client,
Expand All @@ -25,47 +26,37 @@ pub struct Client {
etherscan_url: Url,
}

#[derive(Debug)]
pub enum Chain {
Mainnet,
Ropsten,
Kovan,
Rinkeby,
Goerli,
}

impl fmt::Display for Chain {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{}", format!("{:?}", self).to_lowercase())
}
}

impl Client {
/// Create a new client with the correct endpoints based on the chain and provided API key
pub fn new(chain: Chain, api_key: impl Into<String>) -> Self {
pub fn new(chain: Chain, api_key: impl Into<String>) -> Result<Self> {
let (etherscan_api_url, etherscan_url) = match chain {
Chain::Mainnet => (
Url::parse("https://api.etherscan.io/api"),
Url::parse("https://etherscan.io"),
),
Chain::Ropsten | Chain::Kovan | Chain::Rinkeby | Chain::Goerli => (
Url::parse(&format!("https://api-{}.etherscan.io/api", chain)),
Url::parse(&format!("https://{}.etherscan.io", chain)),
),
Chain::Ropsten | Chain::Kovan | Chain::Rinkeby | Chain::Goerli => {
let chain_name = chain.to_string().to_lowercase();

(
Url::parse(&format!("https://api-{}.etherscan.io/api", chain_name)),
Url::parse(&format!("https://{}.etherscan.io", chain_name)),
)
}
chain => return Err(EtherscanError::UnknownChain(chain)),
};

Self {
Ok(Self {
client: Default::default(),
api_key: api_key.into(),
etherscan_api_url: etherscan_api_url.expect("is valid http"),
etherscan_url: etherscan_url.expect("is valid http"),
}
})
}

/// Create a new client with the correct endpoints based on the chain and API key
/// from ETHERSCAN_API_KEY environment variable
pub fn new_from_env(chain: Chain) -> Result<Self> {
Ok(Self::new(chain, std::env::var("ETHERSCAN_API_KEY")?))
Self::new(chain, std::env::var("ETHERSCAN_API_KEY")?)
}

pub fn etherscan_api_url(&self) -> &Url {
Expand Down Expand Up @@ -157,3 +148,17 @@ struct Query<'a, T: Serialize> {
#[serde(flatten)]
other: T,
}

#[cfg(test)]
mod tests {
use crate::{Client, EtherscanError};
use ethers_core::types::Chain;

#[test]
fn unknown_chain() {
let err = Client::new_from_env(Chain::XDai).unwrap_err();

assert!(matches!(err, EtherscanError::UnknownChain(_)));
assert_eq!(err.to_string(), "unknown chain XDai");
}
}

0 comments on commit dcb20f7

Please sign in to comment.