wormhole_supported_chains/
lib.rs

1//! Provide Types and Data about Wormhole's supported chains.
2
3use std::{fmt, str::FromStr};
4
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use thiserror::Error;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub enum Chain {
10    /// In the wormhole wire format, 0 indicates that a message is for any destination chain, it is
11    /// represented here as `Any`.
12    Any,
13
14    /// Chains
15    Solana,
16    Ethereum,
17    Terra,
18    Bsc,
19    Polygon,
20    Avalanche,
21    Oasis,
22    Algorand,
23    Aurora,
24    Fantom,
25    Karura,
26    Acala,
27    Klaytn,
28    Celo,
29    Near,
30    Moonbeam,
31    Neon,
32    Terra2,
33    Injective,
34    Osmosis,
35    Sui,
36    Aptos,
37    Arbitrum,
38    Optimism,
39    Gnosis,
40    Pythnet,
41    Xpla,
42    Btc,
43    Base,
44    Sei,
45    Rootstock,
46    Scroll,
47    Mantle,
48    Wormchain,
49    CosmosHub,
50    Evmos,
51    Kujira,
52    Neutron,
53    Celestia,
54    Stargaze,
55    Seda,
56    Dymension,
57    Sepolia,
58
59    // Allow arbitrary u16s to support future chains.
60    Unknown(u16),
61}
62
63impl From<u16> for Chain {
64    fn from(other: u16) -> Chain {
65        match other {
66            0 => Chain::Any,
67            1 => Chain::Solana,
68            2 => Chain::Ethereum,
69            3 => Chain::Terra,
70            4 => Chain::Bsc,
71            5 => Chain::Polygon,
72            6 => Chain::Avalanche,
73            7 => Chain::Oasis,
74            8 => Chain::Algorand,
75            9 => Chain::Aurora,
76            10 => Chain::Fantom,
77            11 => Chain::Karura,
78            12 => Chain::Acala,
79            13 => Chain::Klaytn,
80            14 => Chain::Celo,
81            15 => Chain::Near,
82            16 => Chain::Moonbeam,
83            17 => Chain::Neon,
84            18 => Chain::Terra2,
85            19 => Chain::Injective,
86            20 => Chain::Osmosis,
87            21 => Chain::Sui,
88            22 => Chain::Aptos,
89            23 => Chain::Arbitrum,
90            24 => Chain::Optimism,
91            25 => Chain::Gnosis,
92            26 => Chain::Pythnet,
93            28 => Chain::Xpla,
94            29 => Chain::Btc,
95            30 => Chain::Base,
96            32 => Chain::Sei,
97            33 => Chain::Rootstock,
98            34 => Chain::Scroll,
99            35 => Chain::Mantle,
100            3104 => Chain::Wormchain,
101            4000 => Chain::CosmosHub,
102            4001 => Chain::Evmos,
103            4002 => Chain::Kujira,
104            4003 => Chain::Neutron,
105            4004 => Chain::Celestia,
106            4005 => Chain::Stargaze,
107            4006 => Chain::Seda,
108            4007 => Chain::Dymension,
109            10002 => Chain::Sepolia,
110            c => Chain::Unknown(c),
111        }
112    }
113}
114
115impl From<Chain> for u16 {
116    fn from(other: Chain) -> u16 {
117        match other {
118            Chain::Any => 0,
119            Chain::Solana => 1,
120            Chain::Ethereum => 2,
121            Chain::Terra => 3,
122            Chain::Bsc => 4,
123            Chain::Polygon => 5,
124            Chain::Avalanche => 6,
125            Chain::Oasis => 7,
126            Chain::Algorand => 8,
127            Chain::Aurora => 9,
128            Chain::Fantom => 10,
129            Chain::Karura => 11,
130            Chain::Acala => 12,
131            Chain::Klaytn => 13,
132            Chain::Celo => 14,
133            Chain::Near => 15,
134            Chain::Moonbeam => 16,
135            Chain::Neon => 17,
136            Chain::Terra2 => 18,
137            Chain::Injective => 19,
138            Chain::Osmosis => 20,
139            Chain::Sui => 21,
140            Chain::Aptos => 22,
141            Chain::Arbitrum => 23,
142            Chain::Optimism => 24,
143            Chain::Gnosis => 25,
144            Chain::Pythnet => 26,
145            Chain::Xpla => 28,
146            Chain::Btc => 29,
147            Chain::Base => 30,
148            Chain::Sei => 32,
149            Chain::Rootstock => 33,
150            Chain::Scroll => 34,
151            Chain::Mantle => 35,
152            Chain::Wormchain => 3104,
153            Chain::CosmosHub => 4000,
154            Chain::Evmos => 4001,
155            Chain::Kujira => 4002,
156            Chain::Neutron => 4003,
157            Chain::Celestia => 4004,
158            Chain::Stargaze => 4005,
159            Chain::Seda => 4006,
160            Chain::Dymension => 4007,
161            Chain::Sepolia => 10002,
162            Chain::Unknown(c) => c,
163        }
164    }
165}
166
167impl fmt::Display for Chain {
168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169        match self {
170            Self::Any => f.write_str("Any"),
171            Self::Solana => f.write_str("Solana"),
172            Self::Ethereum => f.write_str("Ethereum"),
173            Self::Terra => f.write_str("Terra"),
174            Self::Bsc => f.write_str("Bsc"),
175            Self::Polygon => f.write_str("Polygon"),
176            Self::Avalanche => f.write_str("Avalanche"),
177            Self::Oasis => f.write_str("Oasis"),
178            Self::Algorand => f.write_str("Algorand"),
179            Self::Aurora => f.write_str("Aurora"),
180            Self::Fantom => f.write_str("Fantom"),
181            Self::Karura => f.write_str("Karura"),
182            Self::Acala => f.write_str("Acala"),
183            Self::Klaytn => f.write_str("Klaytn"),
184            Self::Celo => f.write_str("Celo"),
185            Self::Near => f.write_str("Near"),
186            Self::Moonbeam => f.write_str("Moonbeam"),
187            Self::Neon => f.write_str("Neon"),
188            Self::Terra2 => f.write_str("Terra2"),
189            Self::Injective => f.write_str("Injective"),
190            Self::Osmosis => f.write_str("Osmosis"),
191            Self::Sui => f.write_str("Sui"),
192            Self::Aptos => f.write_str("Aptos"),
193            Self::Arbitrum => f.write_str("Arbitrum"),
194            Self::Optimism => f.write_str("Optimism"),
195            Self::Gnosis => f.write_str("Gnosis"),
196            Self::Pythnet => f.write_str("Pythnet"),
197            Self::Xpla => f.write_str("Xpla"),
198            Self::Btc => f.write_str("Btc"),
199            Self::Base => f.write_str("Base"),
200            Self::Sei => f.write_str("Sei"),
201            Self::Rootstock => f.write_str("Rootstock"),
202            Self::Scroll => f.write_str("Scroll"),
203            Self::Mantle => f.write_str("Mantle"),
204            Self::Sepolia => f.write_str("Sepolia"),
205            Self::Wormchain => f.write_str("Wormchain"),
206            Self::CosmosHub => f.write_str("CosmosHub"),
207            Self::Evmos => f.write_str("Evmos"),
208            Self::Kujira => f.write_str("Kujira"),
209            Self::Neutron => f.write_str("Neutron"),
210            Self::Celestia => f.write_str("Celestia"),
211            Self::Stargaze => f.write_str("Stargaze"),
212            Self::Seda => f.write_str("Seda"),
213            Self::Dymension => f.write_str("Dymension"),
214            Self::Unknown(v) => write!(f, "Unknown({v})"),
215        }
216    }
217}
218
219#[derive(Debug, Error)]
220#[error("invalid chain: {0}")]
221pub struct InvalidChainError(String);
222
223impl FromStr for Chain {
224    type Err = InvalidChainError;
225
226    fn from_str(s: &str) -> Result<Self, Self::Err> {
227        match s {
228            "Any" | "any" | "ANY" => Ok(Chain::Any),
229            "Solana" | "solana" | "SOLANA" => Ok(Chain::Solana),
230            "Ethereum" | "ethereum" | "ETHEREUM" => Ok(Chain::Ethereum),
231            "Terra" | "terra" | "TERRA" => Ok(Chain::Terra),
232            "Bsc" | "bsc" | "BSC" => Ok(Chain::Bsc),
233            "Polygon" | "polygon" | "POLYGON" => Ok(Chain::Polygon),
234            "Avalanche" | "avalanche" | "AVALANCHE" => Ok(Chain::Avalanche),
235            "Oasis" | "oasis" | "OASIS" => Ok(Chain::Oasis),
236            "Algorand" | "algorand" | "ALGORAND" => Ok(Chain::Algorand),
237            "Aurora" | "aurora" | "AURORA" => Ok(Chain::Aurora),
238            "Fantom" | "fantom" | "FANTOM" => Ok(Chain::Fantom),
239            "Karura" | "karura" | "KARURA" => Ok(Chain::Karura),
240            "Acala" | "acala" | "ACALA" => Ok(Chain::Acala),
241            "Klaytn" | "klaytn" | "KLAYTN" => Ok(Chain::Klaytn),
242            "Celo" | "celo" | "CELO" => Ok(Chain::Celo),
243            "Near" | "near" | "NEAR" => Ok(Chain::Near),
244            "Moonbeam" | "moonbeam" | "MOONBEAM" => Ok(Chain::Moonbeam),
245            "Neon" | "neon" | "NEON" => Ok(Chain::Neon),
246            "Terra2" | "terra2" | "TERRA2" => Ok(Chain::Terra2),
247            "Injective" | "injective" | "INJECTIVE" => Ok(Chain::Injective),
248            "Osmosis" | "osmosis" | "OSMOSIS" => Ok(Chain::Osmosis),
249            "Sui" | "sui" | "SUI" => Ok(Chain::Sui),
250            "Aptos" | "aptos" | "APTOS" => Ok(Chain::Aptos),
251            "Arbitrum" | "arbitrum" | "ARBITRUM" => Ok(Chain::Arbitrum),
252            "Optimism" | "optimism" | "OPTIMISM" => Ok(Chain::Optimism),
253            "Gnosis" | "gnosis" | "GNOSIS" => Ok(Chain::Gnosis),
254            "Pythnet" | "pythnet" | "PYTHNET" => Ok(Chain::Pythnet),
255            "Xpla" | "xpla" | "XPLA" => Ok(Chain::Xpla),
256            "Btc" | "btc" | "BTC" => Ok(Chain::Btc),
257            "Base" | "base" | "BASE" => Ok(Chain::Base),
258            "Sei" | "sei" | "SEI" => Ok(Chain::Sei),
259            "Rootstock" | "rootstock" | "ROOTSTOCK" => Ok(Chain::Rootstock),
260            "Scroll" | "scroll" | "SCROLL" => Ok(Chain::Scroll),
261            "Mantle" | "mantle" | "MANTLE" => Ok(Chain::Mantle),
262            "Sepolia" | "sepolia" | "SEPOLIA" => Ok(Chain::Sepolia),
263            "Wormchain" | "wormchain" | "WORMCHAIN" => Ok(Chain::Wormchain),
264            "CosmosHub" | "cosmoshub" | "COSMOSHUB" => Ok(Chain::CosmosHub),
265            "Evmos" | "evmos" | "EVMOS" => Ok(Chain::Evmos),
266            "Kujira" | "kujira" | "KUJIRA" => Ok(Chain::Kujira),
267            "Neutron" | "neutron" | "NEUTRON" => Ok(Chain::Neutron),
268            "Celestia" | "celestia" | "CELESTIA" => Ok(Chain::Celestia),
269            "Stargaze" | "stargaze" | "STARGAZE" => Ok(Chain::Stargaze),
270            "Seda" | "seda" | "SEDA" => Ok(Chain::Seda),
271            "Dymension" | "dymension" | "DYMENSION" => Ok(Chain::Dymension),
272            _ => {
273                let mut parts = s.split(&['(', ')']);
274                let _ = parts
275                    .next()
276                    .filter(|name| name.eq_ignore_ascii_case("unknown"))
277                    .ok_or_else(|| InvalidChainError(s.into()))?;
278
279                parts
280                    .next()
281                    .and_then(|v| v.parse::<u16>().ok())
282                    .map(Chain::from)
283                    .ok_or_else(|| InvalidChainError(s.into()))
284            }
285        }
286    }
287}
288
289impl Default for Chain {
290    fn default() -> Self {
291        Self::Any
292    }
293}
294
295impl Serialize for Chain {
296    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
297    where
298        S: Serializer,
299    {
300        serializer.serialize_u16((*self).into())
301    }
302}
303
304impl<'de> Deserialize<'de> for Chain {
305    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
306    where
307        D: Deserializer<'de>,
308    {
309        <u16 as Deserialize>::deserialize(deserializer).map(Self::from)
310    }
311}
312
313#[cfg(test)]
314mod test {
315    use super::*;
316
317    #[test]
318    fn isomorphic_from() {
319        for i in 0u16..=u16::MAX {
320            assert_eq!(i, u16::from(Chain::from(i)));
321        }
322    }
323
324    #[test]
325    fn isomorphic_display() {
326        for i in 0u16..=u16::MAX {
327            let c = Chain::from(i);
328            assert_eq!(c, c.to_string().parse().unwrap());
329        }
330    }
331}