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