starknet_devnet_types/
chain_id.rs

1use std::fmt::Display;
2use std::str::FromStr;
3
4use starknet_rs_core::chain_id::{MAINNET, SEPOLIA};
5use starknet_rs_core::utils::{cairo_short_string_to_felt, parse_cairo_short_string};
6use starknet_types_core::felt::Felt;
7
8use crate::error::ConversionError;
9
10#[derive(Clone, Copy, Debug)]
11pub enum ChainId {
12    Mainnet,
13    Testnet,
14    Custom(Felt),
15}
16
17impl ChainId {
18    /// Used only in tests.
19    /// It was imported from `starknet_rs_core::chain_id`, but now gives a deprecation warning
20    /// defined [here](https://github.com/xJonathanLEI/starknet-rs/blob/f6d339c6b897fb38c839485608ca2fe374a6275d/starknet-core/src/chain_id.rs#L10).
21    /// Instead of ignoring the warning in two places, it's defined here.
22    const TESTNET: Felt = Felt::from_raw([
23        398700013197595345,
24        18446744073709551615,
25        18446744073709548950,
26        3753493103916128178,
27    ]);
28
29    pub const fn goerli_legacy_id() -> Felt {
30        Self::TESTNET
31    }
32
33    pub fn to_felt(&self) -> Felt {
34        Felt::from(self)
35    }
36}
37
38impl Display for ChainId {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        let felt = Felt::from(self);
41        let str = parse_cairo_short_string(&felt).map_err(|_| std::fmt::Error)?;
42        f.write_str(&str)
43    }
44}
45
46impl FromStr for ChainId {
47    type Err = ConversionError;
48
49    fn from_str(s: &str) -> Result<Self, Self::Err> {
50        let uppercase_chain_id_str = s.to_ascii_uppercase();
51        let chain_id = match uppercase_chain_id_str.as_str() {
52            "MAINNET" => ChainId::Mainnet,
53            "TESTNET" => ChainId::Testnet,
54            _ => {
55                let felt = cairo_short_string_to_felt(&uppercase_chain_id_str)
56                    .map_err(|err| ConversionError::OutOfRangeError(err.to_string()))?;
57                ChainId::Custom(felt)
58            }
59        };
60
61        Ok(chain_id)
62    }
63}
64
65impl From<ChainId> for Felt {
66    fn from(value: ChainId) -> Self {
67        match value {
68            ChainId::Mainnet => MAINNET,
69            ChainId::Testnet => SEPOLIA,
70            ChainId::Custom(felt) => felt,
71        }
72    }
73}
74
75impl From<&ChainId> for Felt {
76    fn from(value: &ChainId) -> Self {
77        match value {
78            ChainId::Mainnet => MAINNET,
79            ChainId::Testnet => SEPOLIA,
80            ChainId::Custom(felt) => *felt,
81        }
82    }
83}
84
85impl From<Felt> for ChainId {
86    fn from(value: Felt) -> Self {
87        if value == MAINNET {
88            ChainId::Mainnet
89        } else if value == SEPOLIA {
90            ChainId::Testnet
91        } else {
92            ChainId::Custom(value)
93        }
94    }
95}
96
97impl From<ChainId> for starknet_api::core::ChainId {
98    fn from(value: ChainId) -> Self {
99        match value {
100            ChainId::Mainnet => Self::Mainnet,
101            ChainId::Testnet => Self::Sepolia,
102            ChainId::Custom(_) => Self::Other(format!("{value}")),
103        }
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::ChainId;
110
111    #[test]
112    fn check_conversion_to_starknet_api() {
113        let t = ChainId::Testnet;
114        let sat: starknet_api::core::ChainId = t.into();
115
116        assert_eq!(t.to_felt().to_hex_string(), sat.as_hex());
117    }
118
119    #[test]
120    fn test_display() {
121        assert_eq!(format!("{}", ChainId::Mainnet), "SN_MAIN");
122        assert_eq!(format!("{}", ChainId::Testnet), "SN_SEPOLIA");
123    }
124}