feat(core): chain macros and impls (#1958)
This commit is contained in:
parent
813600e6c9
commit
e007ea01b1
|
@ -1420,6 +1420,7 @@ dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"k256",
|
"k256",
|
||||||
|
"num_enum",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"open-fastrlp",
|
"open-fastrlp",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -2576,6 +2577,27 @@ dependencies = [
|
||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "num_threads"
|
name = "num_threads"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
|
|
@ -42,6 +42,7 @@ cargo_metadata = { version = "0.15.2", optional = true }
|
||||||
convert_case = { version = "0.6.0", optional = true }
|
convert_case = { version = "0.6.0", optional = true }
|
||||||
syn = { version = "1.0.105", optional = true }
|
syn = { version = "1.0.105", optional = true }
|
||||||
proc-macro2 = { version = "1.0.47", optional = true }
|
proc-macro2 = { version = "1.0.47", optional = true }
|
||||||
|
num_enum = "0.5.7"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = { version = "3.3.0", default-features = false }
|
tempfile = { version = "3.3.0", default-features = false }
|
||||||
|
|
|
@ -1,139 +1,161 @@
|
||||||
use super::U256;
|
use super::{U128, U256, U512, U64};
|
||||||
|
use num_enum::{TryFromPrimitive, TryFromPrimitiveError};
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use std::{
|
use std::{
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
fmt,
|
fmt,
|
||||||
str::FromStr,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use strum::EnumVariantNames;
|
use strum::{AsRefStr, EnumString, EnumVariantNames};
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Error)]
|
|
||||||
#[error("Failed to parse chain: {0}")]
|
|
||||||
pub struct ParseChainError(String);
|
|
||||||
|
|
||||||
// When adding a new chain:
|
// When adding a new chain:
|
||||||
// 1. add new variant to the Chain enum;
|
// 1. add new variant to the Chain enum;
|
||||||
// 2. update Display/FromStr impl;
|
// 2. add extra information in the last `impl` block (explorer URLs, block time) when applicable;
|
||||||
// 3. add etherscan_keys if supported.
|
// 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.
|
/// An Ethereum EIP-155 chain.
|
||||||
#[repr(u64)]
|
#[derive(
|
||||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, Deserialize, EnumVariantNames)]
|
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")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[strum(serialize_all = "kebab-case")]
|
#[strum(serialize_all = "kebab-case")]
|
||||||
|
#[repr(u64)]
|
||||||
pub enum Chain {
|
pub enum Chain {
|
||||||
#[default]
|
|
||||||
Mainnet = 1,
|
Mainnet = 1,
|
||||||
Morden = 2,
|
Morden = 2,
|
||||||
Ropsten = 3,
|
Ropsten = 3,
|
||||||
Rinkeby = 4,
|
Rinkeby = 4,
|
||||||
Goerli = 5,
|
Goerli = 5,
|
||||||
Optimism = 10,
|
|
||||||
Cronos = 25,
|
|
||||||
Rsk = 30,
|
|
||||||
Kovan = 42,
|
Kovan = 42,
|
||||||
#[strum(serialize = "bsc")]
|
Sepolia = 11155111,
|
||||||
BinanceSmartChain = 56,
|
|
||||||
|
Optimism = 10,
|
||||||
OptimismKovan = 69,
|
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,
|
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,
|
Arbitrum = 42161,
|
||||||
EmeraldTestnet = 42261,
|
|
||||||
Emerald = 42262,
|
|
||||||
AvalancheFuji = 43113,
|
|
||||||
Avalanche = 43114,
|
|
||||||
PolygonMumbai = 80001,
|
|
||||||
ArbitrumTestnet = 421611,
|
ArbitrumTestnet = 421611,
|
||||||
ArbitrumGoerli = 421613,
|
ArbitrumGoerli = 421613,
|
||||||
Sepolia = 11155111,
|
|
||||||
Aurora = 1313161554,
|
Cronos = 25,
|
||||||
AuroraTestnet = 1313161555,
|
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,
|
Celo = 42220,
|
||||||
CeloAlfajores = 44787,
|
CeloAlfajores = 44787,
|
||||||
CeloBaklava = 62320,
|
CeloBaklava = 62320,
|
||||||
|
|
||||||
|
Aurora = 1313161554,
|
||||||
|
AuroraTestnet = 1313161555,
|
||||||
}
|
}
|
||||||
|
|
||||||
// === impl Chain ===
|
// === impl Chain ===
|
||||||
|
|
||||||
impl fmt::Display for Chain {
|
// This must be implemented manually so we avoid a conflict with `TryFromPrimitive` where it treats
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
// the `#[default]` attribute as its own `#[num_enum(default)]`
|
||||||
let chain = match self {
|
impl Default for Chain {
|
||||||
Chain::Mainnet => "mainnet",
|
fn default() -> Self {
|
||||||
Chain::Morden => "morden",
|
Self::Mainnet
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Chain> for u32 {
|
macro_rules! impl_into_numeric {
|
||||||
|
($($ty:ty)+) => {$(
|
||||||
|
impl From<Chain> for $ty {
|
||||||
fn from(chain: Chain) -> Self {
|
fn from(chain: Chain) -> Self {
|
||||||
chain as u32
|
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 {
|
impl From<Chain> for u64 {
|
||||||
fn from(chain: Chain) -> Self {
|
fn from(chain: Chain) -> Self {
|
||||||
|
@ -141,134 +163,21 @@ impl From<Chain> for u64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Chain> for U256 {
|
impl_into_numeric!(u128 U64 U128 U256 U512);
|
||||||
fn from(chain: Chain) -> Self {
|
|
||||||
u64::from(chain).into()
|
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 {
|
impl_try_from_numeric!(u8 u16 u32 usize; U128 U256 U512);
|
||||||
type Error = ParseChainError;
|
|
||||||
|
|
||||||
fn try_from(chain: u32) -> Result<Chain, Self::Error> {
|
impl fmt::Display for Chain {
|
||||||
(chain as u64).try_into()
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
}
|
f.pad(self.as_ref())
|
||||||
}
|
|
||||||
|
|
||||||
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())),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,163 +186,135 @@ impl Serialize for Chain {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
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 {
|
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
|
/// It can be beneficial to know the average blocktime to adjust the polling of an HTTP provider
|
||||||
/// for example.
|
/// for example.
|
||||||
///
|
///
|
||||||
/// **Note:** this will not return the accurate average depending on the time but is rather a
|
/// **Note:** this is not an accurate average, but is rather a sensible default derived from
|
||||||
/// sensible default derived from blocktime charts like <https://etherscan.com/chart/blocktime>
|
/// blocktime charts such as [Etherscan's](https://etherscan.com/chart/blocktime)
|
||||||
/// <https://polygonscan.com/chart/blocktime>
|
/// or [Polygonscan's](https://polygonscan.com/chart/blocktime).
|
||||||
pub fn average_blocktime_hint(&self) -> Option<Duration> {
|
pub const fn average_blocktime_hint(&self) -> Option<Duration> {
|
||||||
|
use Chain::*;
|
||||||
|
|
||||||
let ms = match self {
|
let ms = match self {
|
||||||
Chain::Arbitrum | Chain::ArbitrumTestnet | Chain::ArbitrumGoerli => 1_300,
|
Arbitrum | ArbitrumTestnet | ArbitrumGoerli => 1_300,
|
||||||
Chain::Mainnet | Chain::Optimism => 13_000,
|
Mainnet | Optimism => 13_000,
|
||||||
Chain::Polygon | Chain::PolygonMumbai => 2_100,
|
Polygon | PolygonMumbai => 2_100,
|
||||||
Chain::Moonbeam | Chain::Moonriver => 12_500,
|
Moonbeam | Moonriver => 12_500,
|
||||||
Chain::BinanceSmartChain | Chain::BinanceSmartChainTestnet => 3_000,
|
BinanceSmartChain | BinanceSmartChainTestnet => 3_000,
|
||||||
Chain::Avalanche | Chain::AvalancheFuji => 2_000,
|
Avalanche | AvalancheFuji => 2_000,
|
||||||
Chain::Fantom | Chain::FantomTestnet => 1_200,
|
Fantom | FantomTestnet => 1_200,
|
||||||
Chain::Cronos | Chain::CronosTestnet => 5_700,
|
Cronos | CronosTestnet => 5_700,
|
||||||
Chain::Evmos | Chain::EvmosTestnet => 1_900,
|
Evmos | EvmosTestnet => 1_900,
|
||||||
Chain::Aurora | Chain::AuroraTestnet => 1_100,
|
Aurora | AuroraTestnet => 1_100,
|
||||||
Chain::Oasis => 5_500,
|
Oasis => 5_500,
|
||||||
Chain::Emerald => 6_000,
|
Emerald => 6_000,
|
||||||
Chain::Dev | Chain::AnvilHardhat => 200,
|
Dev | AnvilHardhat => 200,
|
||||||
Chain::Celo | Chain::CeloAlfajores | Chain::CeloBaklava => 5_000,
|
Celo | CeloAlfajores | CeloBaklava => 5_000,
|
||||||
// Explictly handle all network to make it easier not to forget this match when new
|
// Explictly handle all network to make it easier not to forget this match when new
|
||||||
// networks are added.
|
// networks are added.
|
||||||
Chain::Morden |
|
Morden | Ropsten | Rinkeby | Goerli | Kovan | XDai | Chiado | Sepolia | Moonbase |
|
||||||
Chain::Ropsten |
|
MoonbeamDev | OptimismGoerli | OptimismKovan | Poa | Sokol | Rsk | EmeraldTestnet => {
|
||||||
Chain::Rinkeby |
|
return None
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Duration::from_millis(ms))
|
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")`
|
/// 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 {
|
let urls = match self {
|
||||||
Chain::Mainnet => ("https://api.etherscan.io/api", "https://etherscan.io"),
|
Mainnet => ("https://api.etherscan.io/api", "https://etherscan.io"),
|
||||||
Chain::Ropsten => {
|
Ropsten => ("https://api-ropsten.etherscan.io/api", "https://ropsten.etherscan.io"),
|
||||||
("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"),
|
||||||
Chain::Kovan => ("https://api-kovan.etherscan.io/api", "https://kovan.etherscan.io"),
|
Goerli => ("https://api-goerli.etherscan.io/api", "https://goerli.etherscan.io"),
|
||||||
Chain::Rinkeby => {
|
Sepolia => ("https://api-sepolia.etherscan.io/api", "https://sepolia.etherscan.io"),
|
||||||
("https://api-rinkeby.etherscan.io/api", "https://rinkeby.etherscan.io")
|
Polygon => ("https://api.polygonscan.com/api", "https://polygonscan.com"),
|
||||||
}
|
PolygonMumbai => {
|
||||||
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")
|
("https://api-testnet.polygonscan.com/api", "https://mumbai.polygonscan.com")
|
||||||
}
|
}
|
||||||
Chain::Avalanche => ("https://api.snowtrace.io/api", "https://snowtrace.io"),
|
Avalanche => ("https://api.snowtrace.io/api", "https://snowtrace.io"),
|
||||||
Chain::AvalancheFuji => {
|
AvalancheFuji => {
|
||||||
("https://api-testnet.snowtrace.io/api", "https://testnet.snowtrace.io")
|
("https://api-testnet.snowtrace.io/api", "https://testnet.snowtrace.io")
|
||||||
}
|
}
|
||||||
Chain::Optimism => {
|
Optimism => {
|
||||||
("https://api-optimistic.etherscan.io/api", "https://optimistic.etherscan.io")
|
("https://api-optimistic.etherscan.io/api", "https://optimistic.etherscan.io")
|
||||||
}
|
}
|
||||||
Chain::OptimismGoerli => (
|
OptimismGoerli => (
|
||||||
"https://api-goerli-optimistic.etherscan.io/api",
|
"https://api-goerli-optimistic.etherscan.io/api",
|
||||||
"https://goerli-optimism.etherscan.io",
|
"https://goerli-optimism.etherscan.io",
|
||||||
),
|
),
|
||||||
Chain::OptimismKovan => (
|
OptimismKovan => (
|
||||||
"https://api-kovan-optimistic.etherscan.io/api",
|
"https://api-kovan-optimistic.etherscan.io/api",
|
||||||
"https://kovan-optimistic.etherscan.io",
|
"https://kovan-optimistic.etherscan.io",
|
||||||
),
|
),
|
||||||
Chain::Fantom => ("https://api.ftmscan.com/api", "https://ftmscan.com"),
|
Fantom => ("https://api.ftmscan.com/api", "https://ftmscan.com"),
|
||||||
Chain::FantomTestnet => {
|
FantomTestnet => ("https://api-testnet.ftmscan.com/api", "https://testnet.ftmscan.com"),
|
||||||
("https://api-testnet.ftmscan.com/api", "https://testnet.ftmscan.com")
|
BinanceSmartChain => ("https://api.bscscan.com/api", "https://bscscan.com"),
|
||||||
}
|
BinanceSmartChainTestnet => {
|
||||||
Chain::BinanceSmartChain => ("https://api.bscscan.com/api", "https://bscscan.com"),
|
|
||||||
Chain::BinanceSmartChainTestnet => {
|
|
||||||
("https://api-testnet.bscscan.com/api", "https://testnet.bscscan.com")
|
("https://api-testnet.bscscan.com/api", "https://testnet.bscscan.com")
|
||||||
}
|
}
|
||||||
Chain::Arbitrum => ("https://api.arbiscan.io/api", "https://arbiscan.io"),
|
Arbitrum => ("https://api.arbiscan.io/api", "https://arbiscan.io"),
|
||||||
Chain::ArbitrumTestnet => {
|
ArbitrumTestnet => {
|
||||||
("https://api-testnet.arbiscan.io/api", "https://testnet.arbiscan.io")
|
("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/api",
|
||||||
"https://goerli-rollup-explorer.arbitrum.io",
|
"https://goerli-rollup-explorer.arbitrum.io",
|
||||||
),
|
),
|
||||||
Chain::Cronos => ("https://api.cronoscan.com/api", "https://cronoscan.com"),
|
Cronos => ("https://api.cronoscan.com/api", "https://cronoscan.com"),
|
||||||
Chain::CronosTestnet => {
|
CronosTestnet => {
|
||||||
("https://api-testnet.cronoscan.com/api", "https://testnet.cronoscan.com")
|
("https://api-testnet.cronoscan.com/api", "https://testnet.cronoscan.com")
|
||||||
}
|
}
|
||||||
Chain::Moonbeam => {
|
Moonbeam => ("https://api-moonbeam.moonscan.io/api", "https://moonbeam.moonscan.io/"),
|
||||||
("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"),
|
||||||
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
|
// blockscout API is etherscan compatible
|
||||||
Chain::XDai => {
|
XDai => {
|
||||||
("https://blockscout.com/xdai/mainnet/api", "https://blockscout.com/xdai/mainnet")
|
("https://blockscout.com/xdai/mainnet/api", "https://blockscout.com/xdai/mainnet")
|
||||||
}
|
}
|
||||||
Chain::Chiado => {
|
Chiado => {
|
||||||
("https://blockscout.chiadochain.net/api", "https://blockscout.chiadochain.net")
|
("https://blockscout.chiadochain.net/api", "https://blockscout.chiadochain.net")
|
||||||
}
|
}
|
||||||
Chain::Sokol => {
|
Sokol => ("https://blockscout.com/poa/sokol/api", "https://blockscout.com/poa/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"),
|
||||||
Chain::Poa => {
|
Oasis => ("https://scan.oasischain.io/api", "https://scan.oasischain.io/"),
|
||||||
("https://blockscout.com/poa/core/api", "https://blockscout.com/poa/core")
|
Emerald => {
|
||||||
}
|
|
||||||
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/")
|
("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/api",
|
||||||
"https://testnet.explorer.emerald.oasis.dev/",
|
"https://testnet.explorer.emerald.oasis.dev/",
|
||||||
),
|
),
|
||||||
Chain::Aurora => ("https://api.aurorascan.dev/api", "https://aurorascan.dev"),
|
Aurora => ("https://api.aurorascan.dev/api", "https://aurorascan.dev"),
|
||||||
Chain::AuroraTestnet => {
|
AuroraTestnet => {
|
||||||
("https://testnet.aurorascan.dev/api", "https://testnet.aurorascan.dev")
|
("https://testnet.aurorascan.dev/api", "https://testnet.aurorascan.dev")
|
||||||
}
|
}
|
||||||
Chain::Evmos => ("https://evm.evmos.org/api", "https://evm.evmos.org/"),
|
Evmos => ("https://evm.evmos.org/api", "https://evm.evmos.org/"),
|
||||||
Chain::EvmosTestnet => ("https://evm.evmos.dev/api", "https://evm.evmos.dev/"),
|
EvmosTestnet => ("https://evm.evmos.dev/api", "https://evm.evmos.dev/"),
|
||||||
Chain::Celo => {
|
Celo => ("https://explorer.celo.org/mainnet", "https://explorer.celo.org/mainnet/api"),
|
||||||
("https://explorer.celo.org/mainnet", "https://explorer.celo.org/mainnet/api")
|
CeloAlfajores => {
|
||||||
}
|
|
||||||
Chain::CeloAlfajores => {
|
|
||||||
("https://explorer.celo.org/alfajores", "https://explorer.celo.org/alfajores/api")
|
("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")
|
("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
|
// this is explicitly exhaustive so we don't forget to add new urls when adding a
|
||||||
// new chain
|
// new chain
|
||||||
return None
|
return None
|
||||||
|
@ -443,34 +324,49 @@ impl Chain {
|
||||||
Some(urls)
|
Some(urls)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for checking if a chainid corresponds to a legacy chainid
|
/// Returns whether the chain implements EIP-1559 (with the type 2 EIP-2718 transaction type).
|
||||||
/// without eip1559
|
pub const fn is_legacy(&self) -> bool {
|
||||||
pub fn is_legacy(&self) -> bool {
|
use Chain::*;
|
||||||
// TODO: Add other chains which do not support EIP1559.
|
|
||||||
matches!(
|
match self {
|
||||||
self,
|
// Known legacy chains / non EIP-1559 compliant
|
||||||
Chain::Optimism |
|
Optimism |
|
||||||
Chain::OptimismGoerli |
|
OptimismGoerli |
|
||||||
Chain::OptimismKovan |
|
OptimismKovan |
|
||||||
Chain::Fantom |
|
Fantom |
|
||||||
Chain::FantomTestnet |
|
FantomTestnet |
|
||||||
Chain::BinanceSmartChain |
|
BinanceSmartChain |
|
||||||
Chain::BinanceSmartChainTestnet |
|
BinanceSmartChainTestnet |
|
||||||
Chain::Arbitrum |
|
Arbitrum |
|
||||||
Chain::ArbitrumTestnet |
|
ArbitrumTestnet |
|
||||||
Chain::ArbitrumGoerli |
|
ArbitrumGoerli |
|
||||||
Chain::Rsk |
|
Rsk |
|
||||||
Chain::Oasis |
|
Oasis |
|
||||||
Chain::Emerald |
|
Emerald |
|
||||||
Chain::EmeraldTestnet |
|
EmeraldTestnet |
|
||||||
Chain::Celo |
|
Celo |
|
||||||
Chain::CeloAlfajores |
|
CeloAlfajores |
|
||||||
Chain::CeloBaklava,
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_chain() {
|
fn test_default_chain() {
|
||||||
assert_eq!(serde_json::to_string(&Chain::Mainnet).unwrap(), "\"mainnet\"");
|
assert_eq!(serde_json::to_string(&Chain::default()).unwrap(), "\"mainnet\"");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue