feat(core): chain macros and impls (#1958)

This commit is contained in:
DaniPopes 2022-12-22 13:44:51 +01:00 committed by GitHub
parent 813600e6c9
commit e007ea01b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 272 additions and 353 deletions

22
Cargo.lock generated
View File

@ -1420,6 +1420,7 @@ dependencies = [
"hex",
"hex-literal",
"k256",
"num_enum",
"once_cell",
"open-fastrlp",
"proc-macro2",
@ -2576,6 +2577,27 @@ dependencies = [
"libc",
]
[[package]]
name = "num_enum"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num_threads"
version = "0.1.3"

View File

@ -42,6 +42,7 @@ cargo_metadata = { version = "0.15.2", optional = true }
convert_case = { version = "0.6.0", optional = true }
syn = { version = "1.0.105", optional = true }
proc-macro2 = { version = "1.0.47", optional = true }
num_enum = "0.5.7"
[dev-dependencies]
tempfile = { version = "3.3.0", default-features = false }

View File

@ -1,138 +1,160 @@
use super::U256;
use super::{U128, U256, U512, U64};
use num_enum::{TryFromPrimitive, TryFromPrimitiveError};
use serde::{Deserialize, Serialize, Serializer};
use std::{
convert::{TryFrom, TryInto},
fmt,
str::FromStr,
time::Duration,
};
use strum::EnumVariantNames;
use thiserror::Error;
#[derive(Debug, Clone, Error)]
#[error("Failed to parse chain: {0}")]
pub struct ParseChainError(String);
use strum::{AsRefStr, EnumString, EnumVariantNames};
// When adding a new chain:
// 1. add new variant to the Chain enum;
// 2. update Display/FromStr impl;
// 3. add etherscan_keys if supported.
// 2. add extra information in the last `impl` block (explorer URLs, block time) when applicable;
// 3. (optional) add aliases: `#[strum(serialize = "main", serialize = "alias", ...)]`;
// "main" must be present and will be used in `Display`, `Serialize` and `FromStr`,
// while the aliases will be added only to `FromStr`.
/// Enum for all known chains.
#[repr(u64)]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, Deserialize, EnumVariantNames)]
/// An Ethereum EIP-155 chain.
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
AsRefStr, // also for fmt::Display and serde::Serialize
EnumVariantNames, // Self::VARIANTS
EnumString, // FromStr, TryFrom<&str>
TryFromPrimitive, // TryFrom<u64>
Deserialize,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "kebab-case")]
#[repr(u64)]
pub enum Chain {
#[default]
Mainnet = 1,
Morden = 2,
Ropsten = 3,
Rinkeby = 4,
Goerli = 5,
Optimism = 10,
Cronos = 25,
Rsk = 30,
Kovan = 42,
#[strum(serialize = "bsc")]
BinanceSmartChain = 56,
Sepolia = 11155111,
Optimism = 10,
OptimismKovan = 69,
Sokol = 77,
#[strum(serialize = "bsc-testnet")]
BinanceSmartChainTestnet = 97,
Poa = 99,
#[strum(serialize = "gnosis")]
XDai = 100,
Polygon = 137,
Fantom = 250,
CronosTestnet = 338,
OptimismGoerli = 420,
MoonbeamDev = 1281,
Moonbeam = 1284,
Moonriver = 1285,
Moonbase = 1287,
Dev = 1337,
FantomTestnet = 4002,
EvmosTestnet = 9000,
Evmos = 9001,
Chiado = 10200,
Oasis = 26863,
AnvilHardhat = 31337,
Arbitrum = 42161,
EmeraldTestnet = 42261,
Emerald = 42262,
AvalancheFuji = 43113,
Avalanche = 43114,
PolygonMumbai = 80001,
ArbitrumTestnet = 421611,
ArbitrumGoerli = 421613,
Sepolia = 11155111,
Aurora = 1313161554,
AuroraTestnet = 1313161555,
Cronos = 25,
CronosTestnet = 338,
Rsk = 30,
#[strum(serialize = "bsc")]
BinanceSmartChain = 56,
#[strum(serialize = "bsc-testnet")]
BinanceSmartChainTestnet = 97,
Poa = 99,
Sokol = 77,
#[strum(serialize = "gnosis", serialize = "xdai", serialize = "gnosis-chain")]
XDai = 100,
Polygon = 137,
#[strum(serialize = "mumbai", serialize = "polygon-mumbai")]
PolygonMumbai = 80001,
Fantom = 250,
FantomTestnet = 4002,
Moonbeam = 1284,
MoonbeamDev = 1281,
Moonriver = 1285,
Moonbase = 1287,
#[strum(serialize = "dev")]
Dev = 1337,
#[strum(serialize = "anvil-hardhat", serialize = "anvil", serialize = "hardhat")]
AnvilHardhat = 31337,
Evmos = 9001,
EvmosTestnet = 9000,
Chiado = 10200,
Oasis = 26863,
Emerald = 42262,
EmeraldTestnet = 42261,
Avalanche = 43114,
#[strum(serialize = "fuji", serialize = "avalanche-fuji")]
AvalancheFuji = 43113,
Celo = 42220,
CeloAlfajores = 44787,
CeloBaklava = 62320,
Aurora = 1313161554,
AuroraTestnet = 1313161555,
}
// === impl Chain ===
impl fmt::Display for Chain {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let chain = match self {
Chain::Mainnet => "mainnet",
Chain::Morden => "morden",
Chain::Ropsten => "ropsten",
Chain::Rinkeby => "rinkeby",
Chain::Goerli => "goerli",
Chain::Kovan => "kovan",
Chain::XDai => "gnosis",
Chain::Chiado => "chiado",
Chain::Polygon => "polygon",
Chain::PolygonMumbai => "mumbai",
Chain::Avalanche => "avalanche",
Chain::AvalancheFuji => "fuji",
Chain::Sepolia => "sepolia",
Chain::Moonbeam => "moonbeam",
Chain::Moonbase => "moonbase",
Chain::MoonbeamDev => "moonbeam-dev",
Chain::Moonriver => "moonriver",
Chain::Optimism => "optimism",
Chain::OptimismGoerli => "optimism-goerli",
Chain::OptimismKovan => "optimism-kovan",
Chain::Fantom => "fantom",
Chain::Dev => "dev",
Chain::FantomTestnet => "fantom-testnet",
Chain::BinanceSmartChain => "bsc",
Chain::BinanceSmartChainTestnet => "bsc-testnet",
Chain::Arbitrum => "arbitrum",
Chain::ArbitrumTestnet => "arbitrum-testnet",
Chain::ArbitrumGoerli => "arbitrum-goerli",
Chain::Cronos => "cronos",
Chain::CronosTestnet => "cronos-testnet",
Chain::Poa => "poa",
Chain::Sokol => "sokol",
Chain::Rsk => "rsk",
Chain::Oasis => "oasis",
Chain::Emerald => "emerald",
Chain::EmeraldTestnet => "emerald-testnet",
Chain::AnvilHardhat => "anvil-hardhat",
Chain::Evmos => "evmos",
Chain::EvmosTestnet => "evmos-testnet",
Chain::Aurora => "aurora",
Chain::AuroraTestnet => "aurora-testnet",
Chain::Celo => "celo",
Chain::CeloAlfajores => "celo-alfajores",
Chain::CeloBaklava => "celo-baklava",
};
f.pad(chain)
// This must be implemented manually so we avoid a conflict with `TryFromPrimitive` where it treats
// the `#[default]` attribute as its own `#[num_enum(default)]`
impl Default for Chain {
fn default() -> Self {
Self::Mainnet
}
}
impl From<Chain> for u32 {
fn from(chain: Chain) -> Self {
chain as u32
}
macro_rules! impl_into_numeric {
($($ty:ty)+) => {$(
impl From<Chain> for $ty {
fn from(chain: Chain) -> Self {
u64::from(chain).into()
}
}
)+};
}
macro_rules! impl_try_from_numeric {
($($native:ty)+ ; $($primitive:ty)*) => {
$(
impl TryFrom<$native> for Chain {
type Error = TryFromPrimitiveError<Self>;
fn try_from(value: $native) -> Result<Self, Self::Error> {
(value as u64).try_into()
}
}
)+
$(
impl TryFrom<$primitive> for Chain {
type Error = TryFromPrimitiveError<Self>;
fn try_from(value: $primitive) -> Result<Self, Self::Error> {
if value.bits() > 64 {
// `TryFromPrimitiveError` only has a `number` field which has the same type
// as the `#[repr(_)]` attribute on the enum.
return Err(TryFromPrimitiveError { number: value.low_u64() })
}
value.low_u64().try_into()
}
}
)*
};
}
impl From<Chain> for u64 {
@ -141,134 +163,21 @@ impl From<Chain> for u64 {
}
}
impl From<Chain> for U256 {
fn from(chain: Chain) -> Self {
u64::from(chain).into()
impl_into_numeric!(u128 U64 U128 U256 U512);
impl TryFrom<U64> for Chain {
type Error = TryFromPrimitiveError<Self>;
fn try_from(value: U64) -> Result<Self, Self::Error> {
value.low_u64().try_into()
}
}
impl TryFrom<u32> for Chain {
type Error = ParseChainError;
impl_try_from_numeric!(u8 u16 u32 usize; U128 U256 U512);
fn try_from(chain: u32) -> Result<Chain, Self::Error> {
(chain as u64).try_into()
}
}
impl TryFrom<u64> for Chain {
type Error = ParseChainError;
fn try_from(chain: u64) -> Result<Chain, Self::Error> {
Ok(match chain {
1 => Chain::Mainnet,
2 => Chain::Morden,
3 => Chain::Ropsten,
4 => Chain::Rinkeby,
5 => Chain::Goerli,
42 => Chain::Kovan,
100 => Chain::XDai,
10200 => Chain::Chiado,
137 => Chain::Polygon,
1337 => Chain::Dev,
31337 => Chain::AnvilHardhat,
250 => Chain::Fantom,
4002 => Chain::FantomTestnet,
80001 => Chain::PolygonMumbai,
43114 => Chain::Avalanche,
43113 => Chain::AvalancheFuji,
11155111 => Chain::Sepolia,
1284 => Chain::Moonbeam,
1287 => Chain::Moonbase,
1281 => Chain::MoonbeamDev,
1285 => Chain::Moonriver,
10 => Chain::Optimism,
420 => Chain::OptimismGoerli,
69 => Chain::OptimismKovan,
56 => Chain::BinanceSmartChain,
97 => Chain::BinanceSmartChainTestnet,
42161 => Chain::Arbitrum,
421611 => Chain::ArbitrumTestnet,
421613 => Chain::ArbitrumGoerli,
25 => Chain::Cronos,
338 => Chain::CronosTestnet,
99 => Chain::Poa,
77 => Chain::Sokol,
30 => Chain::Rsk,
26863 => Chain::Oasis,
42262 => Chain::Emerald,
42261 => Chain::EmeraldTestnet,
9001 => Chain::Evmos,
9000 => Chain::EvmosTestnet,
1313161554 => Chain::Aurora,
1313161555 => Chain::AuroraTestnet,
42220 => Chain::Celo,
44787 => Chain::CeloAlfajores,
62320 => Chain::CeloBaklava,
_ => return Err(ParseChainError(chain.to_string())),
})
}
}
impl TryFrom<U256> for Chain {
type Error = ParseChainError;
fn try_from(chain: U256) -> Result<Chain, Self::Error> {
if chain.bits() > 64 {
return Err(ParseChainError(chain.to_string()))
}
chain.as_u64().try_into()
}
}
impl FromStr for Chain {
type Err = ParseChainError;
fn from_str(chain: &str) -> Result<Self, Self::Err> {
Ok(match chain {
"mainnet" => Chain::Mainnet,
"morden" => Chain::Morden,
"ropsten" => Chain::Ropsten,
"rinkeby" => Chain::Rinkeby,
"goerli" => Chain::Goerli,
"kovan" => Chain::Kovan,
"xdai" | "gnosis" | "gnosis-chain" => Chain::XDai,
"chiado" => Chain::Chiado,
"polygon" => Chain::Polygon,
"mumbai" | "polygon-mumbai" => Chain::PolygonMumbai,
"avalanche" => Chain::Avalanche,
"fuji" | "avalanche-fuji" => Chain::AvalancheFuji,
"sepolia" => Chain::Sepolia,
"moonbeam" => Chain::Moonbeam,
"moonbase" => Chain::Moonbase,
"moonbeam-dev" => Chain::MoonbeamDev,
"moonriver" => Chain::Moonriver,
"optimism" => Chain::Optimism,
"optimism-goerli" => Chain::OptimismGoerli,
"optimism-kovan" => Chain::OptimismKovan,
"fantom" => Chain::Fantom,
"fantom-testnet" => Chain::FantomTestnet,
"dev" => Chain::Dev,
"anvil" | "hardhat" | "anvil-hardhat" => Chain::AnvilHardhat,
"bsc" => Chain::BinanceSmartChain,
"bsc-testnet" => Chain::BinanceSmartChainTestnet,
"arbitrum" => Chain::Arbitrum,
"arbitrum-testnet" => Chain::ArbitrumTestnet,
"arbitrum-goerli" => Chain::ArbitrumGoerli,
"cronos" => Chain::Cronos,
"cronos-testnet" => Chain::CronosTestnet,
"poa" => Chain::Poa,
"sokol" => Chain::Sokol,
"rsk" => Chain::Rsk,
"oasis" => Chain::Oasis,
"emerald" => Chain::Emerald,
"emerald-testnet" => Chain::EmeraldTestnet,
"aurora" => Chain::Aurora,
"aurora-testnet" => Chain::AuroraTestnet,
"celo" => Chain::Celo,
"celo-alfajores" => Chain::CeloAlfajores,
"celo-baklava" => Chain::CeloBaklava,
_ => return Err(ParseChainError(chain.to_owned())),
})
impl fmt::Display for Chain {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(self.as_ref())
}
}
@ -277,163 +186,135 @@ impl Serialize for Chain {
where
S: Serializer,
{
s.serialize_str(self.to_string().as_ref())
s.serialize_str(self.as_ref())
}
}
// NB: all utility functions *should* be explicitly exhaustive (not use `_` matcher) so we don't
// forget to update them when adding a new `Chain` variant.
impl Chain {
/// The blocktime varies from chain to chain.
/// Returns the chain's average blocktime, if applicable.
///
/// It can be beneficial to know the average blocktime to adjust the polling of an HTTP provider
/// for example.
///
/// **Note:** this will not return the accurate average depending on the time but is rather a
/// sensible default derived from blocktime charts like <https://etherscan.com/chart/blocktime>
/// <https://polygonscan.com/chart/blocktime>
pub fn average_blocktime_hint(&self) -> Option<Duration> {
/// **Note:** this is not an accurate average, but is rather a sensible default derived from
/// blocktime charts such as [Etherscan's](https://etherscan.com/chart/blocktime)
/// or [Polygonscan's](https://polygonscan.com/chart/blocktime).
pub const fn average_blocktime_hint(&self) -> Option<Duration> {
use Chain::*;
let ms = match self {
Chain::Arbitrum | Chain::ArbitrumTestnet | Chain::ArbitrumGoerli => 1_300,
Chain::Mainnet | Chain::Optimism => 13_000,
Chain::Polygon | Chain::PolygonMumbai => 2_100,
Chain::Moonbeam | Chain::Moonriver => 12_500,
Chain::BinanceSmartChain | Chain::BinanceSmartChainTestnet => 3_000,
Chain::Avalanche | Chain::AvalancheFuji => 2_000,
Chain::Fantom | Chain::FantomTestnet => 1_200,
Chain::Cronos | Chain::CronosTestnet => 5_700,
Chain::Evmos | Chain::EvmosTestnet => 1_900,
Chain::Aurora | Chain::AuroraTestnet => 1_100,
Chain::Oasis => 5_500,
Chain::Emerald => 6_000,
Chain::Dev | Chain::AnvilHardhat => 200,
Chain::Celo | Chain::CeloAlfajores | Chain::CeloBaklava => 5_000,
Arbitrum | ArbitrumTestnet | ArbitrumGoerli => 1_300,
Mainnet | Optimism => 13_000,
Polygon | PolygonMumbai => 2_100,
Moonbeam | Moonriver => 12_500,
BinanceSmartChain | BinanceSmartChainTestnet => 3_000,
Avalanche | AvalancheFuji => 2_000,
Fantom | FantomTestnet => 1_200,
Cronos | CronosTestnet => 5_700,
Evmos | EvmosTestnet => 1_900,
Aurora | AuroraTestnet => 1_100,
Oasis => 5_500,
Emerald => 6_000,
Dev | AnvilHardhat => 200,
Celo | CeloAlfajores | CeloBaklava => 5_000,
// Explictly handle all network to make it easier not to forget this match when new
// networks are added.
Chain::Morden |
Chain::Ropsten |
Chain::Rinkeby |
Chain::Goerli |
Chain::Kovan |
Chain::XDai |
Chain::Chiado |
Chain::Sepolia |
Chain::Moonbase |
Chain::MoonbeamDev |
Chain::OptimismGoerli |
Chain::OptimismKovan |
Chain::Poa |
Chain::Sokol |
Chain::Rsk |
Chain::EmeraldTestnet => return None,
Morden | Ropsten | Rinkeby | Goerli | Kovan | XDai | Chiado | Sepolia | Moonbase |
MoonbeamDev | OptimismGoerli | OptimismKovan | Poa | Sokol | Rsk | EmeraldTestnet => {
return None
}
};
Some(Duration::from_millis(ms))
}
/// Returns the corresponding etherscan URLs
/// Returns the chain's blockchain explorer and its API (Etherscan and Etherscan-like) 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)> {
pub const fn etherscan_urls(&self) -> Option<(&'static str, &'static str)> {
use Chain::*;
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 => {
Mainnet => ("https://api.etherscan.io/api", "https://etherscan.io"),
Ropsten => ("https://api-ropsten.etherscan.io/api", "https://ropsten.etherscan.io"),
Kovan => ("https://api-kovan.etherscan.io/api", "https://kovan.etherscan.io"),
Rinkeby => ("https://api-rinkeby.etherscan.io/api", "https://rinkeby.etherscan.io"),
Goerli => ("https://api-goerli.etherscan.io/api", "https://goerli.etherscan.io"),
Sepolia => ("https://api-sepolia.etherscan.io/api", "https://sepolia.etherscan.io"),
Polygon => ("https://api.polygonscan.com/api", "https://polygonscan.com"),
PolygonMumbai => {
("https://api-testnet.polygonscan.com/api", "https://mumbai.polygonscan.com")
}
Chain::Avalanche => ("https://api.snowtrace.io/api", "https://snowtrace.io"),
Chain::AvalancheFuji => {
Avalanche => ("https://api.snowtrace.io/api", "https://snowtrace.io"),
AvalancheFuji => {
("https://api-testnet.snowtrace.io/api", "https://testnet.snowtrace.io")
}
Chain::Optimism => {
Optimism => {
("https://api-optimistic.etherscan.io/api", "https://optimistic.etherscan.io")
}
Chain::OptimismGoerli => (
OptimismGoerli => (
"https://api-goerli-optimistic.etherscan.io/api",
"https://goerli-optimism.etherscan.io",
),
Chain::OptimismKovan => (
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 => {
Fantom => ("https://api.ftmscan.com/api", "https://ftmscan.com"),
FantomTestnet => ("https://api-testnet.ftmscan.com/api", "https://testnet.ftmscan.com"),
BinanceSmartChain => ("https://api.bscscan.com/api", "https://bscscan.com"),
BinanceSmartChainTestnet => {
("https://api-testnet.bscscan.com/api", "https://testnet.bscscan.com")
}
Chain::Arbitrum => ("https://api.arbiscan.io/api", "https://arbiscan.io"),
Chain::ArbitrumTestnet => {
Arbitrum => ("https://api.arbiscan.io/api", "https://arbiscan.io"),
ArbitrumTestnet => {
("https://api-testnet.arbiscan.io/api", "https://testnet.arbiscan.io")
}
Chain::ArbitrumGoerli => (
ArbitrumGoerli => (
"https://goerli-rollup-explorer.arbitrum.io/api",
"https://goerli-rollup-explorer.arbitrum.io",
),
Chain::Cronos => ("https://api.cronoscan.com/api", "https://cronoscan.com"),
Chain::CronosTestnet => {
Cronos => ("https://api.cronoscan.com/api", "https://cronoscan.com"),
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")
}
Moonbeam => ("https://api-moonbeam.moonscan.io/api", "https://moonbeam.moonscan.io/"),
Moonbase => ("https://api-moonbase.moonscan.io/api", "https://moonbase.moonscan.io/"),
Moonriver => ("https://api-moonriver.moonscan.io/api", "https://moonriver.moonscan.io"),
// blockscout API is etherscan compatible
Chain::XDai => {
XDai => {
("https://blockscout.com/xdai/mainnet/api", "https://blockscout.com/xdai/mainnet")
}
Chain::Chiado => {
Chiado => {
("https://blockscout.chiadochain.net/api", "https://blockscout.chiadochain.net")
}
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 => {
Sokol => ("https://blockscout.com/poa/sokol/api", "https://blockscout.com/poa/sokol"),
Poa => ("https://blockscout.com/poa/core/api", "https://blockscout.com/poa/core"),
Rsk => ("https://blockscout.com/rsk/mainnet/api", "https://blockscout.com/rsk/mainnet"),
Oasis => ("https://scan.oasischain.io/api", "https://scan.oasischain.io/"),
Emerald => {
("https://explorer.emerald.oasis.dev/api", "https://explorer.emerald.oasis.dev/")
}
Chain::EmeraldTestnet => (
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 => {
Aurora => ("https://api.aurorascan.dev/api", "https://aurorascan.dev"),
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::Celo => {
("https://explorer.celo.org/mainnet", "https://explorer.celo.org/mainnet/api")
}
Chain::CeloAlfajores => {
Evmos => ("https://evm.evmos.org/api", "https://evm.evmos.org/"),
EvmosTestnet => ("https://evm.evmos.dev/api", "https://evm.evmos.dev/"),
Celo => ("https://explorer.celo.org/mainnet", "https://explorer.celo.org/mainnet/api"),
CeloAlfajores => {
("https://explorer.celo.org/alfajores", "https://explorer.celo.org/alfajores/api")
}
Chain::CeloBaklava => {
CeloBaklava => {
("https://explorer.celo.org/baklava", "https://explorer.celo.org/baklava/api")
}
Chain::AnvilHardhat | Chain::Dev | Chain::Morden | Chain::MoonbeamDev => {
AnvilHardhat | Dev | Morden | MoonbeamDev => {
// this is explicitly exhaustive so we don't forget to add new urls when adding a
// new chain
return None
@ -443,34 +324,49 @@ impl Chain {
Some(urls)
}
/// Helper function for checking if a chainid corresponds to a legacy chainid
/// without eip1559
pub fn is_legacy(&self) -> bool {
// TODO: Add other chains which do not support EIP1559.
matches!(
self,
Chain::Optimism |
Chain::OptimismGoerli |
Chain::OptimismKovan |
Chain::Fantom |
Chain::FantomTestnet |
Chain::BinanceSmartChain |
Chain::BinanceSmartChainTestnet |
Chain::Arbitrum |
Chain::ArbitrumTestnet |
Chain::ArbitrumGoerli |
Chain::Rsk |
Chain::Oasis |
Chain::Emerald |
Chain::EmeraldTestnet |
Chain::Celo |
Chain::CeloAlfajores |
Chain::CeloBaklava,
)
/// Returns whether the chain implements EIP-1559 (with the type 2 EIP-2718 transaction type).
pub const fn is_legacy(&self) -> bool {
use Chain::*;
match self {
// Known legacy chains / non EIP-1559 compliant
Optimism |
OptimismGoerli |
OptimismKovan |
Fantom |
FantomTestnet |
BinanceSmartChain |
BinanceSmartChainTestnet |
Arbitrum |
ArbitrumTestnet |
ArbitrumGoerli |
Rsk |
Oasis |
Emerald |
EmeraldTestnet |
Celo |
CeloAlfajores |
CeloBaklava => true,
// Known EIP-1559 chains
Mainnet | Goerli | Sepolia | Polygon | PolygonMumbai | Avalanche | AvalancheFuji => {
false
}
// Unknown / not applicable, default to false for backwards compatibility
Dev | AnvilHardhat | Morden | Ropsten | Rinkeby | Cronos | CronosTestnet | Kovan |
Sokol | Poa | XDai | Moonbeam | MoonbeamDev | Moonriver | Moonbase | Evmos |
EvmosTestnet | Chiado | Aurora | AuroraTestnet => false,
}
}
}
#[test]
fn test_default_chain() {
assert_eq!(serde_json::to_string(&Chain::Mainnet).unwrap(), "\"mainnet\"");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_chain() {
assert_eq!(serde_json::to_string(&Chain::default()).unwrap(), "\"mainnet\"");
}
}