Skip to main content

near_kit/types/
network.rs

1//! Chain identification for NEAR Protocol.
2
3use std::fmt;
4
5/// Identifies the NEAR chain the client is connected to.
6///
7/// This is a string-based newtype that replaces the former `Network` enum,
8/// allowing any chain identifier (not just the hardcoded variants).
9///
10/// Use the named constructors for well-known chains, or [`ChainId::new`]
11/// for custom ones.
12///
13/// # Examples
14///
15/// ```
16/// use near_kit::ChainId;
17///
18/// let mainnet = ChainId::mainnet();
19/// assert!(mainnet.is_mainnet());
20/// assert_eq!(mainnet.as_str(), "mainnet");
21///
22/// let custom = ChainId::new("localnet");
23/// assert_eq!(custom.as_str(), "localnet");
24/// ```
25#[derive(Clone, Debug, PartialEq, Eq, Hash)]
26pub struct ChainId(String);
27
28impl ChainId {
29    /// Create a chain ID from any string.
30    pub fn new(id: impl Into<String>) -> Self {
31        Self(id.into())
32    }
33
34    /// NEAR mainnet.
35    pub fn mainnet() -> Self {
36        Self("mainnet".to_string())
37    }
38
39    /// NEAR testnet.
40    pub fn testnet() -> Self {
41        Self("testnet".to_string())
42    }
43
44    /// Returns true if this is mainnet.
45    pub fn is_mainnet(&self) -> bool {
46        self.0 == "mainnet"
47    }
48
49    /// Returns true if this is testnet.
50    pub fn is_testnet(&self) -> bool {
51        self.0 == "testnet"
52    }
53
54    /// Returns the chain identifier as a string slice.
55    pub fn as_str(&self) -> &str {
56        &self.0
57    }
58}
59
60impl Default for ChainId {
61    fn default() -> Self {
62        Self::mainnet()
63    }
64}
65
66impl AsRef<str> for ChainId {
67    fn as_ref(&self) -> &str {
68        &self.0
69    }
70}
71
72impl fmt::Display for ChainId {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.write_str(&self.0)
75    }
76}
77
78impl From<&str> for ChainId {
79    fn from(s: &str) -> Self {
80        Self::new(s)
81    }
82}
83
84impl From<String> for ChainId {
85    fn from(s: String) -> Self {
86        Self::new(s)
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_chain_id_display() {
96        assert_eq!(ChainId::mainnet().to_string(), "mainnet");
97        assert_eq!(ChainId::testnet().to_string(), "testnet");
98        assert_eq!(ChainId::new("custom").to_string(), "custom");
99    }
100
101    #[test]
102    fn test_chain_id_predicates() {
103        assert!(ChainId::mainnet().is_mainnet());
104        assert!(!ChainId::mainnet().is_testnet());
105
106        assert!(ChainId::testnet().is_testnet());
107        assert!(!ChainId::testnet().is_mainnet());
108    }
109
110    #[test]
111    fn test_default_is_mainnet() {
112        assert_eq!(ChainId::default(), ChainId::mainnet());
113    }
114
115    #[test]
116    fn test_as_str() {
117        assert_eq!(ChainId::mainnet().as_str(), "mainnet");
118        assert_eq!(ChainId::new("localnet").as_str(), "localnet");
119    }
120
121    #[test]
122    fn test_as_ref_str() {
123        let chain_id = ChainId::mainnet();
124        let s: &str = chain_id.as_ref();
125        assert_eq!(s, "mainnet");
126    }
127
128    #[test]
129    fn test_custom_chain_id() {
130        let chain_id = ChainId::new("my-custom-network");
131        assert_eq!(chain_id.as_str(), "my-custom-network");
132        assert!(!chain_id.is_mainnet());
133        assert!(!chain_id.is_testnet());
134    }
135
136    #[test]
137    fn test_from_str() {
138        let chain_id: ChainId = "mainnet".into();
139        assert!(chain_id.is_mainnet());
140    }
141
142    #[test]
143    fn test_from_string() {
144        let chain_id: ChainId = String::from("testnet").into();
145        assert!(chain_id.is_testnet());
146    }
147}