arb_chainspec/
lib.rs

1//! Arbitrum chain specification and ArbOS version constants.
2//!
3//! Defines the ArbOS version progression, hardfork timestamps, and the
4//! [`ArbitrumChainSpec`] trait for version-gated EVM spec selection.
5
6use reth_chainspec::ChainSpec;
7pub use reth_chainspec::EthChainSpec;
8use revm::primitives::hardfork::SpecId;
9
10/// ArbOS version constants.
11///
12/// These map to EVM spec upgrades gated by the ArbOS version
13/// stored in the block header's mix_hash.
14pub mod arbos_version {
15    pub const ARBOS_VERSION_2: u64 = 2;
16    pub const ARBOS_VERSION_3: u64 = 3;
17    pub const ARBOS_VERSION_4: u64 = 4;
18    pub const ARBOS_VERSION_5: u64 = 5;
19    pub const ARBOS_VERSION_6: u64 = 6;
20    pub const ARBOS_VERSION_7: u64 = 7;
21    pub const ARBOS_VERSION_8: u64 = 8;
22    pub const ARBOS_VERSION_9: u64 = 9;
23    /// Legacy CollectTips encoding (pre-v10 mix_hash layout).
24    pub const ARBOS_VERSION_COLLECT_TIPS_OLD: u64 = ARBOS_VERSION_9;
25    pub const ARBOS_VERSION_10: u64 = 10;
26    /// ArbOS version 11 — Shanghai EVM rules (PUSH0, etc.).
27    pub const ARBOS_VERSION_11: u64 = 11;
28    /// Gas for scheduled retry txs is subtracted from parent tx gas used.
29    pub const ARBOS_VERSION_FIX_REDEEM_GAS: u64 = ARBOS_VERSION_11;
30    /// ArbOS version 20 — Cancun EVM rules (transient storage, blob base fee).
31    pub const ARBOS_VERSION_20: u64 = 20;
32    /// ArbOS version 30 — Stylus support.
33    pub const ARBOS_VERSION_30: u64 = 30;
34    pub const ARBOS_VERSION_STYLUS: u64 = ARBOS_VERSION_30;
35    /// ArbOS version 31 — Stylus fixes (return data cost check, etc.).
36    pub const ARBOS_VERSION_31: u64 = 31;
37    pub const ARBOS_VERSION_STYLUS_FIXES: u64 = ARBOS_VERSION_31;
38    /// ArbOS version 32 — Stylus charging fixes.
39    pub const ARBOS_VERSION_32: u64 = 32;
40    pub const ARBOS_VERSION_STYLUS_CHARGING_FIXES: u64 = ARBOS_VERSION_32;
41    /// ArbOS version 40 — Prague EVM rules.
42    pub const ARBOS_VERSION_40: u64 = 40;
43    pub const ARBOS_VERSION_STYLUS_LAST_CODE_CACHE_FIX: u64 = ARBOS_VERSION_40;
44    pub const ARBOS_VERSION_41: u64 = 41;
45    /// ArbOS version 50 — Dia upgrade.
46    pub const ARBOS_VERSION_50: u64 = 50;
47    pub const ARBOS_VERSION_DIA: u64 = ARBOS_VERSION_50;
48    /// Maximum ArbOS version supported by this node.
49    pub const MAX_ARBOS_VERSION_SUPPORTED: u64 = ARBOS_VERSION_60;
50    /// ArbOS version 51 — multi-constraint fix.
51    pub const ARBOS_VERSION_MULTI_CONSTRAINT_FIX: u64 = 51;
52    pub const ARBOS_VERSION_51: u64 = 51;
53    pub const ARBOS_VERSION_59: u64 = 59;
54    /// ArbOS version 60 — multi-gas constraints + Stylus contract limit + transaction filtering.
55    pub const ARBOS_VERSION_MULTI_GAS_CONSTRAINTS: u64 = 60;
56    pub const ARBOS_VERSION_60: u64 = 60;
57    pub const ARBOS_VERSION_STYLUS_CONTRACT_LIMIT: u64 = ARBOS_VERSION_60;
58    pub const ARBOS_VERSION_TRANSACTION_FILTERING: u64 = ARBOS_VERSION_60;
59}
60
61/// Trait for Arbitrum chain specifications.
62///
63/// Provides the chain ID and version-gated spec ID mapping
64/// needed by the EVM configuration layer.
65pub trait ArbitrumChainSpec {
66    /// Returns the chain ID.
67    fn chain_id(&self) -> u64;
68
69    /// Maps a timestamp to the appropriate SpecId.
70    fn spec_id_by_timestamp(&self, timestamp: u64) -> SpecId;
71
72    /// Maps an ArbOS version to the appropriate SpecId.
73    fn spec_id_by_arbos_version(&self, arbos_version: u64) -> SpecId;
74}
75
76/// Map ArbOS version to the appropriate SpecId.
77pub fn spec_id_by_arbos_version(arbos_version: u64) -> SpecId {
78    if arbos_version >= arbos_version::ARBOS_VERSION_50 {
79        SpecId::OSAKA
80    } else if arbos_version >= arbos_version::ARBOS_VERSION_40 {
81        SpecId::PRAGUE
82    } else if arbos_version >= arbos_version::ARBOS_VERSION_20 {
83        SpecId::CANCUN
84    } else if arbos_version >= arbos_version::ARBOS_VERSION_11 {
85        SpecId::SHANGHAI
86    } else {
87        SpecId::MERGE
88    }
89}
90
91/// Arbitrum Sepolia hardfork timestamps.
92pub const ARBITRUM_SEPOLIA_SHANGHAI_TIMESTAMP: u64 = 1_706_634_000;
93pub const ARBITRUM_SEPOLIA_CANCUN_TIMESTAMP: u64 = 1_709_229_600;
94pub const ARBITRUM_SEPOLIA_PRAGUE_TIMESTAMP: u64 = 1_746_543_285;
95
96/// Map timestamp to SpecId for Arbitrum Sepolia.
97pub fn arbitrum_sepolia_spec_id_by_timestamp(timestamp: u64) -> SpecId {
98    if timestamp >= ARBITRUM_SEPOLIA_PRAGUE_TIMESTAMP {
99        SpecId::PRAGUE
100    } else if timestamp >= ARBITRUM_SEPOLIA_CANCUN_TIMESTAMP {
101        SpecId::CANCUN
102    } else if timestamp >= ARBITRUM_SEPOLIA_SHANGHAI_TIMESTAMP {
103        SpecId::SHANGHAI
104    } else {
105        SpecId::MERGE
106    }
107}
108
109/// Simple Arbitrum chain spec.
110#[derive(Clone, Debug, Default)]
111pub struct ArbChainSpec {
112    pub chain_id: u64,
113}
114
115impl ArbitrumChainSpec for ArbChainSpec {
116    fn chain_id(&self) -> u64 {
117        self.chain_id
118    }
119
120    fn spec_id_by_timestamp(&self, timestamp: u64) -> SpecId {
121        arbitrum_sepolia_spec_id_by_timestamp(timestamp)
122    }
123
124    fn spec_id_by_arbos_version(&self, arbos_version: u64) -> SpecId {
125        spec_id_by_arbos_version(arbos_version)
126    }
127}
128
129/// Blanket implementation for reth's `ChainSpec`.
130impl ArbitrumChainSpec for ChainSpec {
131    fn chain_id(&self) -> u64 {
132        self.chain().id()
133    }
134
135    fn spec_id_by_timestamp(&self, timestamp: u64) -> SpecId {
136        arbitrum_sepolia_spec_id_by_timestamp(timestamp)
137    }
138
139    fn spec_id_by_arbos_version(&self, arbos_version: u64) -> SpecId {
140        spec_id_by_arbos_version(arbos_version)
141    }
142}
143
144/// Arbitrum One chain ID.
145pub const ARBITRUM_ONE_CHAIN_ID: u64 = 42161;
146
147/// Arbitrum Sepolia chain ID.
148pub const ARBITRUM_SEPOLIA_CHAIN_ID: u64 = 421614;