1use std::{
19 fmt::{Display, Formatter},
20 sync::Arc,
21};
22
23use serde::{Deserialize, Serialize};
24use strum::{Display, EnumString};
25
26#[derive(
28 Debug,
29 Clone,
30 Copy,
31 Hash,
32 PartialOrd,
33 PartialEq,
34 Ord,
35 Eq,
36 Display,
37 EnumString,
38 Serialize,
39 Deserialize,
40)]
41#[non_exhaustive]
42pub enum Blockchain {
43 Abstract,
44 Arbitrum,
45 ArbitrumNova,
46 ArbitrumSepolia,
47 Aurora,
48 Avalanche,
49 Base,
50 BaseSepolia,
51 Berachain,
52 BerachainBartio,
53 Blast,
54 BlastSepolia,
55 Boba,
56 Bsc,
57 BscTestnet,
58 Celo,
59 Chiliz,
60 CitreaTestnet,
61 Curtis,
62 Cyber,
63 Darwinia,
64 Ethereum,
65 Fantom,
66 Flare,
67 Fraxtal,
68 Fuji,
69 GaladrielDevnet,
70 Gnosis,
71 GnosisChiado,
72 GnosisTraces,
73 HarmonyShard0,
74 Holesky,
75 HoleskyTokenTest,
76 Hyperliquid,
77 HyperliquidTemp,
78 Ink,
79 InternalTestChain,
80 Kroma,
81 Linea,
82 Lisk,
83 Lukso,
84 LuksoTestnet,
85 Manta,
86 Mantle,
87 MegaethTestnet,
88 Merlin,
89 Metall2,
90 Metis,
91 MevCommit,
92 Mode,
93 MonadTestnet,
94 MonadTestnetBackup,
95 MoonbaseAlpha,
96 Moonbeam,
97 Morph,
98 MorphHolesky,
99 Opbnb,
100 Optimism,
101 OptimismSepolia,
102 PharosDevnet,
103 Polygon,
104 PolygonAmoy,
105 PolygonZkEvm,
106 Rootstock,
107 Saakuru,
108 Scroll,
109 Sepolia,
110 ShimmerEvm,
111 Soneium,
112 Sophon,
113 SophonTestnet,
114 Superseed,
115 Unichain,
116 UnichainSepolia,
117 Xdc,
118 XdcTestnet,
119 Zeta,
120 Zircuit,
121 ZKsync,
122 Zora,
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
127pub struct Chain {
128 pub name: Blockchain,
130 pub chain_id: u32,
132 pub hypersync_url: String,
134 pub rpc_url: Option<String>,
136 pub native_currency_decimals: u8,
138}
139
140pub type SharedChain = Arc<Chain>;
142
143impl Chain {
144 pub fn new(name: Blockchain, chain_id: u32) -> Self {
146 Self {
147 chain_id,
148 name,
149 hypersync_url: format!("https://{chain_id}.hypersync.xyz"),
150 rpc_url: None,
151 native_currency_decimals: 18, }
153 }
154
155 pub fn set_rpc_url(&mut self, rpc: String) {
157 self.rpc_url = Some(rpc);
158 }
159
160 pub fn from_chain_id(chain_id: u32) -> Option<&'static Chain> {
162 match chain_id {
163 2741 => Some(&chains::ABSTRACT),
164 42161 => Some(&chains::ARBITRUM),
165 42170 => Some(&chains::ARBITRUM_NOVA),
166 421614 => Some(&chains::ARBITRUM_SEPOLIA),
167 1313161554 => Some(&chains::AURORA),
168 43114 => Some(&chains::AVALANCHE),
169 8453 => Some(&chains::BASE),
170 84532 => Some(&chains::BASE_SEPOLIA),
171 80094 => Some(&chains::BERACHAIN),
172 80085 => Some(&chains::BERACHAIN_BARTIO),
173 81457 => Some(&chains::BLAST),
174 168587773 => Some(&chains::BLAST_SEPOLIA),
175 288 => Some(&chains::BOBA),
176 56 => Some(&chains::BSC),
177 97 => Some(&chains::BSC_TESTNET),
178 42220 => Some(&chains::CELO),
179 8888 => Some(&chains::CHILIZ),
180 3333 => Some(&chains::CITREA_TESTNET),
181 33111 => Some(&chains::CURTIS),
182 7560 => Some(&chains::CYBER),
183 46 => Some(&chains::DARWINIA),
184 1 => Some(&chains::ETHEREUM),
185 250 => Some(&chains::FANTOM),
186 14 => Some(&chains::FLARE),
187 252 => Some(&chains::FRAXTAL),
188 43113 => Some(&chains::FUJI),
189 696969 => Some(&chains::GALADRIEL_DEVNET),
190 100 => Some(&chains::GNOSIS),
191 10200 => Some(&chains::GNOSIS_CHIADO),
192 10300 => Some(&chains::GNOSIS_TRACES),
193 1666600000 => Some(&chains::HARMONY_SHARD_0),
194 17000 => Some(&chains::HOLESKY),
195 17001 => Some(&chains::HOLESKY_TOKEN_TEST),
196 7979 => Some(&chains::HYPERLIQUID),
197 7978 => Some(&chains::HYPERLIQUID_TEMP),
198 222 => Some(&chains::INK),
199 13337 => Some(&chains::INTERNAL_TEST_CHAIN),
200 255 => Some(&chains::KROMA),
201 59144 => Some(&chains::LINEA),
202 501 => Some(&chains::LISK),
203 42 => Some(&chains::LUKSO),
204 4201 => Some(&chains::LUKSO_TESTNET),
205 169 => Some(&chains::MANTA),
206 5000 => Some(&chains::MANTLE),
207 777 => Some(&chains::MEGAETH_TESTNET),
208 4200 => Some(&chains::MERLIN),
209 90 => Some(&chains::METALL2),
210 1088 => Some(&chains::METIS),
211 11 => Some(&chains::MEV_COMMIT),
212 34443 => Some(&chains::MODE),
213 2323 => Some(&chains::MONAD_TESTNET),
214 2358 => Some(&chains::MONAD_TESTNET_BACKUP),
215 1287 => Some(&chains::MOONBASE_ALPHA),
216 1284 => Some(&chains::MOONBEAM),
217 2710 => Some(&chains::MORPH),
218 2710111 => Some(&chains::MORPH_HOLESKY),
219 204 => Some(&chains::OPBNB),
220 10 => Some(&chains::OPTIMISM),
221 11155420 => Some(&chains::OPTIMISM_SEPOLIA),
222 1337 => Some(&chains::PHAROS_DEVNET),
223 137 => Some(&chains::POLYGON),
224 80002 => Some(&chains::POLYGON_AMOY),
225 1101 => Some(&chains::POLYGON_ZKEVM),
226 30 => Some(&chains::ROOTSTOCK),
227 1204 => Some(&chains::SAAKURU),
228 534352 => Some(&chains::SCROLL),
229 11155111 => Some(&chains::SEPOLIA),
230 148 => Some(&chains::SHIMMER_EVM),
231 109 => Some(&chains::SONEIUM),
232 138 => Some(&chains::SOPHON),
233 139 => Some(&chains::SOPHON_TESTNET),
234 10001 => Some(&chains::SUPERSEED),
235 9999 => Some(&chains::UNICHAIN),
236 9997 => Some(&chains::UNICHAIN_SEPOLIA),
237 50 => Some(&chains::XDC),
238 51 => Some(&chains::XDC_TESTNET),
239 7000 => Some(&chains::ZETA),
240 78600 => Some(&chains::ZIRCUIT),
241 324 => Some(&chains::ZKSYNC),
242 7777777 => Some(&chains::ZORA),
243 _ => None,
244 }
245 }
246}
247
248impl Display for Chain {
249 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
250 write!(f, "Chain(name={}, id={})", self.name, self.chain_id)
251 }
252}
253
254pub mod chains {
256 use std::sync::LazyLock;
257
258 use crate::defi::chain::{Blockchain, Chain};
259
260 pub static ABSTRACT: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Abstract, 2741));
261 pub static ARBITRUM: LazyLock<Chain> =
262 LazyLock::new(|| Chain::new(Blockchain::Arbitrum, 42161));
263 pub static ARBITRUM_NOVA: LazyLock<Chain> =
264 LazyLock::new(|| Chain::new(Blockchain::ArbitrumNova, 42170));
265 pub static ARBITRUM_SEPOLIA: LazyLock<Chain> =
266 LazyLock::new(|| Chain::new(Blockchain::ArbitrumSepolia, 421614));
267 pub static AURORA: LazyLock<Chain> =
268 LazyLock::new(|| Chain::new(Blockchain::Aurora, 1313161554));
269 pub static AVALANCHE: LazyLock<Chain> =
270 LazyLock::new(|| Chain::new(Blockchain::Avalanche, 43114));
271 pub static BASE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Base, 8453));
272 pub static BASE_SEPOLIA: LazyLock<Chain> =
273 LazyLock::new(|| Chain::new(Blockchain::BaseSepolia, 84532));
274 pub static BERACHAIN: LazyLock<Chain> =
275 LazyLock::new(|| Chain::new(Blockchain::Berachain, 80094));
276 pub static BERACHAIN_BARTIO: LazyLock<Chain> =
277 LazyLock::new(|| Chain::new(Blockchain::BerachainBartio, 80085));
278 pub static BLAST: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Blast, 81457));
279 pub static BLAST_SEPOLIA: LazyLock<Chain> =
280 LazyLock::new(|| Chain::new(Blockchain::BlastSepolia, 168587773));
281 pub static BOBA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Boba, 288));
282 pub static BSC: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Bsc, 56));
283 pub static BSC_TESTNET: LazyLock<Chain> =
284 LazyLock::new(|| Chain::new(Blockchain::BscTestnet, 97));
285 pub static CELO: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Celo, 42220));
286 pub static CHILIZ: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Chiliz, 8888));
287 pub static CITREA_TESTNET: LazyLock<Chain> =
288 LazyLock::new(|| Chain::new(Blockchain::CitreaTestnet, 3333));
289 pub static CURTIS: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Curtis, 33111));
290 pub static CYBER: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Cyber, 7560));
291 pub static DARWINIA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Darwinia, 46));
292 pub static ETHEREUM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Ethereum, 1));
293 pub static FANTOM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Fantom, 250));
294 pub static FLARE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Flare, 14));
295 pub static FRAXTAL: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Fraxtal, 252));
296 pub static FUJI: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Fuji, 43113));
297 pub static GALADRIEL_DEVNET: LazyLock<Chain> =
298 LazyLock::new(|| Chain::new(Blockchain::GaladrielDevnet, 696969));
299 pub static GNOSIS: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Gnosis, 100));
300 pub static GNOSIS_CHIADO: LazyLock<Chain> =
301 LazyLock::new(|| Chain::new(Blockchain::GnosisChiado, 10200));
302 pub static GNOSIS_TRACES: LazyLock<Chain> =
308 LazyLock::new(|| Chain::new(Blockchain::GnosisTraces, 10300));
309 pub static HARMONY_SHARD_0: LazyLock<Chain> =
310 LazyLock::new(|| Chain::new(Blockchain::HarmonyShard0, 1666600000));
311 pub static HOLESKY: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Holesky, 17000));
312 pub static HOLESKY_TOKEN_TEST: LazyLock<Chain> =
315 LazyLock::new(|| Chain::new(Blockchain::HoleskyTokenTest, 17001));
316 pub static HYPERLIQUID: LazyLock<Chain> =
320 LazyLock::new(|| Chain::new(Blockchain::Hyperliquid, 7979));
321 pub static HYPERLIQUID_TEMP: LazyLock<Chain> =
322 LazyLock::new(|| Chain::new(Blockchain::HyperliquidTemp, 7978));
323 pub static INK: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Ink, 222));
325 pub static INTERNAL_TEST_CHAIN: LazyLock<Chain> =
327 LazyLock::new(|| Chain::new(Blockchain::InternalTestChain, 13337));
328 pub static KROMA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Kroma, 255));
329 pub static LINEA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Linea, 59144));
330 pub static LISK: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Lisk, 501));
331 pub static LUKSO: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Lukso, 42));
332 pub static LUKSO_TESTNET: LazyLock<Chain> =
333 LazyLock::new(|| Chain::new(Blockchain::LuksoTestnet, 4201));
334 pub static MANTA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Manta, 169));
335 pub static MANTLE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Mantle, 5000));
336 pub static MEGAETH_TESTNET: LazyLock<Chain> =
337 LazyLock::new(|| Chain::new(Blockchain::MegaethTestnet, 777));
338 pub static MERLIN: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Merlin, 4200));
339 pub static METALL2: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Metall2, 90));
340 pub static METIS: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Metis, 1088));
341 pub static MEV_COMMIT: LazyLock<Chain> =
342 LazyLock::new(|| Chain::new(Blockchain::MevCommit, 11));
343 pub static MODE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Mode, 34443));
344 pub static MONAD_TESTNET: LazyLock<Chain> =
345 LazyLock::new(|| Chain::new(Blockchain::MonadTestnet, 2323));
346 pub static MONAD_TESTNET_BACKUP: LazyLock<Chain> =
347 LazyLock::new(|| Chain::new(Blockchain::MonadTestnetBackup, 2358));
348 pub static MOONBASE_ALPHA: LazyLock<Chain> =
349 LazyLock::new(|| Chain::new(Blockchain::MoonbaseAlpha, 1287));
350 pub static MOONBEAM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Moonbeam, 1284));
351 pub static MORPH: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Morph, 2710));
352 pub static MORPH_HOLESKY: LazyLock<Chain> =
353 LazyLock::new(|| Chain::new(Blockchain::MorphHolesky, 2710111));
354 pub static OPBNB: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Opbnb, 204));
355 pub static OPTIMISM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Optimism, 10));
356 pub static OPTIMISM_SEPOLIA: LazyLock<Chain> =
357 LazyLock::new(|| Chain::new(Blockchain::OptimismSepolia, 11155420));
358 pub static PHAROS_DEVNET: LazyLock<Chain> =
359 LazyLock::new(|| Chain::new(Blockchain::PharosDevnet, 1337));
360 pub static POLYGON: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Polygon, 137));
361 pub static POLYGON_AMOY: LazyLock<Chain> =
362 LazyLock::new(|| Chain::new(Blockchain::PolygonAmoy, 80002));
363 pub static POLYGON_ZKEVM: LazyLock<Chain> =
364 LazyLock::new(|| Chain::new(Blockchain::PolygonZkEvm, 1101));
365 pub static ROOTSTOCK: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Rootstock, 30));
366 pub static SAAKURU: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Saakuru, 1204));
367 pub static SCROLL: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Scroll, 534352));
368 pub static SEPOLIA: LazyLock<Chain> =
369 LazyLock::new(|| Chain::new(Blockchain::Sepolia, 11155111));
370 pub static SHIMMER_EVM: LazyLock<Chain> =
371 LazyLock::new(|| Chain::new(Blockchain::ShimmerEvm, 148));
372 pub static SONEIUM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Soneium, 109));
373 pub static SOPHON: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Sophon, 138));
374 pub static SOPHON_TESTNET: LazyLock<Chain> =
375 LazyLock::new(|| Chain::new(Blockchain::SophonTestnet, 139));
376 pub static SUPERSEED: LazyLock<Chain> =
377 LazyLock::new(|| Chain::new(Blockchain::Superseed, 10001));
378 pub static UNICHAIN: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Unichain, 9999));
379 pub static UNICHAIN_SEPOLIA: LazyLock<Chain> =
380 LazyLock::new(|| Chain::new(Blockchain::UnichainSepolia, 9997));
381 pub static XDC: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Xdc, 50));
382 pub static XDC_TESTNET: LazyLock<Chain> =
383 LazyLock::new(|| Chain::new(Blockchain::XdcTestnet, 51));
384 pub static ZETA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Zeta, 7000));
385 pub static ZIRCUIT: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Zircuit, 78600));
386 pub static ZKSYNC: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::ZKsync, 324));
387 pub static ZORA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Zora, 7777777));
388}
389
390#[cfg(test)]
391mod tests {
392 use rstest::rstest;
393
394 use super::*;
395
396 #[rstest]
397 fn test_ethereum_chain() {
398 let eth_chain = chains::ETHEREUM.clone();
399 assert_eq!(eth_chain.to_string(), "Chain(name=Ethereum, id=1)");
400 assert_eq!(eth_chain.name, Blockchain::Ethereum);
401 assert_eq!(eth_chain.chain_id, 1);
402 assert_eq!(eth_chain.hypersync_url.as_str(), "https://1.hypersync.xyz")
403 }
404
405 #[rstest]
406 fn test_arbitrum_chain() {
407 let arbitrum_chain = chains::ARBITRUM.clone();
408 assert_eq!(arbitrum_chain.to_string(), "Chain(name=Arbitrum, id=42161)");
409 assert_eq!(arbitrum_chain.name, Blockchain::Arbitrum);
410 assert_eq!(arbitrum_chain.chain_id, 42161);
411 assert_eq!(
412 arbitrum_chain.hypersync_url.as_str(),
413 "https://42161.hypersync.xyz"
414 );
415 }
416
417 #[rstest]
418 fn test_chain_constructor() {
419 let chain = Chain::new(Blockchain::Polygon, 137);
420
421 assert_eq!(chain.name, Blockchain::Polygon);
422 assert_eq!(chain.chain_id, 137);
423 assert_eq!(chain.hypersync_url, "https://137.hypersync.xyz");
424 assert!(chain.rpc_url.is_none());
425 assert_eq!(chain.native_currency_decimals, 18);
426 }
427
428 #[rstest]
429 fn test_chain_set_rpc_url() {
430 let mut chain = Chain::new(Blockchain::Ethereum, 1);
431 assert!(chain.rpc_url.is_none());
432
433 let rpc_url = "https://mainnet.infura.io/v3/YOUR-PROJECT-ID".to_string();
434 chain.set_rpc_url(rpc_url.clone());
435
436 assert_eq!(chain.rpc_url, Some(rpc_url));
437 }
438
439 #[rstest]
440 fn test_chain_from_chain_id_valid() {
441 assert!(Chain::from_chain_id(1).is_some()); assert!(Chain::from_chain_id(137).is_some()); assert!(Chain::from_chain_id(42161).is_some()); assert!(Chain::from_chain_id(8453).is_some()); let eth_chain = Chain::from_chain_id(1).unwrap();
449 assert_eq!(eth_chain.name, Blockchain::Ethereum);
450 assert_eq!(eth_chain.chain_id, 1);
451 }
452
453 #[rstest]
454 fn test_chain_from_chain_id_invalid() {
455 assert!(Chain::from_chain_id(999999).is_none());
457 assert!(Chain::from_chain_id(0).is_none());
458 }
459}