pragma_common/web3/
chain.rs

1use std::str::FromStr;
2
3use super::{Token, APT, AVAX, BNB, ETH, POL, SOL, SUI, USDC, USDT, WLD, XDAI};
4
5#[derive(Debug, thiserror::Error)]
6pub enum ChainError {
7    #[error("Unknown chain: {0}")]
8    UnknownChain(String),
9}
10
11#[derive(Debug, Copy, Hash, Eq, Clone, PartialEq, PartialOrd, Ord)]
12#[cfg_attr(
13    feature = "serde",
14    derive(serde::Serialize, serde::Deserialize),
15    serde(rename_all = "lowercase")
16)]
17#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
18pub enum Chain {
19    Starknet,
20    Solana,
21    Sui,
22    Aptos,
23    // Evm chains
24    Ethereum,
25    Base,
26    Arbitrum,
27    Optimism,
28    ZkSync,
29    Polygon,
30    Bnb,
31    Avalanche,
32    Gnosis,
33    Worldchain,
34}
35
36impl Chain {
37    pub fn from_chain_id(id: u64) -> Option<Self> {
38        match id {
39            1 => Some(Self::Ethereum),
40            10 => Some(Self::Optimism),
41            137 => Some(Self::Polygon),
42            324 => Some(Self::ZkSync),
43            8453 => Some(Self::Base),
44            42161 => Some(Self::Arbitrum),
45            56 => Some(Self::Bnb),
46            43114 => Some(Self::Avalanche),
47            100 => Some(Self::Gnosis),
48            480 => Some(Self::Worldchain),
49            _ => None,
50        }
51    }
52
53    #[must_use]
54    pub const fn chain_id(&self) -> Option<u64> {
55        match self {
56            Self::Ethereum => Some(1),
57            Self::Optimism => Some(10),
58            Self::Polygon => Some(137),
59            Self::ZkSync => Some(324),
60            Self::Base => Some(8453),
61            Self::Arbitrum => Some(42161),
62            Self::Bnb => Some(56),
63            Self::Avalanche => Some(43114),
64            Self::Gnosis => Some(100),
65            Self::Worldchain => Some(480),
66            _ => None,
67        }
68    }
69
70    pub const fn is_evm(&self) -> bool {
71        matches!(
72            self,
73            Self::Ethereum
74                | Self::Optimism
75                | Self::Polygon
76                | Self::ZkSync
77                | Self::Base
78                | Self::Arbitrum
79                | Self::Bnb
80                | Self::Avalanche
81                | Self::Gnosis
82                | Self::Worldchain
83        )
84    }
85
86    #[must_use]
87    /// Returns the gas token for the chain
88    pub fn gas_token(&self) -> Token {
89        match self {
90            Self::Ethereum
91            | Self::Base
92            | Self::Optimism
93            | Self::Starknet
94            | Self::Arbitrum
95            | Self::ZkSync => ETH(),
96            Self::Solana => SOL(),
97            Self::Sui => SUI(),
98            Self::Aptos => APT(),
99            Self::Polygon => POL(),
100            Self::Bnb => BNB(),
101            Self::Avalanche => AVAX(),
102            Self::Gnosis => XDAI(),
103            Self::Worldchain => WLD(),
104        }
105    }
106
107    /// Returns the main stablecoin for the chain (or None if there is none)
108    pub fn usd_token(&self) -> Token {
109        match self {
110            Self::Polygon | Self::Optimism | Self::Arbitrum | Self::Gnosis | Self::Aptos => USDT(),
111            Self::Ethereum
112            | Self::Base
113            | Self::ZkSync
114            | Self::Bnb
115            | Self::Avalanche
116            | Self::Worldchain
117            | Self::Solana
118            | Self::Starknet
119            | Self::Sui => USDC(),
120        }
121    }
122}
123
124impl std::fmt::Display for Chain {
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        write!(f, "{self:?}")
127    }
128}
129
130impl FromStr for Chain {
131    type Err = ChainError;
132
133    fn from_str(s: &str) -> Result<Self, Self::Err> {
134        match s.to_lowercase().as_str() {
135            "starknet" => Ok(Self::Starknet),
136            "solana" => Ok(Self::Solana),
137            "sui" => Ok(Self::Sui),
138            "aptos" => Ok(Self::Aptos),
139            "ethereum" => Ok(Self::Ethereum),
140            "base" => Ok(Self::Base),
141            "arbitrum" => Ok(Self::Arbitrum),
142            "optimism" => Ok(Self::Optimism),
143            "zksync" => Ok(Self::ZkSync),
144            "polygon" => Ok(Self::Polygon),
145            "bnb" => Ok(Self::Bnb),
146            "avalanche" => Ok(Self::Avalanche),
147            "gnosis" => Ok(Self::Gnosis),
148            "worldchain" => Ok(Self::Worldchain),
149            _ => Err(ChainError::UnknownChain(s.to_string())),
150        }
151    }
152}