Skip to main content

aptos_sdk/types/
chain_id.rs

1//! Chain ID type.
2//!
3//! The chain ID identifies which Aptos network a transaction is intended for,
4//! preventing replay attacks across networks.
5
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9/// A chain identifier for an Aptos network.
10///
11/// The chain ID is included in every transaction to ensure transactions
12/// cannot be replayed across different networks.
13///
14/// # Known Chain IDs
15///
16/// - Mainnet: 1
17/// - Testnet: 2  
18/// - Devnet: varies (typically 165)
19/// - Local: 4 (default for local testing)
20///
21/// # Example
22///
23/// ```rust
24/// use aptos_sdk::ChainId;
25///
26/// let mainnet = ChainId::mainnet();
27/// assert_eq!(mainnet.id(), 1);
28///
29/// let custom = ChainId::new(42);
30/// assert_eq!(custom.id(), 42);
31/// ```
32#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
33#[serde(transparent)]
34pub struct ChainId(u8);
35
36impl ChainId {
37    /// Creates a new chain ID.
38    pub const fn new(id: u8) -> Self {
39        Self(id)
40    }
41
42    /// Returns the chain ID for mainnet (1).
43    pub const fn mainnet() -> Self {
44        Self(1)
45    }
46
47    /// Returns the chain ID for testnet (2).
48    pub const fn testnet() -> Self {
49        Self(2)
50    }
51
52    /// Returns the numeric chain ID value.
53    pub const fn id(&self) -> u8 {
54        self.0
55    }
56
57    /// Returns true if this is the mainnet chain ID.
58    pub const fn is_mainnet(&self) -> bool {
59        self.0 == 1
60    }
61
62    /// Returns true if this is the testnet chain ID.
63    pub const fn is_testnet(&self) -> bool {
64        self.0 == 2
65    }
66}
67
68impl Default for ChainId {
69    fn default() -> Self {
70        Self::testnet()
71    }
72}
73
74impl fmt::Debug for ChainId {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        write!(f, "ChainId({})", self.0)
77    }
78}
79
80impl fmt::Display for ChainId {
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        write!(f, "{}", self.0)
83    }
84}
85
86impl From<u8> for ChainId {
87    fn from(id: u8) -> Self {
88        Self(id)
89    }
90}
91
92impl From<ChainId> for u8 {
93    fn from(chain_id: ChainId) -> Self {
94        chain_id.0
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_known_chain_ids() {
104        assert_eq!(ChainId::mainnet().id(), 1);
105        assert_eq!(ChainId::testnet().id(), 2);
106    }
107
108    #[test]
109    fn test_is_mainnet_testnet() {
110        assert!(ChainId::mainnet().is_mainnet());
111        assert!(!ChainId::mainnet().is_testnet());
112        assert!(ChainId::testnet().is_testnet());
113        assert!(!ChainId::testnet().is_mainnet());
114    }
115
116    #[test]
117    fn test_custom_chain_id() {
118        let custom = ChainId::new(42);
119        assert_eq!(custom.id(), 42);
120        assert!(!custom.is_mainnet());
121        assert!(!custom.is_testnet());
122    }
123
124    #[test]
125    fn test_json_serialization() {
126        let chain_id = ChainId::mainnet();
127        let json = serde_json::to_string(&chain_id).unwrap();
128        assert_eq!(json, "1");
129
130        let parsed: ChainId = serde_json::from_str(&json).unwrap();
131        assert_eq!(parsed, chain_id);
132    }
133
134    #[test]
135    fn test_default() {
136        let default = ChainId::default();
137        assert_eq!(default, ChainId::testnet());
138    }
139
140    #[test]
141    fn test_debug() {
142        let chain_id = ChainId::mainnet();
143        let debug = format!("{chain_id:?}");
144        assert_eq!(debug, "ChainId(1)");
145    }
146
147    #[test]
148    fn test_display() {
149        let chain_id = ChainId::testnet();
150        let display = format!("{chain_id}");
151        assert_eq!(display, "2");
152    }
153
154    #[test]
155    fn test_from_u8() {
156        let chain_id: ChainId = 3u8.into();
157        assert_eq!(chain_id.id(), 3);
158    }
159
160    #[test]
161    fn test_into_u8() {
162        let chain_id = ChainId::new(5);
163        let id: u8 = chain_id.into();
164        assert_eq!(id, 5);
165    }
166
167    #[test]
168    fn test_equality() {
169        assert_eq!(ChainId::new(1), ChainId::mainnet());
170        assert_ne!(ChainId::mainnet(), ChainId::testnet());
171    }
172
173    #[test]
174    fn test_hash() {
175        use std::collections::HashSet;
176        let mut set = HashSet::new();
177        set.insert(ChainId::mainnet());
178        set.insert(ChainId::testnet());
179        assert_eq!(set.len(), 2);
180        assert!(set.contains(&ChainId::new(1)));
181    }
182}