op_alloy_registry/
superchain.rs

1//! Contains the full superchain data.
2
3use super::Chain;
4use alloc::{string::String, vec::Vec};
5use alloy_primitives::{
6    map::{DefaultHashBuilder, HashMap},
7    Address,
8};
9use op_alloy_genesis::{ChainConfig, HardForkConfiguration, RollupConfig};
10
11/// A superchain configuration.
12#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
13pub struct Superchain {
14    /// Superchain identifier, without capitalization or display changes.
15    pub name: String,
16    /// Superchain configuration file contents.
17    pub config: SuperchainConfig,
18    /// Chain IDs of chains that are part of this superchain.
19    pub chains: Vec<ChainConfig>,
20}
21
22/// A superchain configuration file format
23#[derive(Debug, Clone, Default, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
24#[serde(rename_all = "PascalCase")]
25pub struct SuperchainConfig {
26    /// Superchain name (e.g. "Mainnet")
27    pub name: String,
28    /// Superchain L1 anchor information
29    pub l1: SuperchainL1Info,
30    /// Optional addresses for the superchain-wide default protocol versions contract.
31    pub protocol_versions_addr: Option<Address>,
32    /// Optional address for the superchain-wide default superchain config contract.
33    pub superchain_config_addr: Option<Address>,
34    /// Hardfork Configuration. These values may be overridden by individual chains.
35    #[serde(flatten)]
36    pub hardfork_defaults: HardForkConfiguration,
37}
38
39/// Superchain L1 anchor information
40#[derive(Debug, Clone, Default, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
41#[serde(rename_all = "PascalCase")]
42pub struct SuperchainL1Info {
43    /// L1 chain ID
44    #[serde(rename = "ChainID")]
45    pub chain_id: u64,
46    /// L1 chain public RPC endpoint
47    #[serde(rename = "PublicRPC")]
48    pub public_rpc: String,
49    /// L1 chain explorer RPC endpoint
50    pub explorer: String,
51}
52
53/// A list of Hydrated Superchain Configs.
54#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct Superchains {
57    /// A list of superchain configs.
58    pub superchains: Vec<Superchain>,
59}
60
61/// The registry containing all the superchain configurations.
62#[derive(Debug, Clone, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
63#[serde(rename_all = "camelCase")]
64pub struct Registry {
65    /// The list of chains.
66    pub chains: Vec<Chain>,
67    /// Map of chain IDs to their chain configuration.
68    pub op_chains: HashMap<u64, ChainConfig, DefaultHashBuilder>,
69    /// Map of chain IDs to their rollup configurations.
70    pub rollup_configs: HashMap<u64, RollupConfig, DefaultHashBuilder>,
71}
72
73impl Registry {
74    /// Read the chain list.
75    pub fn read_chain_list() -> Vec<Chain> {
76        let chain_list = include_str!("../etc/chainList.json");
77        serde_json::from_str(chain_list).expect("Failed to read chain list")
78    }
79
80    /// Read superchain configs.
81    pub fn read_superchain_configs() -> Superchains {
82        let superchain_configs = include_str!("../etc/configs.json");
83        serde_json::from_str(superchain_configs).expect("Failed to read superchain configs")
84    }
85
86    /// Initialize the superchain configurations from the chain list.
87    pub fn from_chain_list() -> Self {
88        let chains = Self::read_chain_list();
89        let superchains = Self::read_superchain_configs();
90        let mut op_chains = HashMap::default();
91        let mut rollup_configs = HashMap::default();
92
93        for superchain in superchains.superchains {
94            for mut chain_config in superchain.chains {
95                chain_config.l1_chain_id = superchain.config.l1.chain_id;
96                if let Some(a) = &mut chain_config.addresses {
97                    a.zero_proof_addresses();
98                }
99                let mut rollup = chain_config.load_op_stack_rollup_config();
100                rollup.protocol_versions_address = superchain
101                    .config
102                    .protocol_versions_addr
103                    .expect("Missing protocol versions address");
104                rollup.superchain_config_address = superchain.config.superchain_config_addr;
105                rollup_configs.insert(chain_config.chain_id, rollup);
106                op_chains.insert(chain_config.chain_id, chain_config);
107            }
108        }
109
110        Self { chains, op_chains, rollup_configs }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use alloy_primitives::address;
118    use op_alloy_genesis::{AddressList, SuperchainLevel, OP_MAINNET_BASE_FEE_PARAMS};
119
120    #[test]
121    fn test_read_chain_configs() {
122        let superchains = Registry::from_chain_list();
123        assert!(superchains.chains.len() > 1);
124        let base_config = ChainConfig {
125            name: String::from("Base"),
126            chain_id: 8453,
127            l1_chain_id: 1,
128            public_rpc: String::from("https://mainnet.base.org"),
129            sequencer_rpc: String::from("https://mainnet-sequencer.base.org"),
130            explorer: String::from("https://explorer.base.org"),
131            superchain_level: SuperchainLevel::Frontier,
132            standard_chain_candidate: true,
133            superchain_time: Some(0),
134            batch_inbox_addr: address!("ff00000000000000000000000000000000008453"),
135            superchain: String::from("mainnet"),
136            chain: String::new(),
137            hardfork_configuration: crate::test_utils::BASE_MAINNET_CONFIG.hardfork_config(),
138            block_time: 2,
139            seq_window_size: 3600,
140            max_sequencer_drift: 600,
141            data_availability_type: "eth-da".to_string(),
142            optimism: Some(OP_MAINNET_BASE_FEE_PARAMS),
143            alt_da: None,
144            genesis: crate::test_utils::BASE_MAINNET_CONFIG.genesis,
145            addresses: Some(AddressList {
146                address_manager: address!("8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2"),
147                l1_cross_domain_messenger_proxy: address!(
148                    "866E82a600A1414e583f7F13623F1aC5d58b0Afa"
149                ),
150                l1_erc721_bridge_proxy: address!("608d94945A64503E642E6370Ec598e519a2C1E53"),
151                l1_standard_bridge_proxy: address!("3154Cf16ccdb4C6d922629664174b904d80F2C35"),
152                l2_output_oracle_proxy: Some(address!("56315b90c40730925ec5485cf004d835058518A0")),
153                optimism_mintable_erc20_factory_proxy: address!(
154                    "05cc379EBD9B30BbA19C6fA282AB29218EC61D84"
155                ),
156                optimism_portal_proxy: address!("49048044D57e1C92A77f79988d21Fa8fAF74E97e"),
157                system_config_proxy: address!("73a79Fab69143498Ed3712e519A88a918e1f4072"),
158                system_config_owner: address!("14536667Cd30e52C0b458BaACcB9faDA7046E056"),
159                proxy_admin: address!("0475cBCAebd9CE8AfA5025828d5b98DFb67E059E"),
160                proxy_admin_owner: address!("7bB41C3008B3f03FE483B28b8DB90e19Cf07595c"),
161                challenger: Some(address!("6F8C5bA3F59ea3E76300E3BEcDC231D656017824")),
162                guardian: address!("09f7150d8c019bef34450d6920f6b3608cefdaf2"),
163                anchor_state_registry_proxy: Some(address!(
164                    "db9091e48b1c42992a1213e6916184f9ebdbfedf"
165                )),
166                delayed_weth_proxy: Some(address!("a2f2ac6f5af72e494a227d79db20473cf7a1ffe8")),
167                dispute_game_factory_proxy: Some(address!(
168                    "43edb88c4b80fdd2adff2412a7bebf9df42cb40e"
169                )),
170                fault_dispute_game: Some(address!("cd3c0194db74c23807d4b90a5181e1b28cf7007c")),
171                mips: Some(address!("16e83ce5ce29bf90ad9da06d2fe6a15d5f344ce4")),
172                permissioned_dispute_game: Some(address!(
173                    "19009debf8954b610f207d5925eede827805986e"
174                )),
175                preimage_oracle: Some(address!("9c065e11870b891d214bc2da7ef1f9ddfa1be277")),
176            }),
177            gas_paying_token: None,
178        };
179        assert_eq!(*superchains.op_chains.get(&8453).unwrap(), base_config);
180    }
181
182    #[test]
183    fn test_read_rollup_configs() {
184        let superchains = Registry::from_chain_list();
185        assert_eq!(
186            *superchains.rollup_configs.get(&10).unwrap(),
187            crate::test_utils::OP_MAINNET_CONFIG
188        );
189    }
190}