1use std::{fmt::Display, str::FromStr, sync::Arc};
19
20use serde::{Deserialize, Serialize};
21use strum::{Display, EnumIter, EnumString};
22
23use crate::types::Currency;
24
25#[derive(
27 Debug,
28 Clone,
29 Copy,
30 Hash,
31 PartialOrd,
32 PartialEq,
33 Ord,
34 Eq,
35 Display,
36 EnumIter,
37 EnumString,
38 Serialize,
39 Deserialize,
40)]
41#[non_exhaustive]
42#[strum(ascii_case_insensitive)]
43#[cfg_attr(
44 feature = "python",
45 pyo3::pyclass(
46 frozen,
47 eq,
48 eq_int,
49 module = "nautilus_trader.model",
50 from_py_object,
51 rename_all = "SCREAMING_SNAKE_CASE",
52 )
53)]
54#[cfg_attr(feature = "python", pyo3_stub_gen::derive::gen_stub_pyclass_enum)]
55pub enum Blockchain {
56 Abstract,
57 Arbitrum,
58 ArbitrumNova,
59 ArbitrumSepolia,
60 Aurora,
61 Avalanche,
62 Base,
63 BaseSepolia,
64 Berachain,
65 BerachainBartio,
66 Blast,
67 BlastSepolia,
68 Boba,
69 Bsc,
70 BscTestnet,
71 Celo,
72 Chiliz,
73 CitreaTestnet,
74 Curtis,
75 Cyber,
76 Darwinia,
77 Ethereum,
78 Fantom,
79 Flare,
80 Fraxtal,
81 Fuji,
82 GaladrielDevnet,
83 Gnosis,
84 GnosisChiado,
85 GnosisTraces,
86 HarmonyShard0,
87 Holesky,
88 HoleskyTokenTest,
89 Hyperliquid,
90 HyperliquidTemp,
91 Ink,
92 InternalTestChain,
93 Kroma,
94 Linea,
95 Lisk,
96 Lukso,
97 LuksoTestnet,
98 Manta,
99 Mantle,
100 MegaethTestnet,
101 Merlin,
102 Metall2,
103 Metis,
104 MevCommit,
105 Mode,
106 MonadTestnet,
107 MonadTestnetBackup,
108 MoonbaseAlpha,
109 Moonbeam,
110 Morph,
111 MorphHolesky,
112 Opbnb,
113 Optimism,
114 OptimismSepolia,
115 PharosDevnet,
116 Polygon,
117 PolygonAmoy,
118 PolygonZkEvm,
119 Rootstock,
120 Saakuru,
121 Scroll,
122 Sepolia,
123 ShimmerEvm,
124 Soneium,
125 Sophon,
126 SophonTestnet,
127 Superseed,
128 Unichain,
129 UnichainSepolia,
130 Xdc,
131 XdcTestnet,
132 Zeta,
133 Zircuit,
134 ZKsync,
135 Zora,
136}
137
138#[cfg_attr(
140 feature = "python",
141 pyo3::pyclass(module = "nautilus_trader.model", from_py_object)
142)]
143#[cfg_attr(feature = "python", pyo3_stub_gen::derive::gen_stub_pyclass)]
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145pub struct Chain {
146 pub name: Blockchain,
148 pub chain_id: u32,
150 pub hypersync_url: String,
152 pub rpc_url: Option<String>,
154 pub native_currency_decimals: u8,
156}
157
158pub type SharedChain = Arc<Chain>;
160
161impl Chain {
162 #[must_use]
164 pub fn new(name: Blockchain, chain_id: u32) -> Self {
165 Self {
166 chain_id,
167 name,
168 hypersync_url: format!("https://{chain_id}.hypersync.xyz"),
169 rpc_url: None,
170 native_currency_decimals: 18, }
172 }
173
174 pub fn set_rpc_url(&mut self, rpc: String) {
176 self.rpc_url = Some(rpc);
177 }
178
179 #[must_use]
187 pub fn native_currency(&self) -> Currency {
188 use crate::enums::CurrencyType;
189
190 let (code, name) = match self.name {
191 Blockchain::Ethereum | Blockchain::Sepolia | Blockchain::Holesky => ("ETH", "Ethereum"),
193
194 Blockchain::Arbitrum
196 | Blockchain::ArbitrumNova
197 | Blockchain::ArbitrumSepolia
198 | Blockchain::Base
199 | Blockchain::BaseSepolia
200 | Blockchain::Optimism
201 | Blockchain::OptimismSepolia
202 | Blockchain::Blast
203 | Blockchain::BlastSepolia
204 | Blockchain::Scroll
205 | Blockchain::Linea => ("ETH", "Ethereum"),
206 Blockchain::Polygon | Blockchain::PolygonAmoy => ("POL", "Polygon"),
207 Blockchain::Avalanche | Blockchain::Fuji => ("AVAX", "Avalanche"),
208 Blockchain::Bsc | Blockchain::BscTestnet => ("BNB", "Binance Coin"),
209 _ => panic!("Native currency not specified for chain {}", self.name),
210 };
211
212 Currency::new(
213 code,
214 self.native_currency_decimals,
215 0,
216 name,
217 CurrencyType::Crypto,
218 )
219 }
220
221 #[must_use]
223 pub fn from_chain_id(chain_id: u32) -> Option<&'static Self> {
224 match chain_id {
225 2741 => Some(&chains::ABSTRACT),
226 42161 => Some(&chains::ARBITRUM),
227 42170 => Some(&chains::ARBITRUM_NOVA),
228 421_614 => Some(&chains::ARBITRUM_SEPOLIA),
229 1_313_161_554 => Some(&chains::AURORA),
230 43114 => Some(&chains::AVALANCHE),
231 8453 => Some(&chains::BASE),
232 84532 => Some(&chains::BASE_SEPOLIA),
233 80094 => Some(&chains::BERACHAIN),
234 80085 => Some(&chains::BERACHAIN_BARTIO),
235 81457 => Some(&chains::BLAST),
236 168_587_773 => Some(&chains::BLAST_SEPOLIA),
237 288 => Some(&chains::BOBA),
238 56 => Some(&chains::BSC),
239 97 => Some(&chains::BSC_TESTNET),
240 42220 => Some(&chains::CELO),
241 88888 => Some(&chains::CHILIZ),
242 5115 => Some(&chains::CITREA_TESTNET),
243 33111 => Some(&chains::CURTIS),
244 7560 => Some(&chains::CYBER),
245 46 => Some(&chains::DARWINIA),
246 1 => Some(&chains::ETHEREUM),
247 250 => Some(&chains::FANTOM),
248 14 => Some(&chains::FLARE),
249 252 => Some(&chains::FRAXTAL),
250 43113 => Some(&chains::FUJI),
251 696_969 => Some(&chains::GALADRIEL_DEVNET),
252 100 => Some(&chains::GNOSIS),
253 10200 => Some(&chains::GNOSIS_CHIADO),
254 10300 => Some(&chains::GNOSIS_TRACES),
255 1_666_600_000 => Some(&chains::HARMONY_SHARD_0),
256 17000 => Some(&chains::HOLESKY),
257 17001 => Some(&chains::HOLESKY_TOKEN_TEST),
258 999 => Some(&chains::HYPERLIQUID),
259 7978 => Some(&chains::HYPERLIQUID_TEMP),
260 57073 => Some(&chains::INK),
261 13337 => Some(&chains::INTERNAL_TEST_CHAIN),
262 255 => Some(&chains::KROMA),
263 59144 => Some(&chains::LINEA),
264 1135 => Some(&chains::LISK),
265 42 => Some(&chains::LUKSO),
266 4201 => Some(&chains::LUKSO_TESTNET),
267 169 => Some(&chains::MANTA),
268 5000 => Some(&chains::MANTLE),
269 777 => Some(&chains::MEGAETH_TESTNET),
270 4200 => Some(&chains::MERLIN),
271 1750 => Some(&chains::METALL2),
272 1088 => Some(&chains::METIS),
273 11 => Some(&chains::MEV_COMMIT),
274 34443 => Some(&chains::MODE),
275 10143 => Some(&chains::MONAD_TESTNET),
276 2358 => Some(&chains::MONAD_TESTNET_BACKUP),
277 1287 => Some(&chains::MOONBASE_ALPHA),
278 1284 => Some(&chains::MOONBEAM),
279 2818 => Some(&chains::MORPH),
280 2_710_111 => Some(&chains::MORPH_HOLESKY),
281 204 => Some(&chains::OPBNB),
282 10 => Some(&chains::OPTIMISM),
283 11_155_420 => Some(&chains::OPTIMISM_SEPOLIA),
284 1337 => Some(&chains::PHAROS_DEVNET),
285 137 => Some(&chains::POLYGON),
286 80002 => Some(&chains::POLYGON_AMOY),
287 1101 => Some(&chains::POLYGON_ZKEVM),
288 30 => Some(&chains::ROOTSTOCK),
289 1204 => Some(&chains::SAAKURU),
290 534_352 => Some(&chains::SCROLL),
291 11_155_111 => Some(&chains::SEPOLIA),
292 148 => Some(&chains::SHIMMER_EVM),
293 1868 => Some(&chains::SONEIUM),
294 50104 => Some(&chains::SOPHON),
295 139 => Some(&chains::SOPHON_TESTNET),
296 5330 => Some(&chains::SUPERSEDE),
297 130 => Some(&chains::UNICHAIN),
298 9997 => Some(&chains::UNICHAIN_SEPOLIA),
299 50 => Some(&chains::XDC),
300 51 => Some(&chains::XDC_TESTNET),
301 7000 => Some(&chains::ZETA),
302 78600 => Some(&chains::ZIRCUIT),
303 324 => Some(&chains::ZKSYNC),
304 7_777_777 => Some(&chains::ZORA),
305 _ => None,
306 }
307 }
308
309 #[must_use]
313 pub fn from_chain_name(chain_name: &str) -> Option<&'static Self> {
314 let blockchain = Blockchain::from_str(chain_name).ok()?;
315
316 match blockchain {
317 Blockchain::Abstract => Some(&chains::ABSTRACT),
318 Blockchain::Arbitrum => Some(&chains::ARBITRUM),
319 Blockchain::ArbitrumNova => Some(&chains::ARBITRUM_NOVA),
320 Blockchain::ArbitrumSepolia => Some(&chains::ARBITRUM_SEPOLIA),
321 Blockchain::Aurora => Some(&chains::AURORA),
322 Blockchain::Avalanche => Some(&chains::AVALANCHE),
323 Blockchain::Base => Some(&chains::BASE),
324 Blockchain::BaseSepolia => Some(&chains::BASE_SEPOLIA),
325 Blockchain::Berachain => Some(&chains::BERACHAIN),
326 Blockchain::BerachainBartio => Some(&chains::BERACHAIN_BARTIO),
327 Blockchain::Blast => Some(&chains::BLAST),
328 Blockchain::BlastSepolia => Some(&chains::BLAST_SEPOLIA),
329 Blockchain::Boba => Some(&chains::BOBA),
330 Blockchain::Bsc => Some(&chains::BSC),
331 Blockchain::BscTestnet => Some(&chains::BSC_TESTNET),
332 Blockchain::Celo => Some(&chains::CELO),
333 Blockchain::Chiliz => Some(&chains::CHILIZ),
334 Blockchain::CitreaTestnet => Some(&chains::CITREA_TESTNET),
335 Blockchain::Curtis => Some(&chains::CURTIS),
336 Blockchain::Cyber => Some(&chains::CYBER),
337 Blockchain::Darwinia => Some(&chains::DARWINIA),
338 Blockchain::Ethereum => Some(&chains::ETHEREUM),
339 Blockchain::Fantom => Some(&chains::FANTOM),
340 Blockchain::Flare => Some(&chains::FLARE),
341 Blockchain::Fraxtal => Some(&chains::FRAXTAL),
342 Blockchain::Fuji => Some(&chains::FUJI),
343 Blockchain::GaladrielDevnet => Some(&chains::GALADRIEL_DEVNET),
344 Blockchain::Gnosis => Some(&chains::GNOSIS),
345 Blockchain::GnosisChiado => Some(&chains::GNOSIS_CHIADO),
346 Blockchain::GnosisTraces => Some(&chains::GNOSIS_TRACES),
347 Blockchain::HarmonyShard0 => Some(&chains::HARMONY_SHARD_0),
348 Blockchain::Holesky => Some(&chains::HOLESKY),
349 Blockchain::HoleskyTokenTest => Some(&chains::HOLESKY_TOKEN_TEST),
350 Blockchain::Hyperliquid => Some(&chains::HYPERLIQUID),
351 Blockchain::HyperliquidTemp => Some(&chains::HYPERLIQUID_TEMP),
352 Blockchain::Ink => Some(&chains::INK),
353 Blockchain::InternalTestChain => Some(&chains::INTERNAL_TEST_CHAIN),
354 Blockchain::Kroma => Some(&chains::KROMA),
355 Blockchain::Linea => Some(&chains::LINEA),
356 Blockchain::Lisk => Some(&chains::LISK),
357 Blockchain::Lukso => Some(&chains::LUKSO),
358 Blockchain::LuksoTestnet => Some(&chains::LUKSO_TESTNET),
359 Blockchain::Manta => Some(&chains::MANTA),
360 Blockchain::Mantle => Some(&chains::MANTLE),
361 Blockchain::MegaethTestnet => Some(&chains::MEGAETH_TESTNET),
362 Blockchain::Merlin => Some(&chains::MERLIN),
363 Blockchain::Metall2 => Some(&chains::METALL2),
364 Blockchain::Metis => Some(&chains::METIS),
365 Blockchain::MevCommit => Some(&chains::MEV_COMMIT),
366 Blockchain::Mode => Some(&chains::MODE),
367 Blockchain::MonadTestnet => Some(&chains::MONAD_TESTNET),
368 Blockchain::MonadTestnetBackup => Some(&chains::MONAD_TESTNET_BACKUP),
369 Blockchain::MoonbaseAlpha => Some(&chains::MOONBASE_ALPHA),
370 Blockchain::Moonbeam => Some(&chains::MOONBEAM),
371 Blockchain::Morph => Some(&chains::MORPH),
372 Blockchain::MorphHolesky => Some(&chains::MORPH_HOLESKY),
373 Blockchain::Opbnb => Some(&chains::OPBNB),
374 Blockchain::Optimism => Some(&chains::OPTIMISM),
375 Blockchain::OptimismSepolia => Some(&chains::OPTIMISM_SEPOLIA),
376 Blockchain::PharosDevnet => Some(&chains::PHAROS_DEVNET),
377 Blockchain::Polygon => Some(&chains::POLYGON),
378 Blockchain::PolygonAmoy => Some(&chains::POLYGON_AMOY),
379 Blockchain::PolygonZkEvm => Some(&chains::POLYGON_ZKEVM),
380 Blockchain::Rootstock => Some(&chains::ROOTSTOCK),
381 Blockchain::Saakuru => Some(&chains::SAAKURU),
382 Blockchain::Scroll => Some(&chains::SCROLL),
383 Blockchain::Sepolia => Some(&chains::SEPOLIA),
384 Blockchain::ShimmerEvm => Some(&chains::SHIMMER_EVM),
385 Blockchain::Soneium => Some(&chains::SONEIUM),
386 Blockchain::Sophon => Some(&chains::SOPHON),
387 Blockchain::SophonTestnet => Some(&chains::SOPHON_TESTNET),
388 Blockchain::Superseed => Some(&chains::SUPERSEDE),
389 Blockchain::Unichain => Some(&chains::UNICHAIN),
390 Blockchain::UnichainSepolia => Some(&chains::UNICHAIN_SEPOLIA),
391 Blockchain::Xdc => Some(&chains::XDC),
392 Blockchain::XdcTestnet => Some(&chains::XDC_TESTNET),
393 Blockchain::Zeta => Some(&chains::ZETA),
394 Blockchain::Zircuit => Some(&chains::ZIRCUIT),
395 Blockchain::ZKsync => Some(&chains::ZKSYNC),
396 Blockchain::Zora => Some(&chains::ZORA),
397 }
398 }
399}
400
401impl Display for Chain {
402 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
403 write!(f, "Chain(name={}, id={})", self.name, self.chain_id)
404 }
405}
406
407pub mod chains {
409 use std::sync::LazyLock;
410
411 use crate::defi::chain::{Blockchain, Chain};
412
413 pub static ABSTRACT: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Abstract, 2741));
414 pub static ARBITRUM: LazyLock<Chain> =
415 LazyLock::new(|| Chain::new(Blockchain::Arbitrum, 42161));
416 pub static ARBITRUM_NOVA: LazyLock<Chain> =
417 LazyLock::new(|| Chain::new(Blockchain::ArbitrumNova, 42170));
418 pub static ARBITRUM_SEPOLIA: LazyLock<Chain> =
419 LazyLock::new(|| Chain::new(Blockchain::ArbitrumSepolia, 421_614));
420 pub static AURORA: LazyLock<Chain> =
421 LazyLock::new(|| Chain::new(Blockchain::Aurora, 1_313_161_554));
422 pub static AVALANCHE: LazyLock<Chain> =
423 LazyLock::new(|| Chain::new(Blockchain::Avalanche, 43114));
424 pub static BASE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Base, 8453));
425 pub static BASE_SEPOLIA: LazyLock<Chain> =
426 LazyLock::new(|| Chain::new(Blockchain::BaseSepolia, 84532));
427 pub static BERACHAIN: LazyLock<Chain> =
428 LazyLock::new(|| Chain::new(Blockchain::Berachain, 80094));
429 pub static BERACHAIN_BARTIO: LazyLock<Chain> =
430 LazyLock::new(|| Chain::new(Blockchain::BerachainBartio, 80085));
431 pub static BLAST: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Blast, 81457));
432 pub static BLAST_SEPOLIA: LazyLock<Chain> =
433 LazyLock::new(|| Chain::new(Blockchain::BlastSepolia, 168_587_773));
434 pub static BOBA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Boba, 288));
435 pub static BSC: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Bsc, 56));
436 pub static BSC_TESTNET: LazyLock<Chain> =
437 LazyLock::new(|| Chain::new(Blockchain::BscTestnet, 97));
438 pub static CELO: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Celo, 42220));
439 pub static CHILIZ: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Chiliz, 88888));
440 pub static CITREA_TESTNET: LazyLock<Chain> =
441 LazyLock::new(|| Chain::new(Blockchain::CitreaTestnet, 5115));
442 pub static CURTIS: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Curtis, 33111));
443 pub static CYBER: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Cyber, 7560));
444 pub static DARWINIA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Darwinia, 46));
445 pub static ETHEREUM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Ethereum, 1));
446 pub static FANTOM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Fantom, 250));
447 pub static FLARE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Flare, 14));
448 pub static FRAXTAL: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Fraxtal, 252));
449 pub static FUJI: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Fuji, 43113));
450 pub static GALADRIEL_DEVNET: LazyLock<Chain> =
451 LazyLock::new(|| Chain::new(Blockchain::GaladrielDevnet, 696_969));
452 pub static GNOSIS: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Gnosis, 100));
453 pub static GNOSIS_CHIADO: LazyLock<Chain> =
454 LazyLock::new(|| Chain::new(Blockchain::GnosisChiado, 10200));
455 pub static GNOSIS_TRACES: LazyLock<Chain> =
461 LazyLock::new(|| Chain::new(Blockchain::GnosisTraces, 10300));
462 pub static HARMONY_SHARD_0: LazyLock<Chain> =
463 LazyLock::new(|| Chain::new(Blockchain::HarmonyShard0, 1_666_600_000));
464 pub static HOLESKY: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Holesky, 17000));
465 pub static HOLESKY_TOKEN_TEST: LazyLock<Chain> =
468 LazyLock::new(|| Chain::new(Blockchain::HoleskyTokenTest, 17001));
469 pub static HYPERLIQUID: LazyLock<Chain> =
470 LazyLock::new(|| Chain::new(Blockchain::Hyperliquid, 999));
471 pub static HYPERLIQUID_TEMP: LazyLock<Chain> =
472 LazyLock::new(|| Chain::new(Blockchain::HyperliquidTemp, 7978));
473 pub static INK: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Ink, 57073));
474 pub static INTERNAL_TEST_CHAIN: LazyLock<Chain> =
476 LazyLock::new(|| Chain::new(Blockchain::InternalTestChain, 13337));
477 pub static KROMA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Kroma, 255));
478 pub static LINEA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Linea, 59144));
479 pub static LISK: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Lisk, 1135));
480 pub static LUKSO: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Lukso, 42));
481 pub static LUKSO_TESTNET: LazyLock<Chain> =
482 LazyLock::new(|| Chain::new(Blockchain::LuksoTestnet, 4201));
483 pub static MANTA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Manta, 169));
484 pub static MANTLE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Mantle, 5000));
485 pub static MEGAETH_TESTNET: LazyLock<Chain> =
486 LazyLock::new(|| Chain::new(Blockchain::MegaethTestnet, 777));
487 pub static MERLIN: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Merlin, 4200));
488 pub static METALL2: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Metall2, 1750));
489 pub static METIS: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Metis, 1088));
490 pub static MEV_COMMIT: LazyLock<Chain> =
491 LazyLock::new(|| Chain::new(Blockchain::MevCommit, 11));
492 pub static MODE: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Mode, 34443));
493 pub static MONAD_TESTNET: LazyLock<Chain> =
494 LazyLock::new(|| Chain::new(Blockchain::MonadTestnet, 10143));
495 pub static MONAD_TESTNET_BACKUP: LazyLock<Chain> =
496 LazyLock::new(|| Chain::new(Blockchain::MonadTestnetBackup, 2358));
497 pub static MOONBASE_ALPHA: LazyLock<Chain> =
498 LazyLock::new(|| Chain::new(Blockchain::MoonbaseAlpha, 1287));
499 pub static MOONBEAM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Moonbeam, 1284));
500 pub static MORPH: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Morph, 2818));
501 pub static MORPH_HOLESKY: LazyLock<Chain> =
502 LazyLock::new(|| Chain::new(Blockchain::MorphHolesky, 2_710_111));
503 pub static OPBNB: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Opbnb, 204));
504 pub static OPTIMISM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Optimism, 10));
505 pub static OPTIMISM_SEPOLIA: LazyLock<Chain> =
506 LazyLock::new(|| Chain::new(Blockchain::OptimismSepolia, 11_155_420));
507 pub static PHAROS_DEVNET: LazyLock<Chain> =
508 LazyLock::new(|| Chain::new(Blockchain::PharosDevnet, 1337));
509 pub static POLYGON: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Polygon, 137));
510 pub static POLYGON_AMOY: LazyLock<Chain> =
511 LazyLock::new(|| Chain::new(Blockchain::PolygonAmoy, 80002));
512 pub static POLYGON_ZKEVM: LazyLock<Chain> =
513 LazyLock::new(|| Chain::new(Blockchain::PolygonZkEvm, 1101));
514 pub static ROOTSTOCK: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Rootstock, 30));
515 pub static SAAKURU: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Saakuru, 1204));
516 pub static SCROLL: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Scroll, 534_352));
517 pub static SEPOLIA: LazyLock<Chain> =
518 LazyLock::new(|| Chain::new(Blockchain::Sepolia, 11_155_111));
519 pub static SHIMMER_EVM: LazyLock<Chain> =
520 LazyLock::new(|| Chain::new(Blockchain::ShimmerEvm, 148));
521 pub static SONEIUM: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Soneium, 1868));
522 pub static SOPHON: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Sophon, 50104));
523 pub static SOPHON_TESTNET: LazyLock<Chain> =
524 LazyLock::new(|| Chain::new(Blockchain::SophonTestnet, 139));
525 pub static SUPERSEDE: LazyLock<Chain> =
526 LazyLock::new(|| Chain::new(Blockchain::Superseed, 5330));
527 pub static UNICHAIN: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Unichain, 130));
528 pub static UNICHAIN_SEPOLIA: LazyLock<Chain> =
529 LazyLock::new(|| Chain::new(Blockchain::UnichainSepolia, 9997));
530 pub static XDC: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Xdc, 50));
531 pub static XDC_TESTNET: LazyLock<Chain> =
532 LazyLock::new(|| Chain::new(Blockchain::XdcTestnet, 51));
533 pub static ZETA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Zeta, 7000));
534 pub static ZIRCUIT: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Zircuit, 78600));
535 pub static ZKSYNC: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::ZKsync, 324));
536 pub static ZORA: LazyLock<Chain> = LazyLock::new(|| Chain::new(Blockchain::Zora, 7_777_777));
537}
538
539#[cfg(test)]
540mod tests {
541 use rstest::rstest;
542
543 use super::*;
544
545 #[rstest]
546 fn test_ethereum_chain() {
547 let eth_chain = chains::ETHEREUM.clone();
548 assert_eq!(eth_chain.to_string(), "Chain(name=Ethereum, id=1)");
549 assert_eq!(eth_chain.name, Blockchain::Ethereum);
550 assert_eq!(eth_chain.chain_id, 1);
551 assert_eq!(eth_chain.hypersync_url.as_str(), "https://1.hypersync.xyz");
552
553 let currency = eth_chain.native_currency();
555 assert_eq!(currency.code, "ETH");
556 assert_eq!(currency.precision, 18);
557 assert_eq!(currency.name, "Ethereum");
558 }
559
560 #[rstest]
561 fn test_arbitrum_chain() {
562 let arbitrum_chain = chains::ARBITRUM.clone();
563 assert_eq!(arbitrum_chain.to_string(), "Chain(name=Arbitrum, id=42161)");
564 assert_eq!(arbitrum_chain.name, Blockchain::Arbitrum);
565 assert_eq!(arbitrum_chain.chain_id, 42161);
566 assert_eq!(
567 arbitrum_chain.hypersync_url.as_str(),
568 "https://42161.hypersync.xyz"
569 );
570
571 let currency = arbitrum_chain.native_currency();
573 assert_eq!(currency.code, "ETH");
574 assert_eq!(currency.precision, 18);
575 assert_eq!(currency.name, "Ethereum");
576 }
577
578 #[rstest]
579 fn test_chain_constructor() {
580 let chain = Chain::new(Blockchain::Polygon, 137);
581
582 assert_eq!(chain.name, Blockchain::Polygon);
583 assert_eq!(chain.chain_id, 137);
584 assert_eq!(chain.hypersync_url, "https://137.hypersync.xyz");
585 assert!(chain.rpc_url.is_none());
586 assert_eq!(chain.native_currency_decimals, 18);
587 }
588
589 #[rstest]
590 fn test_chain_set_rpc_url() {
591 let mut chain = Chain::new(Blockchain::Ethereum, 1);
592 assert!(chain.rpc_url.is_none());
593
594 let rpc_url = "https://mainnet.infura.io/v3/YOUR-PROJECT-ID".to_string();
595 chain.set_rpc_url(rpc_url.clone());
596
597 assert_eq!(chain.rpc_url, Some(rpc_url));
598 }
599
600 #[rstest]
601 fn test_chain_from_chain_id_valid() {
602 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();
610 assert_eq!(eth_chain.name, Blockchain::Ethereum);
611 assert_eq!(eth_chain.chain_id, 1);
612 }
613
614 #[rstest]
615 #[case(Blockchain::Chiliz, 88888)]
616 #[case(Blockchain::CitreaTestnet, 5115)]
617 #[case(Blockchain::Hyperliquid, 999)]
618 #[case(Blockchain::Ink, 57073)]
619 #[case(Blockchain::Lisk, 1135)]
620 #[case(Blockchain::Metall2, 1750)]
621 #[case(Blockchain::MonadTestnet, 10143)]
622 #[case(Blockchain::Morph, 2818)]
623 #[case(Blockchain::Soneium, 1868)]
624 #[case(Blockchain::Sophon, 50104)]
625 #[case(Blockchain::Superseed, 5330)]
626 #[case(Blockchain::Unichain, 130)]
627 fn test_chain_ids_match_network_chain_ids(#[case] blockchain: Blockchain, #[case] id: u32) {
628 let chain_by_name = Chain::from_chain_name(&blockchain.to_string()).unwrap();
629 let chain_by_id = Chain::from_chain_id(id).unwrap();
630
631 assert_eq!(chain_by_name.name, blockchain);
632 assert_eq!(chain_by_name.chain_id, id);
633 assert_eq!(
634 chain_by_name.hypersync_url,
635 format!("https://{id}.hypersync.xyz")
636 );
637 assert_eq!(chain_by_id.name, blockchain);
638 }
639
640 #[rstest]
641 fn test_chain_from_chain_id_invalid() {
642 assert!(Chain::from_chain_id(999_999).is_none());
644 assert!(Chain::from_chain_id(0).is_none());
645 }
646
647 #[rstest]
648 fn test_chain_from_chain_name_valid() {
649 assert!(Chain::from_chain_name("Ethereum").is_some());
651 assert!(Chain::from_chain_name("Polygon").is_some());
652 assert!(Chain::from_chain_name("Arbitrum").is_some());
653 assert!(Chain::from_chain_name("Base").is_some());
654
655 let eth_chain = Chain::from_chain_name("Ethereum").unwrap();
657 assert_eq!(eth_chain.name, Blockchain::Ethereum);
658 assert_eq!(eth_chain.chain_id, 1);
659
660 let arbitrum_nova_chain = Chain::from_chain_name("ArbitrumNova").unwrap();
662 assert_eq!(arbitrum_nova_chain.name, Blockchain::ArbitrumNova);
663 assert_eq!(arbitrum_nova_chain.chain_id, 42170);
664
665 let bsc_chain = Chain::from_chain_name("Bsc").unwrap();
667 assert_eq!(bsc_chain.name, Blockchain::Bsc);
668 assert_eq!(bsc_chain.chain_id, 56);
669 }
670
671 #[rstest]
672 fn test_chain_from_chain_name_invalid() {
673 assert!(Chain::from_chain_name("InvalidChain").is_none());
675 assert!(Chain::from_chain_name("").is_none());
676 assert!(Chain::from_chain_name("NonExistentNetwork").is_none());
677 }
678
679 #[rstest]
680 fn test_chain_from_chain_name_case_sensitive() {
681 assert!(Chain::from_chain_name("Ethereum").is_some());
683 assert!(Chain::from_chain_name("ethereum").is_some()); assert!(Chain::from_chain_name("ETHEREUM").is_some()); assert!(Chain::from_chain_name("EtHeReUm").is_some()); assert!(Chain::from_chain_name("Arbitrum").is_some());
688 assert!(Chain::from_chain_name("arbitrum").is_some()); }
690
691 #[rstest]
692 fn test_chain_from_chain_name_consistency_with_id() {
693 let chains_to_test = [
695 ("Ethereum", 1),
696 ("Polygon", 137),
697 ("Arbitrum", 42161),
698 ("Base", 8453),
699 ("Optimism", 10),
700 ("Avalanche", 43114),
701 ("Fantom", 250),
702 ("Bsc", 56),
703 ];
704
705 for (name, id) in chains_to_test {
706 let chain_by_name =
707 Chain::from_chain_name(name).unwrap_or_else(|| panic!("Chain {name} should exist"));
708 let chain_by_id =
709 Chain::from_chain_id(id).unwrap_or_else(|| panic!("Chain {name} should exist"));
710
711 assert_eq!(chain_by_name.name, chain_by_id.name);
713 assert_eq!(chain_by_name.chain_id, chain_by_id.chain_id);
714 assert_eq!(chain_by_name.hypersync_url, chain_by_id.hypersync_url);
715 }
716 }
717}