1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(rename_all = "lowercase")]
10pub enum ChainFamily {
11 Evm,
12 Solana,
13 Cosmos,
14 Sui,
15 Aptos,
16 Custom(String),
18}
19
20impl fmt::Display for ChainFamily {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 ChainFamily::Evm => write!(f, "evm"),
24 ChainFamily::Solana => write!(f, "solana"),
25 ChainFamily::Cosmos => write!(f, "cosmos"),
26 ChainFamily::Sui => write!(f, "sui"),
27 ChainFamily::Aptos => write!(f, "aptos"),
28 ChainFamily::Custom(s) => write!(f, "{s}"),
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
36pub struct ChainId {
37 pub slug: String,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub evm_chain_id: Option<u64>,
42 pub family: ChainFamily,
44}
45
46impl ChainId {
47 pub fn evm(slug: impl Into<String>, chain_id: u64) -> Self {
48 Self {
49 slug: slug.into(),
50 evm_chain_id: Some(chain_id),
51 family: ChainFamily::Evm,
52 }
53 }
54
55 pub fn solana(slug: impl Into<String>) -> Self {
56 Self {
57 slug: slug.into(),
58 evm_chain_id: None,
59 family: ChainFamily::Solana,
60 }
61 }
62
63 pub fn cosmos(slug: impl Into<String>) -> Self {
64 Self {
65 slug: slug.into(),
66 evm_chain_id: None,
67 family: ChainFamily::Cosmos,
68 }
69 }
70
71 pub fn custom(slug: impl Into<String>, family_name: impl Into<String>) -> Self {
72 let slug = slug.into();
73 Self {
74 slug,
75 evm_chain_id: None,
76 family: ChainFamily::Custom(family_name.into()),
77 }
78 }
79}
80
81impl fmt::Display for ChainId {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(f, "{}", self.slug)
84 }
85}
86
87pub mod chains {
89 use super::ChainId;
90
91 pub fn ethereum() -> ChainId { ChainId::evm("ethereum", 1) }
92 pub fn arbitrum() -> ChainId { ChainId::evm("arbitrum", 42161) }
93 pub fn base() -> ChainId { ChainId::evm("base", 8453) }
94 pub fn polygon() -> ChainId { ChainId::evm("polygon", 137) }
95 pub fn optimism() -> ChainId { ChainId::evm("optimism", 10) }
96 pub fn avalanche() -> ChainId { ChainId::evm("avalanche", 43114) }
97 pub fn bsc() -> ChainId { ChainId::evm("bsc", 56) }
98 pub fn solana_mainnet() -> ChainId { ChainId::solana("solana-mainnet") }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn chain_id_display() {
107 assert_eq!(chains::ethereum().to_string(), "ethereum");
108 assert_eq!(chains::arbitrum().to_string(), "arbitrum");
109 }
110
111 #[test]
112 fn chain_family_serde() {
113 let json = serde_json::to_string(&ChainFamily::Evm).unwrap();
114 assert_eq!(json, "\"evm\"");
115 let parsed: ChainFamily = serde_json::from_str(&json).unwrap();
116 assert_eq!(parsed, ChainFamily::Evm);
117 }
118}