espresso_types/v0/v0_1/
chain_config.rs

1use alloy::primitives::{Address, U256};
2use alloy_compat::ethers_serde;
3use committable::{Commitment, Committable};
4use derive_more::{Deref, Display, From, Into};
5use itertools::Either;
6
7use serde::{Deserialize, Serialize};
8
9use crate::{FeeAccount, FeeAmount};
10
11#[derive(Default, Hash, Copy, Clone, Debug, Display, PartialEq, Eq, From, Into)]
12#[display("{_0}")]
13pub struct ChainId(pub U256);
14
15#[derive(Hash, Copy, Clone, Debug, Default, Display, PartialEq, Eq, From, Into, Deref)]
16#[display("{_0}")]
17pub struct BlockSize(pub(crate) u64);
18
19/// Global variables for an Espresso blockchain.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub struct ChainConfig {
22    /// Espresso chain ID
23    pub chain_id: ChainId,
24
25    /// Maximum size in bytes of a block
26    pub max_block_size: BlockSize,
27
28    /// Minimum fee in WEI per byte of payload
29    pub base_fee: FeeAmount,
30
31    /// Fee contract address on L1.
32    ///
33    /// This is optional so that fees can easily be toggled on/off, with no need to deploy a
34    /// contract when they are off. In a future release, after fees are switched on and thoroughly
35    /// tested, this may be made mandatory.
36    #[serde(with = "ethers_serde::option_address")]
37    pub fee_contract: Option<Address>,
38
39    /// Account that receives sequencing fees.
40    ///
41    /// This account in the Espresso fee ledger will always receive every fee paid in Espresso,
42    /// regardless of whether or not their is a `fee_contract` deployed. Once deployed, the fee
43    /// contract can decide what to do with tokens locked in this account in Espresso.
44    pub fee_recipient: FeeAccount,
45}
46
47#[derive(Clone, Debug, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)]
48pub struct ResolvableChainConfig {
49    pub(crate) chain_config: Either<ChainConfig, Commitment<ChainConfig>>,
50}
51
52impl Committable for ChainConfig {
53    fn tag() -> String {
54        "CHAIN_CONFIG".to_string()
55    }
56
57    fn commit(&self) -> Commitment<Self> {
58        let comm = committable::RawCommitmentBuilder::new(&Self::tag())
59            .fixed_size_field("chain_id", &self.chain_id.to_fixed_bytes())
60            .u64_field("max_block_size", *self.max_block_size)
61            .fixed_size_field("base_fee", &self.base_fee.to_fixed_bytes())
62            .fixed_size_field("fee_recipient", &self.fee_recipient.to_fixed_bytes());
63        let comm = if let Some(addr) = self.fee_contract {
64            comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0)
65        } else {
66            comm.u64_field("fee_contract", 0)
67        };
68        comm.finalize()
69    }
70}
71
72impl ResolvableChainConfig {
73    pub fn commit(&self) -> Commitment<ChainConfig> {
74        match self.chain_config {
75            Either::Left(config) => config.commit(),
76            Either::Right(commitment) => commitment,
77        }
78    }
79    pub fn resolve(self) -> Option<ChainConfig> {
80        match self.chain_config {
81            Either::Left(config) => Some(config),
82            Either::Right(_) => None,
83        }
84    }
85}
86
87impl From<Commitment<ChainConfig>> for ResolvableChainConfig {
88    fn from(value: Commitment<ChainConfig>) -> Self {
89        Self {
90            chain_config: Either::Right(value),
91        }
92    }
93}
94
95impl From<ChainConfig> for ResolvableChainConfig {
96    fn from(value: ChainConfig) -> Self {
97        Self {
98            chain_config: Either::Left(value),
99        }
100    }
101}
102
103impl Default for ChainConfig {
104    fn default() -> Self {
105        Self {
106            chain_id: U256::from(35353).into(), // arbitrarily chosen chain ID
107            max_block_size: 30720.into(),
108            base_fee: 0.into(),
109            fee_contract: None,
110            fee_recipient: Default::default(),
111        }
112    }
113}