alloy_chains/
named.rs

1use alloy_primitives::{address, Address};
2use core::{cmp::Ordering, fmt, time::Duration};
3use num_enum::TryFromPrimitiveError;
4
5#[allow(unused_imports)]
6use alloc::string::String;
7// When adding a new chain:
8//   1. add new variant to the NamedChain enum;
9//   2. add extra information in the last `impl` block (explorer URLs, block time) when applicable;
10//   3. (optional) add aliases:
11//     - Strum (in kebab-case): `#[strum(to_string = "<main>", serialize = "<aliasX>", ...)]`
12//      `to_string = "<main>"` must be present and will be used in `Display`, `Serialize`
13//      and `FromStr`, while `serialize = "<aliasX>"` will be appended to `FromStr`.
14//      More info: <https://docs.rs/strum/latest/strum/additional_attributes/index.html#attributes-on-variants>
15//     - Serde (in snake_case): `#[cfg_attr(feature = "serde", serde(alias = "<aliasX>", ...))]`
16//      Aliases are appended to the `Deserialize` implementation.
17//      More info: <https://serde.rs/variant-attrs.html>
18//     - Add a test at the bottom of the file
19//   4. run `cargo test --all-features` to update the JSON bindings and schema.
20
21// We don't derive Serialize because it is manually implemented using AsRef<str> and it would break
22// a lot of things since Serialize is `kebab-case` vs Deserialize `snake_case`. This means that the
23// NamedChain type is not "round-trippable", because the Serialize and Deserialize implementations
24// do not use the same case style.
25
26/// An Ethereum EIP-155 chain.
27#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
28#[derive(strum::IntoStaticStr)] // Into<&'static str>, AsRef<str>, fmt::Display and serde::Serialize
29#[derive(strum::VariantNames)] // NamedChain::VARIANTS
30#[derive(strum::VariantArray)] // NamedChain::VARIANTS
31#[derive(strum::EnumString)] // FromStr, TryFrom<&str>
32#[derive(strum::EnumIter)] // NamedChain::iter
33#[derive(strum::EnumCount)] // NamedChain::COUNT
34#[derive(num_enum::TryFromPrimitive)] // TryFrom<u64>
35#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
36#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
37#[strum(serialize_all = "kebab-case")]
38#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
39#[repr(u64)]
40#[allow(missing_docs)]
41#[non_exhaustive]
42pub enum NamedChain {
43    #[strum(to_string = "mainnet", serialize = "ethlive")]
44    #[cfg_attr(feature = "serde", serde(alias = "ethlive"))]
45    Mainnet = 1,
46    Morden = 2,
47    Ropsten = 3,
48    Rinkeby = 4,
49    Goerli = 5,
50    Kovan = 42,
51    Holesky = 17000,
52    Sepolia = 11155111,
53
54    #[cfg_attr(feature = "serde", serde(alias = "odyssey"))]
55    Odyssey = 911867,
56
57    Optimism = 10,
58    #[cfg_attr(feature = "serde", serde(alias = "optimism-kovan"))]
59    OptimismKovan = 69,
60    #[cfg_attr(feature = "serde", serde(alias = "optimism-goerli"))]
61    OptimismGoerli = 420,
62    #[cfg_attr(feature = "serde", serde(alias = "optimism-sepolia"))]
63    OptimismSepolia = 11155420,
64
65    #[strum(to_string = "bob")]
66    #[cfg_attr(feature = "serde", serde(alias = "bob"))]
67    Bob = 60808,
68    #[strum(to_string = "bob-sepolia")]
69    #[cfg_attr(feature = "serde", serde(alias = "bob-sepolia"))]
70    BobSepolia = 808813,
71
72    #[cfg_attr(feature = "serde", serde(alias = "arbitrum_one", alias = "arbitrum-one"))]
73    Arbitrum = 42161,
74    ArbitrumTestnet = 421611,
75    #[cfg_attr(feature = "serde", serde(alias = "arbitrum-goerli"))]
76    ArbitrumGoerli = 421613,
77    #[cfg_attr(feature = "serde", serde(alias = "arbitrum-sepolia"))]
78    ArbitrumSepolia = 421614,
79    #[cfg_attr(feature = "serde", serde(alias = "arbitrum-nova"))]
80    ArbitrumNova = 42170,
81
82    Cronos = 25,
83    CronosTestnet = 338,
84
85    Rsk = 30,
86
87    #[strum(to_string = "telos")]
88    #[cfg_attr(feature = "serde", serde(alias = "telos", alias = "telos_evm"))]
89    TelosEvm = 40,
90    #[strum(to_string = "telos-testnet")]
91    #[cfg_attr(
92        feature = "serde",
93        serde(alias = "telos_testnet", alias = "telos-evm-testnet", alias = "telos_evm_testnet")
94    )]
95    TelosEvmTestnet = 41,
96
97    #[strum(to_string = "crab")]
98    #[cfg_attr(feature = "serde", serde(alias = "crab"))]
99    Crab = 44,
100    #[strum(to_string = "darwinia")]
101    #[cfg_attr(feature = "serde", serde(alias = "darwinia"))]
102    Darwinia = 46,
103    #[strum(to_string = "koi")]
104    #[cfg_attr(feature = "serde", serde(alias = "koi"))]
105    Koi = 701,
106
107    /// Note the correct name for BSC should be `BNB Smart Chain` due to the rebranding: <https://www.bnbchain.org/en/blog/bsc-is-now-bnb-chain-the-infrastructure-for-the-metafi-universe>
108    /// We keep `Binance Smart Chain` for backward compatibility, and the enum could be renamed in
109    /// the future release.
110    #[strum(to_string = "bsc", serialize = "binance-smart-chain", serialize = "bnb-smart-chain")]
111    #[cfg_attr(
112        feature = "serde",
113        serde(alias = "bsc", alias = "bnb-smart-chain", alias = "binance-smart-chain")
114    )]
115    BinanceSmartChain = 56,
116    #[strum(
117        to_string = "bsc-testnet",
118        serialize = "binance-smart-chain-testnet",
119        serialize = "bnb-smart-chain-testnet"
120    )]
121    #[cfg_attr(
122        feature = "serde",
123        serde(
124            alias = "bsc_testnet",
125            alias = "bsc-testnet",
126            alias = "bnb-smart-chain-testnet",
127            alias = "binance-smart-chain-testnet"
128        )
129    )]
130    BinanceSmartChainTestnet = 97,
131
132    Poa = 99,
133    Sokol = 77,
134
135    Scroll = 534352,
136    #[cfg_attr(
137        feature = "serde",
138        serde(alias = "scroll_sepolia_testnet", alias = "scroll-sepolia")
139    )]
140    ScrollSepolia = 534351,
141
142    Metis = 1088,
143
144    #[cfg_attr(feature = "serde", serde(alias = "conflux-espace-testnet"))]
145    CfxTestnet = 71,
146    #[cfg_attr(feature = "serde", serde(alias = "conflux-espace"))]
147    Cfx = 1030,
148
149    #[strum(to_string = "xdai", serialize = "gnosis", serialize = "gnosis-chain")]
150    #[cfg_attr(feature = "serde", serde(alias = "xdai", alias = "gnosis", alias = "gnosis-chain"))]
151    Gnosis = 100,
152
153    Polygon = 137,
154    #[strum(to_string = "mumbai", serialize = "polygon-mumbai")]
155    #[cfg_attr(feature = "serde", serde(alias = "mumbai", alias = "polygon-mumbai"))]
156    PolygonMumbai = 80001,
157    #[strum(to_string = "amoy", serialize = "polygon-amoy")]
158    #[cfg_attr(feature = "serde", serde(alias = "amoy", alias = "polygon-amoy"))]
159    PolygonAmoy = 80002,
160    #[strum(serialize = "polygon-zkevm", serialize = "zkevm")]
161    #[cfg_attr(
162        feature = "serde",
163        serde(alias = "zkevm", alias = "polygon_zkevm", alias = "polygon-zkevm")
164    )]
165    PolygonZkEvm = 1101,
166    #[strum(serialize = "polygon-zkevm-testnet", serialize = "zkevm-testnet")]
167    #[cfg_attr(
168        feature = "serde",
169        serde(
170            alias = "zkevm-testnet",
171            alias = "polygon_zkevm_testnet",
172            alias = "polygon-zkevm-testnet"
173        )
174    )]
175    PolygonZkEvmTestnet = 1442,
176
177    Fantom = 250,
178    FantomTestnet = 4002,
179
180    Moonbeam = 1284,
181    MoonbeamDev = 1281,
182
183    Moonriver = 1285,
184
185    Moonbase = 1287,
186
187    Dev = 1337,
188    #[strum(to_string = "anvil-hardhat", serialize = "anvil", serialize = "hardhat")]
189    #[cfg_attr(
190        feature = "serde",
191        serde(alias = "anvil", alias = "hardhat", alias = "anvil-hardhat")
192    )]
193    AnvilHardhat = 31337,
194
195    #[strum(to_string = "gravity-alpha-mainnet")]
196    #[cfg_attr(feature = "serde", serde(alias = "gravity-alpha-mainnet"))]
197    GravityAlphaMainnet = 1625,
198    #[strum(to_string = "gravity-alpha-testnet-sepolia")]
199    #[cfg_attr(feature = "serde", serde(alias = "gravity-alpha-testnet-sepolia"))]
200    GravityAlphaTestnetSepolia = 13505,
201
202    Evmos = 9001,
203    EvmosTestnet = 9000,
204
205    Chiado = 10200,
206
207    Oasis = 26863,
208
209    Emerald = 42262,
210    EmeraldTestnet = 42261,
211
212    FilecoinMainnet = 314,
213    FilecoinCalibrationTestnet = 314159,
214
215    Avalanche = 43114,
216    #[strum(to_string = "fuji", serialize = "avalanche-fuji")]
217    #[cfg_attr(feature = "serde", serde(alias = "fuji"))]
218    AvalancheFuji = 43113,
219
220    Celo = 42220,
221    CeloAlfajores = 44787,
222    CeloBaklava = 62320,
223
224    Aurora = 1313161554,
225    AuroraTestnet = 1313161555,
226
227    Canto = 7700,
228    CantoTestnet = 740,
229
230    Boba = 288,
231
232    Base = 8453,
233    #[cfg_attr(feature = "serde", serde(alias = "base-goerli"))]
234    BaseGoerli = 84531,
235    #[cfg_attr(feature = "serde", serde(alias = "base-sepolia"))]
236    BaseSepolia = 84532,
237    #[cfg_attr(feature = "serde", serde(alias = "syndr"))]
238    Syndr = 404,
239    #[cfg_attr(feature = "serde", serde(alias = "syndr-sepolia"))]
240    SyndrSepolia = 444444,
241
242    Shimmer = 148,
243
244    Ink = 57073,
245    #[cfg_attr(feature = "serde", serde(alias = "ink_sepolia_testnet", alias = "ink-sepolia"))]
246    InkSepolia = 763373,
247
248    #[strum(to_string = "fraxtal")]
249    #[cfg_attr(feature = "serde", serde(alias = "fraxtal"))]
250    Fraxtal = 252,
251    #[strum(to_string = "fraxtal-testnet")]
252    #[cfg_attr(feature = "serde", serde(alias = "fraxtal-testnet"))]
253    FraxtalTestnet = 2522,
254
255    Blast = 81457,
256    #[cfg_attr(feature = "serde", serde(alias = "blast-sepolia"))]
257    BlastSepolia = 168587773,
258
259    Linea = 59144,
260    #[cfg_attr(feature = "serde", serde(alias = "linea-goerli"))]
261    LineaGoerli = 59140,
262    #[cfg_attr(feature = "serde", serde(alias = "linea-sepolia"))]
263    LineaSepolia = 59141,
264
265    #[strum(to_string = "zksync")]
266    #[cfg_attr(feature = "serde", serde(alias = "zksync"))]
267    ZkSync = 324,
268    #[strum(to_string = "zksync-testnet")]
269    #[cfg_attr(feature = "serde", serde(alias = "zksync_testnet", alias = "zksync-testnet"))]
270    ZkSyncTestnet = 300,
271
272    #[strum(to_string = "mantle")]
273    #[cfg_attr(feature = "serde", serde(alias = "mantle"))]
274    Mantle = 5000,
275    #[strum(to_string = "mantle-testnet")]
276    #[cfg_attr(feature = "serde", serde(alias = "mantle-testnet"))]
277    MantleTestnet = 5001,
278    #[strum(to_string = "mantle-sepolia")]
279    #[cfg_attr(feature = "serde", serde(alias = "mantle-sepolia"))]
280    MantleSepolia = 5003,
281
282    #[strum(to_string = "xai")]
283    #[cfg_attr(feature = "serde", serde(alias = "xai"))]
284    Xai = 660279,
285    #[strum(to_string = "xai-sepolia")]
286    #[cfg_attr(feature = "serde", serde(alias = "xai-sepolia"))]
287    XaiSepolia = 37714555429,
288
289    #[strum(to_string = "happychain-testnet")]
290    #[cfg_attr(feature = "serde", serde(alias = "happychain-testnet"))]
291    HappychainTestnet = 216,
292
293    Viction = 88,
294
295    Zora = 7777777,
296    #[cfg_attr(feature = "serde", serde(alias = "zora-sepolia"))]
297    ZoraSepolia = 999999999,
298
299    Pgn = 424,
300    #[cfg_attr(feature = "serde", serde(alias = "pgn-sepolia"))]
301    PgnSepolia = 58008,
302
303    Mode = 34443,
304    #[cfg_attr(feature = "serde", serde(alias = "mode-sepolia"))]
305    ModeSepolia = 919,
306
307    Elastos = 20,
308
309    #[cfg_attr(
310        feature = "serde",
311        serde(alias = "kakarot-sepolia", alias = "kakarot-starknet-sepolia")
312    )]
313    KakarotSepolia = 920637907288165,
314
315    #[cfg_attr(feature = "serde", serde(alias = "etherlink"))]
316    Etherlink = 42793,
317
318    #[cfg_attr(feature = "serde", serde(alias = "etherlink-testnet"))]
319    EtherlinkTestnet = 128123,
320
321    Degen = 666666666,
322
323    #[strum(to_string = "opbnb-mainnet")]
324    #[cfg_attr(
325        feature = "serde",
326        serde(rename = "opbnb_mainnet", alias = "opbnb-mainnet", alias = "op-bnb-mainnet")
327    )]
328    OpBNBMainnet = 204,
329    #[strum(to_string = "opbnb-testnet")]
330    #[cfg_attr(
331        feature = "serde",
332        serde(rename = "opbnb_testnet", alias = "opbnb-testnet", alias = "op-bnb-testnet")
333    )]
334    OpBNBTestnet = 5611,
335
336    Ronin = 2020,
337
338    #[cfg_attr(feature = "serde", serde(alias = "ronin-testnet"))]
339    RoninTestnet = 2021,
340
341    Taiko = 167000,
342    #[cfg_attr(feature = "serde", serde(alias = "taiko-hekla"))]
343    TaikoHekla = 167009,
344
345    #[strum(to_string = "autonomys-nova-testnet")]
346    #[cfg_attr(
347        feature = "serde",
348        serde(rename = "autonomys_nova_testnet", alias = "autonomys-nova-testnet")
349    )]
350    AutonomysNovaTestnet = 490000,
351
352    Flare = 14,
353    #[cfg_attr(feature = "serde", serde(alias = "flare-coston2"))]
354    FlareCoston2 = 114,
355
356    #[strum(to_string = "acala")]
357    #[cfg_attr(feature = "serde", serde(alias = "acala"))]
358    Acala = 787,
359    #[strum(to_string = "acala-mandala-testnet")]
360    #[cfg_attr(feature = "serde", serde(alias = "acala-mandala-testnet"))]
361    AcalaMandalaTestnet = 595,
362    #[strum(to_string = "acala-testnet")]
363    #[cfg_attr(feature = "serde", serde(alias = "acala-testnet"))]
364    AcalaTestnet = 597,
365
366    #[strum(to_string = "karura")]
367    #[cfg_attr(feature = "serde", serde(alias = "karura"))]
368    Karura = 686,
369    #[strum(to_string = "karura-testnet")]
370    #[cfg_attr(feature = "serde", serde(alias = "karura-testnet"))]
371    KaruraTestnet = 596,
372    #[strum(to_string = "pulsechain")]
373    #[cfg_attr(feature = "serde", serde(alias = "pulsechain"))]
374    Pulsechain = 369,
375    #[strum(to_string = "pulsechain-testnet")]
376    #[cfg_attr(feature = "serde", serde(alias = "pulsechain-testnet"))]
377    PulsechainTestnet = 943,
378
379    #[strum(to_string = "immutable")]
380    #[cfg_attr(feature = "serde", serde(alias = "immutable"))]
381    Immutable = 13371,
382    #[strum(to_string = "immutable-testnet")]
383    #[cfg_attr(feature = "serde", serde(alias = "immutable-testnet"))]
384    ImmutableTestnet = 13473,
385
386    #[strum(to_string = "soneium")]
387    #[cfg_attr(feature = "serde", serde(alias = "soneium"))]
388    Soneium = 1868,
389
390    #[strum(to_string = "soneium-minato-testnet")]
391    #[cfg_attr(feature = "serde", serde(alias = "soneium-minato-testnet"))]
392    SoneiumMinatoTestnet = 1946,
393
394    #[cfg_attr(feature = "serde", serde(alias = "worldchain"))]
395    World = 480,
396    #[strum(to_string = "world-sepolia")]
397    #[cfg_attr(feature = "serde", serde(alias = "worldchain-sepolia", alias = "world-sepolia"))]
398    WorldSepolia = 4801,
399    Iotex = 4689,
400    Core = 1116,
401    Merlin = 4200,
402    Bitlayer = 200901,
403    Vana = 1480,
404    Zeta = 7000,
405    Kaia = 8217,
406    Story = 1514,
407
408    Unichain = 130,
409    #[strum(to_string = "unichain-sepolia")]
410    #[cfg_attr(feature = "serde", serde(alias = "unichain-sepolia"))]
411    UnichainSepolia = 1301,
412
413    #[strum(to_string = "apechain")]
414    #[cfg_attr(feature = "serde", serde(alias = "apechain"))]
415    ApeChain = 33139,
416    #[strum(to_string = "curtis", serialize = "apechain-testnet")]
417    #[cfg_attr(feature = "serde", serde(alias = "apechain-testnet", alias = "curtis"))]
418    Curtis = 33111,
419
420    #[strum(to_string = "sonic-testnet")]
421    #[cfg_attr(feature = "serde", serde(alias = "sonic-testnet"))]
422    SonicTestnet = 64165,
423    #[strum(to_string = "sonic")]
424    #[cfg_attr(feature = "serde", serde(alias = "sonic"))]
425    Sonic = 146,
426
427    #[strum(to_string = "treasure")]
428    #[cfg_attr(feature = "serde", serde(alias = "treasure"))]
429    Treasure = 61166,
430
431    #[strum(to_string = "treasure-topaz", serialize = "treasure-topaz-testnet")]
432    #[cfg_attr(
433        feature = "serde",
434        serde(alias = "treasure-topaz-testnet", alias = "treasure-topaz")
435    )]
436    TreasureTopaz = 978658,
437
438    #[strum(to_string = "berachain-bartio", serialize = "berachain-bartio-testnet")]
439    #[cfg_attr(
440        feature = "serde",
441        serde(alias = "berachain-bartio-testnet", alias = "berachain-bartio")
442    )]
443    BerachainBartio = 80084,
444
445    #[strum(to_string = "berachain-artio", serialize = "berachain-artio-testnet")]
446    #[cfg_attr(
447        feature = "serde",
448        serde(alias = "berachain-artio-testnet", alias = "berachain-artio")
449    )]
450    BerachainArtio = 80085,
451
452    Berachain = 80094,
453
454    #[strum(to_string = "superposition-testnet")]
455    #[cfg_attr(feature = "serde", serde(alias = "superposition-testnet"))]
456    SuperpositionTestnet = 98985,
457
458    #[strum(to_string = "superposition")]
459    #[cfg_attr(feature = "serde", serde(alias = "superposition"))]
460    Superposition = 55244,
461
462    #[strum(serialize = "monad-testnet")]
463    #[cfg_attr(feature = "serde", serde(alias = "monad-testnet"))]
464    MonadTestnet = 10143,
465
466    #[strum(to_string = "hyperliquid")]
467    #[cfg_attr(feature = "serde", serde(alias = "hyperliquid"))]
468    Hyperliquid = 999,
469}
470
471// This must be implemented manually so we avoid a conflict with `TryFromPrimitive` where it treats
472// the `#[default]` attribute as its own `#[num_enum(default)]`
473impl Default for NamedChain {
474    #[inline]
475    fn default() -> Self {
476        Self::Mainnet
477    }
478}
479
480macro_rules! impl_into_numeric {
481    ($($t:ty)+) => {$(
482        impl From<NamedChain> for $t {
483            #[inline]
484            fn from(chain: NamedChain) -> Self {
485                chain as $t
486            }
487        }
488    )+};
489}
490
491impl_into_numeric!(u64 i64 u128 i128);
492#[cfg(target_pointer_width = "64")]
493impl_into_numeric!(usize isize);
494
495macro_rules! impl_try_from_numeric {
496    ($($native:ty)+) => {
497        $(
498            impl TryFrom<$native> for NamedChain {
499                type Error = TryFromPrimitiveError<NamedChain>;
500
501                #[inline]
502                fn try_from(value: $native) -> Result<Self, Self::Error> {
503                    (value as u64).try_into()
504                }
505            }
506        )+
507    };
508}
509
510impl_try_from_numeric!(u8 i8 u16 i16 u32 i32 usize isize);
511
512impl fmt::Display for NamedChain {
513    #[inline]
514    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
515        self.as_str().fmt(f)
516    }
517}
518
519impl AsRef<str> for NamedChain {
520    #[inline]
521    fn as_ref(&self) -> &str {
522        self.as_str()
523    }
524}
525
526impl PartialEq<u64> for NamedChain {
527    #[inline]
528    fn eq(&self, other: &u64) -> bool {
529        (*self as u64) == *other
530    }
531}
532
533impl PartialOrd<u64> for NamedChain {
534    #[inline]
535    fn partial_cmp(&self, other: &u64) -> Option<Ordering> {
536        (*self as u64).partial_cmp(other)
537    }
538}
539
540#[cfg(feature = "serde")]
541impl serde::Serialize for NamedChain {
542    #[inline]
543    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
544        s.serialize_str(self.as_ref())
545    }
546}
547
548#[cfg(feature = "rlp")]
549impl alloy_rlp::Encodable for NamedChain {
550    #[inline]
551    fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
552        (*self as u64).encode(out)
553    }
554
555    #[inline]
556    fn length(&self) -> usize {
557        (*self as u64).length()
558    }
559}
560
561#[cfg(feature = "rlp")]
562impl alloy_rlp::Decodable for NamedChain {
563    #[inline]
564    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
565        let n = u64::decode(buf)?;
566        Self::try_from(n).map_err(|_| alloy_rlp::Error::Overflow)
567    }
568}
569
570// NB: all utility functions *should* be explicitly exhaustive (not use `_` matcher) so we don't
571//     forget to update them when adding a new `NamedChain` variant.
572#[allow(clippy::match_like_matches_macro)]
573#[deny(unreachable_patterns, unused_variables)]
574impl NamedChain {
575    /// Returns the string representation of the chain.
576    #[inline]
577    pub fn as_str(&self) -> &'static str {
578        self.into()
579    }
580
581    /// Returns `true` if this chain is Ethereum or an Ethereum testnet.
582    pub const fn is_ethereum(&self) -> bool {
583        use NamedChain::*;
584
585        matches!(self, Mainnet | Morden | Ropsten | Rinkeby | Goerli | Kovan | Holesky | Sepolia)
586    }
587
588    /// Returns true if the chain contains Optimism configuration.
589    pub const fn is_optimism(self) -> bool {
590        use NamedChain::*;
591
592        matches!(
593            self,
594            Optimism
595                | OptimismGoerli
596                | OptimismKovan
597                | OptimismSepolia
598                | Base
599                | BaseGoerli
600                | BaseSepolia
601                | Fraxtal
602                | FraxtalTestnet
603                | Ink
604                | InkSepolia
605                | Mode
606                | ModeSepolia
607                | Pgn
608                | PgnSepolia
609                | Zora
610                | ZoraSepolia
611                | BlastSepolia
612                | OpBNBMainnet
613                | OpBNBTestnet
614                | Soneium
615                | SoneiumMinatoTestnet
616                | Odyssey
617                | World
618                | WorldSepolia
619                | Unichain
620                | UnichainSepolia
621                | HappychainTestnet
622        )
623    }
624
625    /// Returns true if the chain contains Arbitrum configuration.
626    pub const fn is_arbitrum(self) -> bool {
627        use NamedChain::*;
628
629        matches!(self, Arbitrum | ArbitrumTestnet | ArbitrumGoerli | ArbitrumSepolia | ArbitrumNova)
630    }
631
632    /// Returns the chain's average blocktime, if applicable.
633    ///
634    /// It can be beneficial to know the average blocktime to adjust the polling of an HTTP provider
635    /// for example.
636    ///
637    /// **Note:** this is not an accurate average, but is rather a sensible default derived from
638    /// blocktime charts such as [Etherscan's](https://etherscan.com/chart/blocktime)
639    /// or [Polygonscan's](https://polygonscan.com/chart/blocktime).
640    ///
641    /// # Examples
642    ///
643    /// ```
644    /// use alloy_chains::NamedChain;
645    /// use std::time::Duration;
646    ///
647    /// assert_eq!(NamedChain::Mainnet.average_blocktime_hint(), Some(Duration::from_millis(12_000)),);
648    /// assert_eq!(NamedChain::Optimism.average_blocktime_hint(), Some(Duration::from_millis(2_000)),);
649    /// ```
650    pub const fn average_blocktime_hint(self) -> Option<Duration> {
651        use NamedChain::*;
652
653        Some(Duration::from_millis(match self {
654            Mainnet | Taiko | TaikoHekla => 12_000,
655
656            Arbitrum
657            | ArbitrumTestnet
658            | ArbitrumGoerli
659            | ArbitrumSepolia
660            | GravityAlphaMainnet
661            | GravityAlphaTestnetSepolia
662            | Xai
663            | XaiSepolia
664            | Syndr
665            | SyndrSepolia
666            | ArbitrumNova
667            | ApeChain
668            | Curtis
669            | SuperpositionTestnet
670            | Superposition => 260,
671
672            Optimism | OptimismGoerli | OptimismSepolia | Base | BaseGoerli | BaseSepolia
673            | Blast | BlastSepolia | Fraxtal | FraxtalTestnet | Zora | ZoraSepolia | Mantle
674            | MantleSepolia | Mode | ModeSepolia | Pgn | PgnSepolia | HappychainTestnet
675            | Soneium | SoneiumMinatoTestnet | Bob | BobSepolia => 2_000,
676
677            Ink | InkSepolia | Odyssey => 1_000,
678
679            Viction => 2_000,
680
681            Polygon | PolygonMumbai | PolygonAmoy => 2_100,
682
683            Acala | AcalaMandalaTestnet | AcalaTestnet | Karura | KaruraTestnet | Moonbeam
684            | Moonriver => 12_500,
685
686            BinanceSmartChain | BinanceSmartChainTestnet => 3_000,
687
688            Avalanche | AvalancheFuji => 2_000,
689
690            Fantom | FantomTestnet => 1_200,
691
692            Cronos | CronosTestnet | Canto | CantoTestnet => 5_700,
693
694            Evmos | EvmosTestnet => 1_900,
695
696            Aurora | AuroraTestnet => 1_100,
697
698            Oasis => 5_500,
699
700            Emerald | Darwinia | Crab | Koi => 6_000,
701
702            Dev | AnvilHardhat => 200,
703
704            Celo | CeloAlfajores | CeloBaklava => 5_000,
705
706            FilecoinCalibrationTestnet | FilecoinMainnet => 30_000,
707
708            Scroll | ScrollSepolia => 3_000,
709
710            Shimmer => 5_000,
711
712            Gnosis | Chiado => 5_000,
713
714            Elastos => 5_000,
715
716            Etherlink => 5_000,
717
718            EtherlinkTestnet => 5_000,
719
720            Degen => 600,
721
722            Cfx | CfxTestnet => 500,
723
724            OpBNBMainnet | OpBNBTestnet | AutonomysNovaTestnet => 1_000,
725
726            Ronin | RoninTestnet => 3_000,
727
728            Flare => 1_800,
729
730            FlareCoston2 => 2_500,
731
732            Pulsechain => 10000,
733            PulsechainTestnet => 10101,
734
735            Immutable | ImmutableTestnet => 2_000,
736
737            World | WorldSepolia => 2_000,
738
739            Iotex => 5_000,
740            Core => 3_000,
741            Merlin => 3_000,
742            Bitlayer => 3_000,
743            Vana => 6_000,
744            Zeta => 6_000,
745            Kaia => 1_000,
746            Story => 2_500,
747
748            Sonic => 1_000,
749
750            TelosEvm | TelosEvmTestnet => 500,
751
752            UnichainSepolia | Unichain => 1_000,
753
754            BerachainBartio | BerachainArtio | Berachain => 2_000,
755
756            MonadTestnet => 500,
757
758            Hyperliquid => 2_000,
759
760            Morden | Ropsten | Rinkeby | Goerli | Kovan | Sepolia | Holesky | MantleTestnet
761            | Moonbase | MoonbeamDev | OptimismKovan | Poa | Sokol | Rsk | EmeraldTestnet
762            | Boba | ZkSync | ZkSyncTestnet | PolygonZkEvm | PolygonZkEvmTestnet | Metis
763            | Linea | LineaGoerli | LineaSepolia | KakarotSepolia | SonicTestnet | Treasure
764            | TreasureTopaz => return None,
765        }))
766    }
767
768    /// Returns whether the chain implements EIP-1559 (with the type 2 EIP-2718 transaction type).
769    ///
770    /// # Examples
771    ///
772    /// ```
773    /// use alloy_chains::NamedChain;
774    ///
775    /// assert!(!NamedChain::Mainnet.is_legacy());
776    /// assert!(NamedChain::Celo.is_legacy());
777    /// ```
778    pub const fn is_legacy(self) -> bool {
779        use NamedChain::*;
780
781        match self {
782            // Known legacy chains / non EIP-1559 compliant.
783            Acala
784            | AcalaMandalaTestnet
785            | AcalaTestnet
786            | ArbitrumTestnet
787            | BinanceSmartChain
788            | BinanceSmartChainTestnet
789            | Boba
790            | Celo
791            | CeloAlfajores
792            | CeloBaklava
793            | Elastos
794            | Emerald
795            | EmeraldTestnet
796            | Fantom
797            | FantomTestnet
798            | Karura
799            | KaruraTestnet
800            | MantleTestnet
801            | Metis
802            | Oasis
803            | OptimismKovan
804            | PolygonZkEvm
805            | PolygonZkEvmTestnet
806            | Ronin
807            | RoninTestnet
808            | Rsk
809            | Shimmer
810            | TelosEvm
811            | TelosEvmTestnet
812            | Treasure
813            | TreasureTopaz
814            | Viction
815            | ZkSync
816            | ZkSyncTestnet => true,
817
818            // Known EIP-1559 chains.
819            Mainnet
820            | Goerli
821            | Sepolia
822            | Holesky
823            | Odyssey
824            | Base
825            | BaseGoerli
826            | BaseSepolia
827            | Blast
828            | BlastSepolia
829            | Fraxtal
830            | FraxtalTestnet
831            | Optimism
832            | OptimismGoerli
833            | OptimismSepolia
834            | Bob
835            | BobSepolia
836            | Polygon
837            | PolygonMumbai
838            | PolygonAmoy
839            | Avalanche
840            | AvalancheFuji
841            | Arbitrum
842            | ArbitrumGoerli
843            | ArbitrumSepolia
844            | ArbitrumNova
845            | GravityAlphaMainnet
846            | GravityAlphaTestnetSepolia
847            | Xai
848            | XaiSepolia
849            | HappychainTestnet
850            | Syndr
851            | SyndrSepolia
852            | FilecoinMainnet
853            | Linea
854            | LineaGoerli
855            | LineaSepolia
856            | FilecoinCalibrationTestnet
857            | Gnosis
858            | Chiado
859            | Zora
860            | ZoraSepolia
861            | Ink
862            | InkSepolia
863            | Mantle
864            | MantleSepolia
865            | Mode
866            | ModeSepolia
867            | Pgn
868            | PgnSepolia
869            | KakarotSepolia
870            | Etherlink
871            | EtherlinkTestnet
872            | Degen
873            | OpBNBMainnet
874            | OpBNBTestnet
875            | Taiko
876            | TaikoHekla
877            | AutonomysNovaTestnet
878            | Flare
879            | FlareCoston2
880            | Scroll
881            | ScrollSepolia
882            | Darwinia
883            | Cfx
884            | CfxTestnet
885            | Crab
886            | Pulsechain
887            | PulsechainTestnet
888            | Koi
889            | Immutable
890            | ImmutableTestnet
891            | Soneium
892            | SoneiumMinatoTestnet
893            | Sonic
894            | World
895            | WorldSepolia
896            | Unichain
897            | UnichainSepolia
898            | ApeChain
899            | BerachainBartio
900            | BerachainArtio
901            | Berachain
902            | Curtis
903            | SuperpositionTestnet
904            | Superposition
905            | MonadTestnet
906            | Hyperliquid => false,
907
908            // Unknown / not applicable, default to false for backwards compatibility.
909            Dev | AnvilHardhat | Morden | Ropsten | Rinkeby | Cronos | CronosTestnet | Kovan
910            | Sokol | Poa | Moonbeam | MoonbeamDev | Moonriver | Moonbase | Evmos
911            | EvmosTestnet | Aurora | AuroraTestnet | Canto | CantoTestnet | Iotex | Core
912            | Merlin | Bitlayer | SonicTestnet | Vana | Zeta | Kaia | Story => false,
913        }
914    }
915
916    /// Returns whether the chain supports the [Shanghai hardfork][ref].
917    ///
918    /// [ref]: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md
919    pub const fn supports_shanghai(self) -> bool {
920        use NamedChain::*;
921
922        matches!(
923            self,
924            Mainnet
925                | Goerli
926                | Sepolia
927                | Holesky
928                | AnvilHardhat
929                | Optimism
930                | OptimismGoerli
931                | OptimismSepolia
932                | Bob
933                | BobSepolia
934                | Odyssey
935                | Base
936                | BaseGoerli
937                | BaseSepolia
938                | Blast
939                | BlastSepolia
940                | Fraxtal
941                | FraxtalTestnet
942                | Ink
943                | InkSepolia
944                | Gnosis
945                | Chiado
946                | ZoraSepolia
947                | Mantle
948                | MantleSepolia
949                | Mode
950                | ModeSepolia
951                | PolygonMumbai
952                | Polygon
953                | Arbitrum
954                | ArbitrumNova
955                | ArbitrumSepolia
956                | GravityAlphaMainnet
957                | GravityAlphaTestnetSepolia
958                | Xai
959                | XaiSepolia
960                | Syndr
961                | SyndrSepolia
962                | Etherlink
963                | EtherlinkTestnet
964                | Scroll
965                | ScrollSepolia
966                | HappychainTestnet
967                | Shimmer
968                | OpBNBMainnet
969                | OpBNBTestnet
970                | KakarotSepolia
971                | Taiko
972                | TaikoHekla
973                | Avalanche
974                | AvalancheFuji
975                | AutonomysNovaTestnet
976                | Acala
977                | AcalaMandalaTestnet
978                | AcalaTestnet
979                | Karura
980                | KaruraTestnet
981                | Darwinia
982                | Crab
983                | Cfx
984                | CfxTestnet
985                | Pulsechain
986                | PulsechainTestnet
987                | Koi
988                | Immutable
989                | ImmutableTestnet
990                | Soneium
991                | SoneiumMinatoTestnet
992                | World
993                | WorldSepolia
994                | Iotex
995                | Unichain
996                | UnichainSepolia
997                | ApeChain
998                | Curtis
999                | SuperpositionTestnet
1000                | Superposition
1001                | MonadTestnet
1002        )
1003    }
1004
1005    #[doc(hidden)]
1006    #[deprecated(since = "0.1.3", note = "use `supports_shanghai` instead")]
1007    pub const fn supports_push0(self) -> bool {
1008        self.supports_shanghai()
1009    }
1010
1011    /// Returns whether the chain is a testnet.
1012    pub const fn is_testnet(self) -> bool {
1013        use NamedChain::*;
1014
1015        match self {
1016            // Ethereum testnets.
1017            Goerli | Holesky | Kovan | Sepolia | Morden | Ropsten | Rinkeby => true,
1018
1019            // Other testnets.
1020            ArbitrumGoerli
1021            | ArbitrumSepolia
1022            | ArbitrumTestnet
1023            | SyndrSepolia
1024            | AuroraTestnet
1025            | AvalancheFuji
1026            | Odyssey
1027            | BaseGoerli
1028            | BaseSepolia
1029            | BlastSepolia
1030            | BinanceSmartChainTestnet
1031            | CantoTestnet
1032            | CronosTestnet
1033            | CeloAlfajores
1034            | CeloBaklava
1035            | EmeraldTestnet
1036            | EvmosTestnet
1037            | FantomTestnet
1038            | FilecoinCalibrationTestnet
1039            | FraxtalTestnet
1040            | HappychainTestnet
1041            | LineaGoerli
1042            | LineaSepolia
1043            | InkSepolia
1044            | MantleTestnet
1045            | MantleSepolia
1046            | MoonbeamDev
1047            | OptimismGoerli
1048            | OptimismKovan
1049            | OptimismSepolia
1050            | BobSepolia
1051            | PolygonMumbai
1052            | PolygonAmoy
1053            | PolygonZkEvmTestnet
1054            | ScrollSepolia
1055            | Shimmer
1056            | ZkSyncTestnet
1057            | ZoraSepolia
1058            | ModeSepolia
1059            | PgnSepolia
1060            | KakarotSepolia
1061            | EtherlinkTestnet
1062            | OpBNBTestnet
1063            | RoninTestnet
1064            | TaikoHekla
1065            | AutonomysNovaTestnet
1066            | FlareCoston2
1067            | AcalaMandalaTestnet
1068            | AcalaTestnet
1069            | KaruraTestnet
1070            | CfxTestnet
1071            | PulsechainTestnet
1072            | GravityAlphaTestnetSepolia
1073            | XaiSepolia
1074            | Koi
1075            | ImmutableTestnet
1076            | SoneiumMinatoTestnet
1077            | WorldSepolia
1078            | UnichainSepolia
1079            | Curtis
1080            | TreasureTopaz
1081            | SonicTestnet
1082            | BerachainBartio
1083            | BerachainArtio
1084            | SuperpositionTestnet
1085            | MonadTestnet
1086            | TelosEvmTestnet => true,
1087
1088            // Dev chains.
1089            Dev | AnvilHardhat => true,
1090
1091            // Mainnets.
1092            Mainnet | Optimism | Arbitrum | ArbitrumNova | Blast | Syndr | Cronos | Rsk
1093            | BinanceSmartChain | Poa | Sokol | Scroll | Metis | Gnosis | Polygon
1094            | PolygonZkEvm | Fantom | Moonbeam | Moonriver | Moonbase | Evmos | Chiado | Oasis
1095            | Emerald | FilecoinMainnet | Avalanche | Celo | Aurora | Canto | Boba | Base
1096            | Fraxtal | Ink | Linea | ZkSync | Mantle | GravityAlphaMainnet | Xai | Zora | Pgn
1097            | Mode | Viction | Elastos | Degen | OpBNBMainnet | Ronin | Taiko | Flare | Acala
1098            | Karura | Darwinia | Cfx | Crab | Pulsechain | Etherlink | Immutable | World
1099            | Iotex | Core | Merlin | Bitlayer | ApeChain | Vana | Zeta | Kaia | Treasure | Bob
1100            | Soneium | Sonic | Superposition | Berachain | Unichain | TelosEvm | Story
1101            | Hyperliquid => false,
1102        }
1103    }
1104
1105    /// Returns the symbol of the chain's native currency.
1106    pub const fn native_currency_symbol(self) -> Option<&'static str> {
1107        use NamedChain::*;
1108
1109        Some(match self {
1110            Mainnet | Goerli | Holesky | Kovan | Sepolia | Morden | Ropsten | Rinkeby | Scroll
1111            | ScrollSepolia | Taiko | TaikoHekla | Unichain | UnichainSepolia
1112            | SuperpositionTestnet | Superposition => "ETH",
1113
1114            Mantle | MantleSepolia => "MNT",
1115
1116            GravityAlphaMainnet | GravityAlphaTestnetSepolia => "G",
1117
1118            Xai | XaiSepolia => "XAI",
1119
1120            HappychainTestnet => "HAPPY",
1121
1122            BinanceSmartChain | BinanceSmartChainTestnet | OpBNBMainnet | OpBNBTestnet => "BNB",
1123
1124            Etherlink | EtherlinkTestnet => "XTZ",
1125
1126            Degen => "DEGEN",
1127
1128            Ronin | RoninTestnet => "RON",
1129
1130            Shimmer => "SMR",
1131
1132            Flare => "FLR",
1133
1134            FlareCoston2 => "C2FLR",
1135
1136            Darwinia => "RING",
1137
1138            Crab => "CRAB",
1139
1140            Koi => "KRING",
1141
1142            Cfx | CfxTestnet => "CFX",
1143            Pulsechain | PulsechainTestnet => "PLS",
1144
1145            Immutable => "IMX",
1146            ImmutableTestnet => "tIMX",
1147
1148            World | WorldSepolia => "WRLD",
1149
1150            Iotex => "IOTX",
1151            Core => "CORE",
1152            Merlin => "BTC",
1153            Bitlayer => "BTC",
1154            Vana => "VANA",
1155            Zeta => "ZETA",
1156            Kaia => "KAIA",
1157            Story => "IP",
1158            ApeChain | Curtis => "APE",
1159
1160            Treasure | TreasureTopaz => "MAGIC",
1161
1162            BerachainBartio | BerachainArtio | Berachain => "BERA",
1163
1164            Sonic => "S",
1165
1166            TelosEvm | TelosEvmTestnet => "TLOS",
1167
1168            Hyperliquid => "HYPE",
1169
1170            _ => return None,
1171        })
1172    }
1173
1174    /// Returns the chain's blockchain explorer and its API (Etherscan and Etherscan-like) URLs.
1175    ///
1176    /// Returns `(API_URL, BASE_URL)`.
1177    ///
1178    /// All URLs have no trailing `/`
1179    ///
1180    /// # Examples
1181    ///
1182    /// ```
1183    /// use alloy_chains::NamedChain;
1184    ///
1185    /// assert_eq!(
1186    ///     NamedChain::Mainnet.etherscan_urls(),
1187    ///     Some(("https://api.etherscan.io/api", "https://etherscan.io"))
1188    /// );
1189    /// assert_eq!(
1190    ///     NamedChain::Avalanche.etherscan_urls(),
1191    ///     Some(("https://api.snowtrace.io/api", "https://snowtrace.io"))
1192    /// );
1193    /// assert_eq!(NamedChain::AnvilHardhat.etherscan_urls(), None);
1194    /// ```
1195    pub const fn etherscan_urls(self) -> Option<(&'static str, &'static str)> {
1196        use NamedChain::*;
1197
1198        Some(match self {
1199            Mainnet => ("https://api.etherscan.io/api", "https://etherscan.io"),
1200            Ropsten => ("https://api-ropsten.etherscan.io/api", "https://ropsten.etherscan.io"),
1201            Kovan => ("https://api-kovan.etherscan.io/api", "https://kovan.etherscan.io"),
1202            Rinkeby => ("https://api-rinkeby.etherscan.io/api", "https://rinkeby.etherscan.io"),
1203            Goerli => ("https://api-goerli.etherscan.io/api", "https://goerli.etherscan.io"),
1204            Sepolia => ("https://api-sepolia.etherscan.io/api", "https://sepolia.etherscan.io"),
1205            Holesky => ("https://api-holesky.etherscan.io/api", "https://holesky.etherscan.io"),
1206
1207            Polygon => ("https://api.polygonscan.com/api", "https://polygonscan.com"),
1208            PolygonMumbai => {
1209                ("https://api-testnet.polygonscan.com/api", "https://mumbai.polygonscan.com")
1210            }
1211            PolygonAmoy => ("https://api-amoy.polygonscan.com/api", "https://amoy.polygonscan.com"),
1212
1213            PolygonZkEvm => {
1214                ("https://api-zkevm.polygonscan.com/api", "https://zkevm.polygonscan.com")
1215            }
1216            PolygonZkEvmTestnet => (
1217                "https://api-testnet-zkevm.polygonscan.com/api",
1218                "https://testnet-zkevm.polygonscan.com",
1219            ),
1220
1221            Avalanche => ("https://api.snowtrace.io/api", "https://snowtrace.io"),
1222            AvalancheFuji => {
1223                ("https://api-testnet.snowtrace.io/api", "https://testnet.snowtrace.io")
1224            }
1225
1226            Optimism => {
1227                ("https://api-optimistic.etherscan.io/api", "https://optimistic.etherscan.io")
1228            }
1229            OptimismGoerli => (
1230                "https://api-goerli-optimistic.etherscan.io/api",
1231                "https://goerli-optimism.etherscan.io",
1232            ),
1233            OptimismKovan => (
1234                "https://api-kovan-optimistic.etherscan.io/api",
1235                "https://kovan-optimistic.etherscan.io",
1236            ),
1237            OptimismSepolia => (
1238                "https://api-sepolia-optimistic.etherscan.io/api",
1239                "https://sepolia-optimism.etherscan.io",
1240            ),
1241
1242            Bob => ("https://explorer.gobob.xyz/api", "https://explorer.gobob.xyz"),
1243            BobSepolia => (
1244                "https://bob-sepolia.explorer.gobob.xyz/api",
1245                "https://bob-sepolia.explorer.gobob.xyz",
1246            ),
1247
1248            Fantom => ("https://api.ftmscan.com/api", "https://ftmscan.com"),
1249            FantomTestnet => ("https://api-testnet.ftmscan.com/api", "https://testnet.ftmscan.com"),
1250
1251            BinanceSmartChain => ("https://api.bscscan.com/api", "https://bscscan.com"),
1252            BinanceSmartChainTestnet => {
1253                ("https://api-testnet.bscscan.com/api", "https://testnet.bscscan.com")
1254            }
1255
1256            OpBNBMainnet => ("https://opbnb.bscscan.com/api", "https://opbnb.bscscan.com"),
1257            OpBNBTestnet => {
1258                ("https://opbnb-testnet.bscscan.com/api", "https://opbnb-testnet.bscscan.com")
1259            }
1260
1261            Arbitrum => ("https://api.arbiscan.io/api", "https://arbiscan.io"),
1262            ArbitrumTestnet => {
1263                ("https://api-testnet.arbiscan.io/api", "https://testnet.arbiscan.io")
1264            }
1265            ArbitrumGoerli => ("https://api-goerli.arbiscan.io/api", "https://goerli.arbiscan.io"),
1266            ArbitrumSepolia => {
1267                ("https://api-sepolia.arbiscan.io/api", "https://sepolia.arbiscan.io")
1268            }
1269            ArbitrumNova => ("https://api-nova.arbiscan.io/api", "https://nova.arbiscan.io"),
1270
1271            GravityAlphaMainnet => {
1272                ("https://explorer.gravity.xyz/api", "https://explorer.gravity.xyz")
1273            }
1274            GravityAlphaTestnetSepolia => {
1275                ("https://explorer-sepolia.gravity.xyz/api", "https://explorer-sepolia.gravity.xyz")
1276            }
1277            HappychainTestnet => (
1278                "https://happy-testnet-sepolia.explorer.caldera.xyz/api",
1279                "https://happy-testnet-sepolia.explorer.caldera.xyz",
1280            ),
1281
1282            XaiSepolia => ("https://sepolia.xaiscan.io/api", "https://sepolia.xaiscan.io"),
1283            Xai => ("https://xaiscan.io/api", "https://xaiscan.io"),
1284
1285            Syndr => ("https://explorer.syndr.com/api", "https://explorer.syndr.com"),
1286            SyndrSepolia => {
1287                ("https://sepolia-explorer.syndr.com/api", "https://sepolia-explorer.syndr.com")
1288            }
1289
1290            Cronos => ("https://api.cronoscan.com/api", "https://cronoscan.com"),
1291            CronosTestnet => {
1292                ("https://api-testnet.cronoscan.com/api", "https://testnet.cronoscan.com")
1293            }
1294
1295            Moonbeam => ("https://api-moonbeam.moonscan.io/api", "https://moonbeam.moonscan.io"),
1296            Moonbase => ("https://api-moonbase.moonscan.io/api", "https://moonbase.moonscan.io"),
1297            Moonriver => ("https://api-moonriver.moonscan.io/api", "https://moonriver.moonscan.io"),
1298
1299            Gnosis => ("https://api.gnosisscan.io/api", "https://gnosisscan.io"),
1300
1301            Scroll => ("https://api.scrollscan.com/api", "https://scrollscan.com"),
1302            ScrollSepolia => {
1303                ("https://api-sepolia.scrollscan.com/api", "https://sepolia.scrollscan.com")
1304            }
1305
1306            Ink => ("https://explorer.inkonchain.com/api/v2", "https://explorer.inkonchain.com"),
1307            InkSepolia => (
1308                "https://explorer-sepolia.inkonchain.com/api/v2",
1309                "https://explorer-sepolia.inkonchain.com",
1310            ),
1311
1312            Shimmer => {
1313                ("https://explorer.evm.shimmer.network/api", "https://explorer.evm.shimmer.network")
1314            }
1315
1316            Metis => (
1317                "https://api.routescan.io/v2/network/mainnet/evm/1088/etherscan",
1318                "https://explorer.metis.io",
1319            ),
1320
1321            Chiado => {
1322                ("https://blockscout.chiadochain.net/api", "https://blockscout.chiadochain.net")
1323            }
1324
1325            FilecoinCalibrationTestnet => (
1326                "https://api.calibration.node.glif.io/rpc/v1",
1327                "https://calibration.filfox.info/en",
1328            ),
1329
1330            Sokol => ("https://blockscout.com/poa/sokol/api", "https://blockscout.com/poa/sokol"),
1331
1332            Poa => ("https://blockscout.com/poa/core/api", "https://blockscout.com/poa/core"),
1333
1334            Rsk => ("https://blockscout.com/rsk/mainnet/api", "https://blockscout.com/rsk/mainnet"),
1335
1336            Oasis => ("https://scan.oasischain.io/api", "https://scan.oasischain.io"),
1337
1338            Emerald => {
1339                ("https://explorer.emerald.oasis.dev/api", "https://explorer.emerald.oasis.dev")
1340            }
1341            EmeraldTestnet => (
1342                "https://testnet.explorer.emerald.oasis.dev/api",
1343                "https://testnet.explorer.emerald.oasis.dev",
1344            ),
1345
1346            Aurora => ("https://api.aurorascan.dev/api", "https://aurorascan.dev"),
1347            AuroraTestnet => {
1348                ("https://testnet.aurorascan.dev/api", "https://testnet.aurorascan.dev")
1349            }
1350
1351            Evmos => ("https://evm.evmos.org/api", "https://evm.evmos.org"),
1352            EvmosTestnet => ("https://evm.evmos.dev/api", "https://evm.evmos.dev"),
1353
1354            Celo => ("https://api.celoscan.io/api", "https://celoscan.io"),
1355            CeloAlfajores => {
1356                ("https://api-alfajores.celoscan.io/api", "https://alfajores.celoscan.io")
1357            }
1358            CeloBaklava => {
1359                ("https://explorer.celo.org/baklava/api", "https://explorer.celo.org/baklava")
1360            }
1361
1362            Canto => ("https://evm.explorer.canto.io/api", "https://evm.explorer.canto.io"),
1363            CantoTestnet => (
1364                "https://testnet-explorer.canto.neobase.one/api",
1365                "https://testnet-explorer.canto.neobase.one",
1366            ),
1367
1368            Boba => ("https://api.bobascan.com/api", "https://bobascan.com"),
1369
1370            Base => ("https://api.basescan.org/api", "https://basescan.org"),
1371            BaseGoerli => ("https://api-goerli.basescan.org/api", "https://goerli.basescan.org"),
1372            BaseSepolia => ("https://api-sepolia.basescan.org/api", "https://sepolia.basescan.org"),
1373
1374            Fraxtal => ("https://api.fraxscan.com/api", "https://fraxscan.com"),
1375            FraxtalTestnet => {
1376                ("https://api-holesky.fraxscan.com/api", "https://holesky.fraxscan.com")
1377            }
1378
1379            Blast => ("https://api.blastscan.io/api", "https://blastscan.io"),
1380            BlastSepolia => {
1381                ("https://api-sepolia.blastscan.io/api", "https://sepolia.blastscan.io")
1382            }
1383
1384            ZkSync => ("https://api-era.zksync.network/api", "https://era.zksync.network"),
1385            ZkSyncTestnet => {
1386                ("https://api-sepolia-era.zksync.network/api", "https://sepolia-era.zksync.network")
1387            }
1388
1389            Linea => ("https://api.lineascan.build/api", "https://lineascan.build"),
1390            LineaGoerli => {
1391                ("https://explorer.goerli.linea.build/api", "https://explorer.goerli.linea.build")
1392            }
1393            LineaSepolia => {
1394                ("https://api-sepolia.lineascan.build/api", "https://sepolia.lineascan.build")
1395            }
1396
1397            Mantle => ("https://explorer.mantle.xyz/api", "https://explorer.mantle.xyz"),
1398            MantleTestnet => {
1399                ("https://explorer.testnet.mantle.xyz/api", "https://explorer.testnet.mantle.xyz")
1400            }
1401            MantleSepolia => {
1402                ("https://explorer.sepolia.mantle.xyz/api", "https://explorer.sepolia.mantle.xyz")
1403            }
1404
1405            Viction => ("https://www.vicscan.xyz/api", "https://www.vicscan.xyz"),
1406
1407            Zora => ("https://explorer.zora.energy/api", "https://explorer.zora.energy"),
1408            ZoraSepolia => {
1409                ("https://sepolia.explorer.zora.energy/api", "https://sepolia.explorer.zora.energy")
1410            }
1411
1412            Pgn => {
1413                ("https://explorer.publicgoods.network/api", "https://explorer.publicgoods.network")
1414            }
1415
1416            PgnSepolia => (
1417                "https://explorer.sepolia.publicgoods.network/api",
1418                "https://explorer.sepolia.publicgoods.network",
1419            ),
1420
1421            Mode => ("https://explorer.mode.network/api", "https://explorer.mode.network"),
1422            ModeSepolia => (
1423                "https://sepolia.explorer.mode.network/api",
1424                "https://sepolia.explorer.mode.network",
1425            ),
1426
1427            Elastos => ("https://esc.elastos.io/api", "https://esc.elastos.io"),
1428
1429            AnvilHardhat | Dev | Morden | MoonbeamDev | FilecoinMainnet | AutonomysNovaTestnet
1430            | Iotex => {
1431                return None;
1432            }
1433            KakarotSepolia => {
1434                ("https://sepolia.kakarotscan.org/api", "https://sepolia.kakarotscan.org")
1435            }
1436            Etherlink => ("https://explorer.etherlink.com/api", "https://explorer.etherlink.com"),
1437            EtherlinkTestnet => (
1438                "https://testnet-explorer.etherlink.com/api",
1439                "https://testnet-explorer.etherlink.com",
1440            ),
1441            Degen => ("https://explorer.degen.tips/api", "https://explorer.degen.tips"),
1442            Ronin => ("https://skynet-api.roninchain.com/ronin", "https://app.roninchain.com"),
1443            RoninTestnet => (
1444                "https://api-gateway.skymavis.com/rpc/testnet",
1445                "https://saigon-app.roninchain.com",
1446            ),
1447            Taiko => ("https://api.taikoscan.io/api", "https://taikoscan.io"),
1448            TaikoHekla => ("https://api-testnet.taikoscan.io/api", "https://hekla.taikoscan.io"),
1449            Flare => {
1450                ("https://flare-explorer.flare.network/api", "https://flare-explorer.flare.network")
1451            }
1452            FlareCoston2 => (
1453                "https://coston2-explorer.flare.network/api",
1454                "https://coston2-explorer.flare.network",
1455            ),
1456            Acala => ("https://blockscout.acala.network/api", "https://blockscout.acala.network"),
1457            AcalaMandalaTestnet => (
1458                "https://blockscout.mandala.aca-staging.network/api",
1459                "https://blockscout.mandala.aca-staging.network",
1460            ),
1461            AcalaTestnet => (
1462                "https://blockscout.acala-testnet.aca-staging.network/api",
1463                "https://blockscout.acala-testnet.aca-staging.network",
1464            ),
1465            Karura => {
1466                ("https://blockscout.karura.network/api", "https://blockscout.karura.network")
1467            }
1468            KaruraTestnet => (
1469                "https://blockscout.karura-testnet.aca-staging.network/api",
1470                "https://blockscout.karura-testnet.aca-staging.network",
1471            ),
1472
1473            Darwinia => {
1474                ("https://explorer.darwinia.network/api", "https://explorer.darwinia.network")
1475            }
1476            Crab => {
1477                ("https://crab-scan.darwinia.network/api", "https://crab-scan.darwinia.network")
1478            }
1479            Koi => ("https://koi-scan.darwinia.network/api", "https://koi-scan.darwinia.network"),
1480            Cfx => ("https://evmapi.confluxscan.net/api", "https://evm.confluxscan.io"),
1481            CfxTestnet => {
1482                ("https://evmapi-testnet.confluxscan.net/api", "https://evmtestnet.confluxscan.io")
1483            }
1484            Pulsechain => ("https://api.scan.pulsechain.com", "https://scan.pulsechain.com"),
1485            PulsechainTestnet => (
1486                "https://api.scan.v4.testnet.pulsechain.com",
1487                "https://scan.v4.testnet.pulsechain.com",
1488            ),
1489
1490            Immutable => ("https://explorer.immutable.com/api", "https://explorer.immutable.com"),
1491            ImmutableTestnet => (
1492                "https://explorer.testnet.immutable.com/api",
1493                "https://explorer.testnet.immutable.com",
1494            ),
1495            Soneium => ("https://soneium.blockscout.com/api", "https://soneium.blockscout.com"),
1496            SoneiumMinatoTestnet => (
1497                "https://soneium-minato.blockscout.com/api",
1498                "https://soneium-minato.blockscout.com",
1499            ),
1500            Odyssey => {
1501                ("https://odyssey-explorer.ithaca.xyz/api", "https://odyssey-explorer.ithaca.xyz")
1502            }
1503            World => ("https://api.worldscan.org/api", "https://worldscan.org"),
1504            WorldSepolia => {
1505                ("https://api-sepolia.worldscan.org/api", "https://sepolia.worldscan.org")
1506            }
1507            Unichain => ("https://api.uniscan.xyz/api", "https://uniscan.xyz"),
1508            UnichainSepolia => {
1509                ("https://api-sepolia.uniscan.xyz/api", "https://sepolia.uniscan.xyz")
1510            }
1511            Core => ("https://openapi.coredao.org/api", "https://scan.coredao.org"),
1512            Merlin => ("https://scan.merlinchain.io/api", "https://scan.merlinchain.io"),
1513            Bitlayer => ("https://api.btrscan.com/scan/api", "https://www.btrscan.com"),
1514            Vana => ("https://api.vanascan.io/api", "https://vanascan.io"),
1515            Zeta => ("https://zetachain.blockscout.com/api", "https://zetachain.blockscout.com"),
1516            Kaia => ("https://mainnet-oapi.kaiascan.io/api", "https://kaiascan.io"),
1517            Story => ("https://www.storyscan.xyz/api/v2", "https://www.storyscan.xyz"),
1518
1519            ApeChain => ("https://api.apescan.io/api", "https://apescan.io"),
1520            Curtis => ("https://curtis.explorer.caldera.xyz/api/v2", "https://curtis.apescan.io"),
1521            SonicTestnet => (
1522                "https://api.routescan.io/v2/network/testnet/evm/64165/etherscan/api",
1523                "https://scan.soniclabs.com",
1524            ),
1525            Sonic => ("https://api.sonicscan.org/api", "https://sonicscan.org"),
1526            Treasure => ("https://block-explorer.treasurescan.io/api", "https://treasurescan.io"),
1527            TreasureTopaz => (
1528                "https://block-explorer.topaz.treasurescan.io/api",
1529                "https://topaz.treasurescan.io",
1530            ),
1531            BerachainBartio => ("https://bartio.beratrail.io/api", "https://bartio.beratrail.io"),
1532            BerachainArtio => ("https://artio.beratrail.io/api", "https://artio.beratrail.io"),
1533            Berachain => ("https://api.berascan.com/api", "https://berascan.com"),
1534            SuperpositionTestnet => (
1535                "https://testnet-explorer.superposition.so/api",
1536                "https://testnet-explorer.superposition.so",
1537            ),
1538            Superposition => {
1539                ("https://explorer.superposition.so/api", "https://explorer.superposition.so")
1540            }
1541            MonadTestnet => ("https://sourcify.dev/server", "https://testnet.monadexplorer.com"),
1542            TelosEvm => ("https://api.teloscan.io/api", "https://teloscan.io"),
1543            TelosEvmTestnet => {
1544                ("https://api.testnet.teloscan.io/api", "https://testnet.teloscan.io")
1545            }
1546            Hyperliquid => (
1547                "https://hyperliquid.cloud.blockscout.com/api/v2",
1548                "https://hyperliquid.cloud.blockscout.com",
1549            ),
1550        })
1551    }
1552
1553    /// Returns the chain's blockchain explorer's API key environment variable's default name.
1554    ///
1555    /// # Examples
1556    ///
1557    /// ```
1558    /// use alloy_chains::NamedChain;
1559    ///
1560    /// assert_eq!(NamedChain::Mainnet.etherscan_api_key_name(), Some("ETHERSCAN_API_KEY"));
1561    /// assert_eq!(NamedChain::AnvilHardhat.etherscan_api_key_name(), None);
1562    /// ```
1563    pub const fn etherscan_api_key_name(self) -> Option<&'static str> {
1564        use NamedChain::*;
1565
1566        let api_key_name = match self {
1567            Mainnet
1568            | Morden
1569            | Ropsten
1570            | Kovan
1571            | Rinkeby
1572            | Goerli
1573            | Holesky
1574            | Optimism
1575            | OptimismGoerli
1576            | OptimismKovan
1577            | OptimismSepolia
1578            | BinanceSmartChain
1579            | BinanceSmartChainTestnet
1580            | OpBNBMainnet
1581            | OpBNBTestnet
1582            | Arbitrum
1583            | ArbitrumTestnet
1584            | ArbitrumGoerli
1585            | ArbitrumSepolia
1586            | ArbitrumNova
1587            | Syndr
1588            | SyndrSepolia
1589            | Cronos
1590            | CronosTestnet
1591            | Aurora
1592            | AuroraTestnet
1593            | Celo
1594            | CeloAlfajores
1595            | Base
1596            | Linea
1597            | LineaSepolia
1598            | Mantle
1599            | MantleTestnet
1600            | MantleSepolia
1601            | Xai
1602            | XaiSepolia
1603            | BaseGoerli
1604            | BaseSepolia
1605            | Fraxtal
1606            | FraxtalTestnet
1607            | Blast
1608            | BlastSepolia
1609            | Gnosis
1610            | Scroll
1611            | ScrollSepolia
1612            | Taiko
1613            | TaikoHekla
1614            | Unichain
1615            | UnichainSepolia
1616            | MonadTestnet
1617            | ApeChain => "ETHERSCAN_API_KEY",
1618
1619            Avalanche | AvalancheFuji => "SNOWTRACE_API_KEY",
1620
1621            Polygon | PolygonMumbai | PolygonAmoy | PolygonZkEvm | PolygonZkEvmTestnet => {
1622                "POLYGONSCAN_API_KEY"
1623            }
1624
1625            Fantom | FantomTestnet => "FTMSCAN_API_KEY",
1626
1627            Moonbeam | Moonbase | MoonbeamDev | Moonriver => "MOONSCAN_API_KEY",
1628
1629            Acala | AcalaMandalaTestnet | AcalaTestnet | Canto | CantoTestnet | CeloBaklava
1630            | Etherlink | EtherlinkTestnet | Flare | FlareCoston2 | KakarotSepolia | Karura
1631            | KaruraTestnet | Mode | ModeSepolia | Pgn | PgnSepolia | Shimmer | Zora
1632            | ZoraSepolia | Darwinia | Crab | Koi | Immutable | ImmutableTestnet | Soneium
1633            | SoneiumMinatoTestnet | World | WorldSepolia | Curtis | Ink | InkSepolia
1634            | SuperpositionTestnet | Superposition | Vana | Story | Hyperliquid => {
1635                "BLOCKSCOUT_API_KEY"
1636            }
1637
1638            Boba => "BOBASCAN_API_KEY",
1639
1640            Core => "CORESCAN_API_KEY",
1641            Merlin => "MERLINSCAN_API_KEY",
1642            Bitlayer => "BITLAYERSCAN_API_KEY",
1643            Zeta => "ZETASCAN_API_KEY",
1644            Kaia => "KAIASCAN_API_KEY",
1645            Sonic => "SONICSCAN_API_KEY",
1646            Berachain => "BERASCAN_API_KEY",
1647            // Explicitly exhaustive. See NB above.
1648            Metis
1649            | Chiado
1650            | Odyssey
1651            | Sepolia
1652            | Rsk
1653            | Sokol
1654            | Poa
1655            | Oasis
1656            | Emerald
1657            | EmeraldTestnet
1658            | Evmos
1659            | EvmosTestnet
1660            | AnvilHardhat
1661            | Dev
1662            | GravityAlphaMainnet
1663            | GravityAlphaTestnetSepolia
1664            | Bob
1665            | BobSepolia
1666            | ZkSync
1667            | ZkSyncTestnet
1668            | FilecoinMainnet
1669            | LineaGoerli
1670            | FilecoinCalibrationTestnet
1671            | Viction
1672            | Elastos
1673            | Degen
1674            | Ronin
1675            | RoninTestnet
1676            | Cfx
1677            | CfxTestnet
1678            | Pulsechain
1679            | PulsechainTestnet
1680            | AutonomysNovaTestnet
1681            | Iotex
1682            | HappychainTestnet
1683            | SonicTestnet
1684            | Treasure
1685            | TreasureTopaz
1686            | BerachainBartio
1687            | BerachainArtio
1688            | TelosEvm
1689            | TelosEvmTestnet => return None,
1690        };
1691
1692        Some(api_key_name)
1693    }
1694
1695    /// Returns the chain's blockchain explorer's API key, from the environment variable with the
1696    /// name specified in [`etherscan_api_key_name`](NamedChain::etherscan_api_key_name).
1697    ///
1698    /// # Examples
1699    ///
1700    /// ```
1701    /// use alloy_chains::NamedChain;
1702    ///
1703    /// let chain = NamedChain::Mainnet;
1704    /// std::env::set_var(chain.etherscan_api_key_name().unwrap(), "KEY");
1705    /// assert_eq!(chain.etherscan_api_key().as_deref(), Some("KEY"));
1706    /// ```
1707    #[cfg(feature = "std")]
1708    pub fn etherscan_api_key(self) -> Option<String> {
1709        self.etherscan_api_key_name().and_then(|name| std::env::var(name).ok())
1710    }
1711
1712    /// Returns the address of the public DNS node list for the given chain.
1713    ///
1714    /// See also <https://github.com/ethereum/discv4-dns-lists>.
1715    pub fn public_dns_network_protocol(self) -> Option<String> {
1716        use NamedChain::*;
1717
1718        const DNS_PREFIX: &str = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@";
1719        if let Mainnet | Goerli | Sepolia | Ropsten | Rinkeby | Holesky = self {
1720            // `{DNS_PREFIX}all.{self.lower()}.ethdisco.net`
1721            let mut s = String::with_capacity(DNS_PREFIX.len() + 32);
1722            s.push_str(DNS_PREFIX);
1723            s.push_str("all.");
1724            let chain_str = self.as_ref();
1725            s.push_str(chain_str);
1726            let l = s.len();
1727            s[l - chain_str.len()..].make_ascii_lowercase();
1728            s.push_str(".ethdisco.net");
1729
1730            Some(s)
1731        } else {
1732            None
1733        }
1734    }
1735
1736    /// Returns the address of the most popular wrapped native token address for this chain, if it
1737    /// exists.
1738    ///
1739    /// Example:
1740    ///
1741    /// ```
1742    /// use alloy_chains::NamedChain;
1743    /// use alloy_primitives::address;
1744    ///
1745    /// let chain = NamedChain::Mainnet;
1746    /// assert_eq!(
1747    ///     chain.wrapped_native_token(),
1748    ///     Some(address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"))
1749    /// );
1750    /// ```
1751    pub const fn wrapped_native_token(self) -> Option<Address> {
1752        use NamedChain::*;
1753
1754        let addr = match self {
1755            Mainnet => address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
1756            Optimism => address!("4200000000000000000000000000000000000006"),
1757            BinanceSmartChain => address!("bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"),
1758            OpBNBMainnet => address!("4200000000000000000000000000000000000006"),
1759            Arbitrum => address!("82af49447d8a07e3bd95bd0d56f35241523fbab1"),
1760            Base => address!("4200000000000000000000000000000000000006"),
1761            Linea => address!("e5d7c2a44ffddf6b295a15c148167daaaf5cf34f"),
1762            Mantle => address!("deaddeaddeaddeaddeaddeaddeaddeaddead1111"),
1763            Blast => address!("4300000000000000000000000000000000000004"),
1764            Gnosis => address!("e91d153e0b41518a2ce8dd3d7944fa863463a97d"),
1765            Scroll => address!("5300000000000000000000000000000000000004"),
1766            Taiko => address!("a51894664a773981c6c112c43ce576f315d5b1b6"),
1767            Avalanche => address!("b31f66aa3c1e785363f0875a1b74e27b85fd66c7"),
1768            Polygon => address!("0d500b1d8e8ef31e21c99d1db9a6444d3adf1270"),
1769            Fantom => address!("21be370d5312f44cb42ce377bc9b8a0cef1a4c83"),
1770            Iotex => address!("a00744882684c3e4747faefd68d283ea44099d03"),
1771            Core => address!("40375C92d9FAf44d2f9db9Bd9ba41a3317a2404f"),
1772            Merlin => address!("F6D226f9Dc15d9bB51182815b320D3fBE324e1bA"),
1773            Bitlayer => address!("ff204e2681a6fa0e2c3fade68a1b28fb90e4fc5f"),
1774            ApeChain => address!("48b62137EdfA95a428D35C09E44256a739F6B557"),
1775            Vana => address!("00EDdD9621Fb08436d0331c149D1690909a5906d"),
1776            Zeta => address!("5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf"),
1777            Kaia => address!("19aac5f612f524b754ca7e7c41cbfa2e981a4432"),
1778            Story => address!("1514000000000000000000000000000000000000"),
1779            Treasure => address!("263d8f36bb8d0d9526255e205868c26690b04b88"),
1780            Superposition => address!("1fB719f10b56d7a85DCD32f27f897375fB21cfdd"),
1781            Sonic => address!("039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38"),
1782            Berachain => address!("6969696969696969696969696969696969696969"),
1783            Hyperliquid => address!("5555555555555555555555555555555555555555"),
1784            _ => return None,
1785        };
1786
1787        Some(addr)
1788    }
1789}
1790
1791#[cfg(test)]
1792mod tests {
1793    use super::*;
1794    use strum::{EnumCount, IntoEnumIterator};
1795
1796    #[allow(unused_imports)]
1797    use alloc::string::ToString;
1798
1799    #[test]
1800    #[cfg(feature = "serde")]
1801    fn default() {
1802        assert_eq!(serde_json::to_string(&NamedChain::default()).unwrap(), "\"mainnet\"");
1803    }
1804
1805    #[test]
1806    fn enum_iter() {
1807        assert_eq!(NamedChain::COUNT, NamedChain::iter().size_hint().0);
1808    }
1809
1810    #[test]
1811    fn roundtrip_string() {
1812        for chain in NamedChain::iter() {
1813            let chain_string = chain.to_string();
1814            assert_eq!(chain_string, format!("{chain}"));
1815            assert_eq!(chain_string.as_str(), chain.as_ref());
1816            #[cfg(feature = "serde")]
1817            assert_eq!(serde_json::to_string(&chain).unwrap(), format!("\"{chain_string}\""));
1818
1819            assert_eq!(chain_string.parse::<NamedChain>().unwrap(), chain);
1820        }
1821    }
1822
1823    #[test]
1824    #[cfg(feature = "serde")]
1825    fn roundtrip_serde() {
1826        for chain in NamedChain::iter() {
1827            let chain_string = serde_json::to_string(&chain).unwrap();
1828            let chain_string = chain_string.replace('-', "_");
1829            assert_eq!(serde_json::from_str::<'_, NamedChain>(&chain_string).unwrap(), chain);
1830        }
1831    }
1832
1833    #[test]
1834    fn aliases() {
1835        use NamedChain::*;
1836
1837        // kebab-case
1838        const ALIASES: &[(NamedChain, &[&str])] = &[
1839            (Mainnet, &["ethlive"]),
1840            (BinanceSmartChain, &["bsc", "bnb-smart-chain", "binance-smart-chain"]),
1841            (
1842                BinanceSmartChainTestnet,
1843                &["bsc-testnet", "bnb-smart-chain-testnet", "binance-smart-chain-testnet"],
1844            ),
1845            (Gnosis, &["gnosis", "gnosis-chain"]),
1846            (PolygonMumbai, &["mumbai"]),
1847            (PolygonZkEvm, &["zkevm", "polygon-zkevm"]),
1848            (PolygonZkEvmTestnet, &["zkevm-testnet", "polygon-zkevm-testnet"]),
1849            (AnvilHardhat, &["anvil", "hardhat"]),
1850            (AvalancheFuji, &["fuji"]),
1851            (ZkSync, &["zksync"]),
1852            (Mantle, &["mantle"]),
1853            (MantleTestnet, &["mantle-testnet"]),
1854            (MantleSepolia, &["mantle-sepolia"]),
1855            (GravityAlphaMainnet, &["gravity-alpha-mainnet"]),
1856            (GravityAlphaTestnetSepolia, &["gravity-alpha-testnet-sepolia"]),
1857            (Bob, &["bob"]),
1858            (BobSepolia, &["bob-sepolia"]),
1859            (HappychainTestnet, &["happychain-testnet"]),
1860            (Xai, &["xai"]),
1861            (XaiSepolia, &["xai-sepolia"]),
1862            (Base, &["base"]),
1863            (BaseGoerli, &["base-goerli"]),
1864            (BaseSepolia, &["base-sepolia"]),
1865            (Fraxtal, &["fraxtal"]),
1866            (FraxtalTestnet, &["fraxtal-testnet"]),
1867            (Ink, &["ink"]),
1868            (InkSepolia, &["ink-sepolia"]),
1869            (BlastSepolia, &["blast-sepolia"]),
1870            (Syndr, &["syndr"]),
1871            (SyndrSepolia, &["syndr-sepolia"]),
1872            (LineaGoerli, &["linea-goerli"]),
1873            (LineaSepolia, &["linea-sepolia"]),
1874            (AutonomysNovaTestnet, &["autonomys-nova-testnet"]),
1875            (Immutable, &["immutable"]),
1876            (ImmutableTestnet, &["immutable-testnet"]),
1877            (Soneium, &["soneium"]),
1878            (SoneiumMinatoTestnet, &["soneium-minato-testnet"]),
1879            (ApeChain, &["apechain"]),
1880            (Curtis, &["apechain-testnet", "curtis"]),
1881            (Treasure, &["treasure"]),
1882            (TreasureTopaz, &["treasure-topaz-testnet", "treasure-topaz"]),
1883            (BerachainArtio, &["berachain-artio-testnet", "berachain-artio"]),
1884            (BerachainBartio, &["berachain-bartio-testnet", "berachain-bartio"]),
1885            (SuperpositionTestnet, &["superposition-testnet"]),
1886            (Superposition, &["superposition"]),
1887            (Hyperliquid, &["hyperliquid"]),
1888        ];
1889
1890        for &(chain, aliases) in ALIASES {
1891            for &alias in aliases {
1892                let named = alias.parse::<NamedChain>().expect(alias);
1893                assert_eq!(named, chain);
1894
1895                #[cfg(feature = "serde")]
1896                {
1897                    assert_eq!(
1898                        serde_json::from_str::<NamedChain>(&format!("\"{alias}\"")).unwrap(),
1899                        chain
1900                    );
1901
1902                    assert_eq!(
1903                        serde_json::from_str::<NamedChain>(&format!("\"{named}\"")).unwrap(),
1904                        chain
1905                    );
1906                }
1907            }
1908        }
1909    }
1910
1911    #[test]
1912    #[cfg(feature = "serde")]
1913    fn serde_to_string_match() {
1914        for chain in NamedChain::iter() {
1915            let chain_serde = serde_json::to_string(&chain).unwrap();
1916            let chain_string = format!("\"{chain}\"");
1917            assert_eq!(chain_serde, chain_string);
1918        }
1919    }
1920
1921    #[test]
1922    fn test_dns_network() {
1923        let s = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net";
1924        assert_eq!(NamedChain::Mainnet.public_dns_network_protocol().unwrap(), s);
1925    }
1926
1927    #[test]
1928    fn ensure_no_trailing_etherscan_url_separator() {
1929        for chain in NamedChain::iter() {
1930            if let Some((api, base)) = chain.etherscan_urls() {
1931                assert!(!api.ends_with('/'), "{:?} api url has trailing /", chain);
1932                assert!(!base.ends_with('/'), "{:?} base url has trailing /", chain);
1933            }
1934        }
1935    }
1936}