use alloy_primitives::{Address, address};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schema", schemars(rename_all = "snake_case"))]
#[repr(u64)]
#[allow(missing_docs)]
#[non_exhaustive]
pub enum NamedChain {
%%enum_variants
}
impl NamedChain {
pub const COUNT: usize = %%chain_data_len;
pub const VARIANTS: &'static [Self] = &[
%%variants
];
pub const VARIANT_NAMES: &'static [&'static str] = &{
let mut names = [""; %%chain_data_len];
let mut index = 0;
while index < CHAIN_DATA.len() {
names[index] = CHAIN_DATA[index].name();
index += 1;
}
names
};
#[inline]
const fn from_index(index: ChainIndex) -> Self {
Self::VARIANTS[index as usize]
}
const fn index(self) -> ChainIndex {
match self {
%%chain_index_arms
}
}
#[inline]
const fn data(self) -> ChainData {
CHAIN_DATA[self.index() as usize]
}
#[inline]
const fn has_flag(self, flag: ChainFlags) -> bool {
self.data().flags & flag != 0
}
pub const fn from_chain_id(id: u64) -> Option<Self> {
match id {
%%chain_id_arms
_ => None,
}
}
#[inline]
pub const fn as_str(&self) -> &'static str {
self.data().name()
}
#[inline]
pub const fn is_ethereum(&self) -> bool {
%%ethereum_predicate
}
#[inline]
pub const fn is_optimism(self) -> bool {
%%optimism_predicate
}
#[inline]
pub const fn is_gnosis(self) -> bool {
%%gnosis_predicate
}
#[inline]
pub const fn is_polygon(self) -> bool {
%%polygon_predicate
}
#[inline]
pub const fn is_arbitrum(self) -> bool {
%%arbitrum_predicate
}
#[inline]
pub const fn is_elastic(self) -> bool {
%%elastic_predicate
}
#[inline]
pub const fn is_tempo(self) -> bool {
%%tempo_predicate
}
#[inline]
pub const fn is_custom_sourcify(self) -> bool {
%%custom_sourcify_predicate
}
#[inline]
pub const fn is_legacy(self) -> bool {
%%legacy_predicate
}
#[inline]
pub const fn supports_shanghai(self) -> bool {
%%shanghai_predicate
}
#[inline]
pub const fn is_testnet(self) -> bool {
%%testnet_predicate
}
#[inline]
pub const fn native_currency_symbol(self) -> Option<&'static str> {
self.data().native_currency_symbol()
}
#[inline]
pub const fn etherscan_urls(self) -> Option<(&'static str, &'static str)> {
let data = self.data();
match (data.etherscan_api_url(), data.etherscan_base_url()) {
(Some(api), Some(base)) => Some((api, base)),
_ => None,
}
}
#[inline]
pub const fn etherscan_api_key_name(self) -> Option<&'static str> {
self.data().etherscan_api_key_name()
}
#[inline]
pub const fn wrapped_native_token(self) -> Option<Address> {
let index = self.data().wrapped_native_token;
if index == NO_INDEX {
None
} else {
Some(WRAPPED_NATIVE_TOKENS[index as usize])
}
}
#[inline]
pub(crate) const fn average_blocktime_millis(self) -> u16 {
self.data().average_blocktime_millis
}
pub(crate) fn from_parse_str(value: &str) -> Option<Self> {
PARSE_NAMES.get(value).copied().map(Self::from_index)
}
#[cfg(feature = "serde")]
pub(crate) fn from_serde_str(value: &str) -> Option<Self> {
PARSE_NAMES
.get(value)
.or_else(|| SERDE_NAMES.get(value))
.copied()
.map(Self::from_index)
}
}
type ChainIndex = %%chain_index_type;
type ChainFlags = %%flag_type;
%%flag_consts
const NO_INDEX: u8 = u8::MAX;
#[derive(Clone, Copy)]
#[repr(C, packed)]
struct ChainData {
name: u8,
native_currency_symbol: u8,
etherscan_api_url: u8,
etherscan_base_url: u8,
etherscan_api_key_name: u8,
average_blocktime_millis: u16,
flags: ChainFlags,
wrapped_native_token: u8,
}
impl ChainData {
#[inline]
const fn name(self) -> &'static str {
CHAIN_NAMES[self.name as usize]
}
#[inline]
const fn native_currency_symbol(self) -> Option<&'static str> {
static_str(&NATIVE_CURRENCY_SYMBOLS, self.native_currency_symbol)
}
#[inline]
const fn etherscan_api_url(self) -> Option<&'static str> {
static_str(ÐERSCAN_API_URLS, self.etherscan_api_url)
}
#[inline]
const fn etherscan_base_url(self) -> Option<&'static str> {
static_str(ÐERSCAN_BASE_URLS, self.etherscan_base_url)
}
#[inline]
const fn etherscan_api_key_name(self) -> Option<&'static str> {
static_str(ÐERSCAN_API_KEY_NAMES, self.etherscan_api_key_name)
}
}
const fn static_str(table: &'static [&'static str], index: u8) -> Option<&'static str> {
if index == NO_INDEX { None } else { Some(table[index as usize]) }
}
#[cfg(test)]
pub(crate) const PARSE_ALIASES: &[(NamedChain, &str)] = &[
%%parse_aliases
];
#[cfg(all(test, feature = "serde"))]
pub(crate) const SERDE_ALIASES: &[(NamedChain, &str)] = &[
%%serde_aliases
];
%%string_table_data
static WRAPPED_NATIVE_TOKENS: [Address; %%wrapped_native_token_len] = [
%%wrapped_native_token_data
];
static CHAIN_DATA: [ChainData; %%chain_data_len] = {
use NO_INDEX as N;
use NO_INDEX as W;
%%flag_aliases
#[allow(clippy::too_many_arguments)]
const fn d(
name: u8,
native_currency_symbol: u8,
etherscan_api_url: u8,
etherscan_base_url: u8,
etherscan_api_key_name: u8,
average_blocktime_millis: u16,
flags: ChainFlags,
wrapped_native_token: u8,
) -> ChainData {
ChainData {
name,
native_currency_symbol,
etherscan_api_url,
etherscan_base_url,
etherscan_api_key_name,
average_blocktime_millis,
flags,
wrapped_native_token,
}
}
[
%%chain_data
]
};
%%phf_maps
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_index_is_not_used_as_index() {
assert_table_len(CHAIN_NAMES.len());
assert_table_len(NATIVE_CURRENCY_SYMBOLS.len());
assert_table_len(ETHERSCAN_API_URLS.len());
assert_table_len(ETHERSCAN_BASE_URLS.len());
assert_table_len(ETHERSCAN_API_KEY_NAMES.len());
assert_table_len(WRAPPED_NATIVE_TOKENS.len());
for data in CHAIN_DATA.iter().copied() {
assert_index(data.name, CHAIN_NAMES.len());
assert_optional_index(data.native_currency_symbol, NATIVE_CURRENCY_SYMBOLS.len());
assert_optional_index(data.etherscan_api_url, ETHERSCAN_API_URLS.len());
assert_optional_index(data.etherscan_base_url, ETHERSCAN_BASE_URLS.len());
assert_optional_index(data.etherscan_api_key_name, ETHERSCAN_API_KEY_NAMES.len());
assert_optional_index(data.wrapped_native_token, WRAPPED_NATIVE_TOKENS.len());
}
}
fn assert_table_len(len: usize) {
assert!(len <= NO_INDEX as usize);
}
fn assert_index(index: u8, len: usize) {
assert_ne!(index, NO_INDEX);
assert!((index as usize) < len);
}
fn assert_optional_index(index: u8, len: usize) {
if index != NO_INDEX {
assert!((index as usize) < len);
}
}
}