feat: add etherscan urls function (#1582)
This commit is contained in:
parent
47d3333195
commit
922b23fad6
|
@ -13,6 +13,12 @@ use thiserror::Error;
|
||||||
#[error("Failed to parse chain: {0}")]
|
#[error("Failed to parse chain: {0}")]
|
||||||
pub struct ParseChainError(String);
|
pub struct ParseChainError(String);
|
||||||
|
|
||||||
|
/// Enum for all known chains
|
||||||
|
///
|
||||||
|
/// When adding a new chain:
|
||||||
|
/// 1. add new variant
|
||||||
|
/// 2. update Display/FromStr impl
|
||||||
|
/// 3. add etherscan_keys if supported
|
||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Deserialize, EnumVariantNames)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Deserialize, EnumVariantNames)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
|
@ -92,6 +98,100 @@ impl Chain {
|
||||||
|
|
||||||
Some(Duration::from_millis(ms))
|
Some(Duration::from_millis(ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the corresponding etherscan URLs
|
||||||
|
///
|
||||||
|
/// Returns `(API URL, BASE_URL)`, like `("https://api(-chain).etherscan.io/api", "https://etherscan.io")`
|
||||||
|
pub fn etherscan_urls(&self) -> Option<(&'static str, &'static str)> {
|
||||||
|
let urls = match self {
|
||||||
|
Chain::Mainnet => ("https://api.etherscan.io/api", "https://etherscan.io"),
|
||||||
|
Chain::Ropsten => {
|
||||||
|
("https://api-ropsten.etherscan.io/api", "https://ropsten.etherscan.io")
|
||||||
|
}
|
||||||
|
Chain::Kovan => ("https://api-kovan.etherscan.io/api", "https://kovan.etherscan.io"),
|
||||||
|
Chain::Rinkeby => {
|
||||||
|
("https://api-rinkeby.etherscan.io/api", "https://rinkeby.etherscan.io")
|
||||||
|
}
|
||||||
|
Chain::Goerli => ("https://api-goerli.etherscan.io/api", "https://goerli.etherscan.io"),
|
||||||
|
Chain::Sepolia => {
|
||||||
|
("https://api-sepolia.etherscan.io/api", "https://sepolia.etherscan.io")
|
||||||
|
}
|
||||||
|
Chain::Polygon => ("https://api.polygonscan.com/api", "https://polygonscan.com"),
|
||||||
|
Chain::PolygonMumbai => {
|
||||||
|
("https://api-testnet.polygonscan.com/api", "https://mumbai.polygonscan.com")
|
||||||
|
}
|
||||||
|
Chain::Avalanche => ("https://api.snowtrace.io/api", "https://snowtrace.io"),
|
||||||
|
Chain::AvalancheFuji => {
|
||||||
|
("https://api-testnet.snowtrace.io/api", "https://testnet.snowtrace.io")
|
||||||
|
}
|
||||||
|
Chain::Optimism => {
|
||||||
|
("https://api-optimistic.etherscan.io/api", "https://optimistic.etherscan.io")
|
||||||
|
}
|
||||||
|
Chain::OptimismKovan => (
|
||||||
|
"https://api-kovan-optimistic.etherscan.io/api",
|
||||||
|
"https://kovan-optimistic.etherscan.io",
|
||||||
|
),
|
||||||
|
Chain::Fantom => ("https://api.ftmscan.com/api", "https://ftmscan.com"),
|
||||||
|
Chain::FantomTestnet => {
|
||||||
|
("https://api-testnet.ftmscan.com/api", "https://testnet.ftmscan.com")
|
||||||
|
}
|
||||||
|
Chain::BinanceSmartChain => ("https://api.bscscan.com/api", "https://bscscan.com"),
|
||||||
|
Chain::BinanceSmartChainTestnet => {
|
||||||
|
("https://api-testnet.bscscan.com/api", "https://testnet.bscscan.com")
|
||||||
|
}
|
||||||
|
Chain::Arbitrum => ("https://api.arbiscan.io/api", "https://arbiscan.io"),
|
||||||
|
Chain::ArbitrumTestnet => {
|
||||||
|
("https://api-testnet.arbiscan.io/api", "https://testnet.arbiscan.io")
|
||||||
|
}
|
||||||
|
Chain::Cronos => ("https://api.cronoscan.com/api", "https://cronoscan.com"),
|
||||||
|
Chain::CronosTestnet => {
|
||||||
|
("https://api-testnet.cronoscan.com/api", "https://testnet.cronoscan.com")
|
||||||
|
}
|
||||||
|
Chain::Moonbeam => {
|
||||||
|
("https://api-moonbeam.moonscan.io/api", "https://moonbeam.moonscan.io/")
|
||||||
|
}
|
||||||
|
Chain::Moonbase => {
|
||||||
|
("https://api-moonbase.moonscan.io/api", "https://moonbase.moonscan.io/")
|
||||||
|
}
|
||||||
|
Chain::Moonriver => {
|
||||||
|
("https://api-moonriver.moonscan.io/api", "https://moonriver.moonscan.io")
|
||||||
|
}
|
||||||
|
// blockscout API is etherscan compatible
|
||||||
|
Chain::XDai => {
|
||||||
|
("https://blockscout.com/xdai/mainnet/api", "https://blockscout.com/xdai/mainnet")
|
||||||
|
}
|
||||||
|
Chain::Sokol => {
|
||||||
|
("https://blockscout.com/poa/sokol/api", "https://blockscout.com/poa/sokol")
|
||||||
|
}
|
||||||
|
Chain::Poa => {
|
||||||
|
("https://blockscout.com/poa/core/api", "https://blockscout.com/poa/core")
|
||||||
|
}
|
||||||
|
Chain::Rsk => {
|
||||||
|
("https://blockscout.com/rsk/mainnet/api", "https://blockscout.com/rsk/mainnet")
|
||||||
|
}
|
||||||
|
Chain::Oasis => ("https://scan.oasischain.io/api", "https://scan.oasischain.io/"),
|
||||||
|
Chain::Emerald => {
|
||||||
|
("https://explorer.emerald.oasis.dev/api", "https://explorer.emerald.oasis.dev/")
|
||||||
|
}
|
||||||
|
Chain::EmeraldTestnet => (
|
||||||
|
"https://testnet.explorer.emerald.oasis.dev/api",
|
||||||
|
"https://testnet.explorer.emerald.oasis.dev/",
|
||||||
|
),
|
||||||
|
Chain::Aurora => ("https://api.aurorascan.dev/api", "https://aurorascan.dev"),
|
||||||
|
Chain::AuroraTestnet => {
|
||||||
|
("https://testnet.aurorascan.dev/api", "https://testnet.aurorascan.dev")
|
||||||
|
}
|
||||||
|
Chain::Evmos => ("https://evm.evmos.org/api", "https://evm.evmos.org/"),
|
||||||
|
Chain::EvmosTestnet => ("https://evm.evmos.dev/api", "https://evm.evmos.dev/"),
|
||||||
|
Chain::AnvilHardhat | Chain::Dev | Chain::Morden | Chain::MoonbeamDev => {
|
||||||
|
// this is explicitly exhaustive so we don't forget to add new urls when adding a
|
||||||
|
// new chain
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(urls)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Chain {
|
impl fmt::Display for Chain {
|
||||||
|
|
|
@ -231,90 +231,10 @@ impl ClientBuilder {
|
||||||
) -> (reqwest::Result<Url>, reqwest::Result<Url>) {
|
) -> (reqwest::Result<Url>, reqwest::Result<Url>) {
|
||||||
(api.into_url(), url.into_url())
|
(api.into_url(), url.into_url())
|
||||||
}
|
}
|
||||||
|
let (etherscan_api_url, etherscan_url) = chain
|
||||||
let (etherscan_api_url, etherscan_url) = match chain {
|
.etherscan_urls()
|
||||||
Chain::Mainnet => urls("https://api.etherscan.io/api", "https://etherscan.io"),
|
.map(|(api, base)| urls(api, base))
|
||||||
Chain::Ropsten | Chain::Kovan | Chain::Rinkeby | Chain::Goerli | Chain::Sepolia => {
|
.ok_or(EtherscanError::ChainNotSupported(chain))?;
|
||||||
let chain_name = chain.to_string().to_lowercase();
|
|
||||||
urls(
|
|
||||||
format!("https://api-{}.etherscan.io/api", chain_name),
|
|
||||||
format!("https://{}.etherscan.io", chain_name),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Chain::Polygon => urls("https://api.polygonscan.com/api", "https://polygonscan.com"),
|
|
||||||
Chain::PolygonMumbai => {
|
|
||||||
urls("https://api-testnet.polygonscan.com/api", "https://mumbai.polygonscan.com")
|
|
||||||
}
|
|
||||||
Chain::Avalanche => urls("https://api.snowtrace.io/api", "https://snowtrace.io"),
|
|
||||||
Chain::AvalancheFuji => {
|
|
||||||
urls("https://api-testnet.snowtrace.io/api", "https://testnet.snowtrace.io")
|
|
||||||
}
|
|
||||||
Chain::Optimism => {
|
|
||||||
urls("https://api-optimistic.etherscan.io/api", "https://optimistic.etherscan.io")
|
|
||||||
}
|
|
||||||
Chain::OptimismKovan => urls(
|
|
||||||
"https://api-kovan-optimistic.etherscan.io/api",
|
|
||||||
"https://kovan-optimistic.etherscan.io",
|
|
||||||
),
|
|
||||||
Chain::Fantom => urls("https://api.ftmscan.com/api", "https://ftmscan.com"),
|
|
||||||
Chain::FantomTestnet => {
|
|
||||||
urls("https://api-testnet.ftmscan.com/api", "https://testnet.ftmscan.com")
|
|
||||||
}
|
|
||||||
Chain::BinanceSmartChain => urls("https://api.bscscan.com/api", "https://bscscan.com"),
|
|
||||||
Chain::BinanceSmartChainTestnet => {
|
|
||||||
urls("https://api-testnet.bscscan.com/api", "https://testnet.bscscan.com")
|
|
||||||
}
|
|
||||||
Chain::Arbitrum => urls("https://api.arbiscan.io/api", "https://arbiscan.io"),
|
|
||||||
Chain::ArbitrumTestnet => {
|
|
||||||
urls("https://api-testnet.arbiscan.io/api", "https://testnet.arbiscan.io")
|
|
||||||
}
|
|
||||||
Chain::Cronos => urls("https://api.cronoscan.com/api", "https://cronoscan.com"),
|
|
||||||
Chain::CronosTestnet => {
|
|
||||||
urls("https://api-testnet.cronoscan.com/api", "https://testnet.cronoscan.com")
|
|
||||||
}
|
|
||||||
Chain::Moonbeam => {
|
|
||||||
urls("https://api-moonbeam.moonscan.io/api", "https://moonbeam.moonscan.io/")
|
|
||||||
}
|
|
||||||
Chain::Moonbase => {
|
|
||||||
urls("https://api-moonbase.moonscan.io/api", "https://moonbase.moonscan.io/")
|
|
||||||
}
|
|
||||||
Chain::Moonriver => {
|
|
||||||
urls("https://api-moonriver.moonscan.io/api", "https://moonriver.moonscan.io")
|
|
||||||
}
|
|
||||||
// blockscout API is etherscan compatible
|
|
||||||
Chain::XDai => urls(
|
|
||||||
"https://blockscout.com/xdai/mainnet/api",
|
|
||||||
"https://blockscout.com/xdai/mainnet",
|
|
||||||
),
|
|
||||||
Chain::Sokol => {
|
|
||||||
urls("https://blockscout.com/poa/sokol/api", "https://blockscout.com/poa/sokol")
|
|
||||||
}
|
|
||||||
Chain::Poa => {
|
|
||||||
urls("https://blockscout.com/poa/core/api", "https://blockscout.com/poa/core")
|
|
||||||
}
|
|
||||||
Chain::Rsk => {
|
|
||||||
urls("https://blockscout.com/rsk/mainnet/api", "https://blockscout.com/rsk/mainnet")
|
|
||||||
}
|
|
||||||
Chain::Oasis => urls("https://scan.oasischain.io/api", "https://scan.oasischain.io/"),
|
|
||||||
Chain::Emerald => urls(
|
|
||||||
"https://explorer.emerald.oasis.dev/api",
|
|
||||||
"https://explorer.emerald.oasis.dev/",
|
|
||||||
),
|
|
||||||
Chain::EmeraldTestnet => urls(
|
|
||||||
"https://testnet.explorer.emerald.oasis.dev/api",
|
|
||||||
"https://testnet.explorer.emerald.oasis.dev/",
|
|
||||||
),
|
|
||||||
Chain::Aurora => urls("https://api.aurorascan.dev/api", "https://aurorascan.dev"),
|
|
||||||
Chain::AuroraTestnet => {
|
|
||||||
urls("https://testnet.aurorascan.dev/api", "https://testnet.aurorascan.dev")
|
|
||||||
}
|
|
||||||
Chain::AnvilHardhat | Chain::Dev => {
|
|
||||||
return Err(EtherscanError::LocalNetworksNotSupported)
|
|
||||||
}
|
|
||||||
Chain::Evmos => urls("https://evm.evmos.org/api", "https://evm.evmos.org/"),
|
|
||||||
Chain::EvmosTestnet => urls("https://evm.evmos.dev/api", "https://evm.evmos.dev/"),
|
|
||||||
chain => return Err(EtherscanError::ChainNotSupported(chain)),
|
|
||||||
};
|
|
||||||
self.with_api_url(etherscan_api_url?)?.with_url(etherscan_url?)
|
self.with_api_url(etherscan_api_url?)?.with_url(etherscan_url?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue