From 0a318063b9c73db9eeaef355905e4ab5b97c3038 Mon Sep 17 00:00:00 2001 From: Yuwen Zhang Date: Mon, 30 Sep 2024 11:03:31 -0700 Subject: [PATCH] feat(protocol): operator fee --- crates/genesis/src/chain.rs | 3 + crates/genesis/src/rollup.rs | 31 +++- crates/protocol/src/info/errors.rs | 6 + crates/protocol/src/info/isthmus.rs | 137 ++++++++++++++++++ crates/protocol/src/info/mod.rs | 3 + crates/protocol/src/info/variant.rs | 84 ++++++++++- crates/protocol/src/lib.rs | 3 +- crates/protocol/src/utils.rs | 9 +- .../registry/src/test_utils/base_mainnet.rs | 1 + .../registry/src/test_utils/base_sepolia.rs | 1 + crates/registry/src/test_utils/op_mainnet.rs | 1 + crates/registry/src/test_utils/op_sepolia.rs | 1 + 12 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 crates/protocol/src/info/isthmus.rs diff --git a/crates/genesis/src/chain.rs b/crates/genesis/src/chain.rs index 33056d36..923a2328 100644 --- a/crates/genesis/src/chain.rs +++ b/crates/genesis/src/chain.rs @@ -53,6 +53,8 @@ pub struct HardForkConfiguration { pub granite_time: Option, /// Holocene hardfork activation time pub holocene_time: Option, + /// Isthmus hardfork activation time + pub isthmus_time: Option, } /// Defines core blockchain settings per block. @@ -215,6 +217,7 @@ impl ChainConfig { fjord_time: self.hardfork_configuration.fjord_time, granite_time: self.hardfork_configuration.granite_time, holocene_time: self.hardfork_configuration.holocene_time, + isthmus_time: self.hardfork_configuration.isthmus_time, batch_inbox_address: self.batch_inbox_addr, deposit_contract_address: self .addresses diff --git a/crates/genesis/src/rollup.rs b/crates/genesis/src/rollup.rs index 33413636..0eca7a14 100644 --- a/crates/genesis/src/rollup.rs +++ b/crates/genesis/src/rollup.rs @@ -91,6 +91,11 @@ pub struct RollupConfig { /// otherwise. #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub holocene_time: Option, + /// `isthmus_time` sets the activation time for the Isthmus network upgrade. + /// Active if `isthmus_time` != None && L2 block timestamp >= Some(isthmus_time), inactive + /// otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + pub isthmus_time: Option, /// `batch_inbox_address` is the L1 address that batches are sent to. pub batch_inbox_address: Address, /// `deposit_contract_address` is the L1 address that deposits are sent to. @@ -144,6 +149,7 @@ impl<'a> arbitrary::Arbitrary<'a> for RollupConfig { fjord_time: Option::::arbitrary(u)?, granite_time: Option::::arbitrary(u)?, holocene_time: Option::::arbitrary(u)?, + isthmus_time: Option::::arbitrary(u)?, batch_inbox_address: Address::arbitrary(u)?, deposit_contract_address: Address::arbitrary(u)?, l1_system_config_address: Address::arbitrary(u)?, @@ -177,6 +183,7 @@ impl Default for RollupConfig { fjord_time: None, granite_time: None, holocene_time: None, + isthmus_time: None, batch_inbox_address: Address::ZERO, deposit_contract_address: Address::ZERO, l1_system_config_address: Address::ZERO, @@ -221,7 +228,12 @@ impl RollupConfig { /// Returns true if Holocene is active at the given timestamp. pub fn is_holocene_active(&self, timestamp: u64) -> bool { - self.holocene_time.map_or(false, |t| timestamp >= t) + self.holocene_time.map_or(false, |t| timestamp >= t) || self.is_isthmus_active(timestamp) + } + + /// Returns true if Isthmus is active at the given timestamp. + pub fn is_isthmus_active(&self, timestamp: u64) -> bool { + self.isthmus_time.map_or(false, |t| timestamp >= t) } /// Returns true if a DA Challenge proxy Address is provided in the rollup config and the @@ -266,6 +278,7 @@ impl RollupConfig { fjord_time: self.fjord_time, granite_time: self.granite_time, holocene_time: self.holocene_time, + isthmus_time: self.isthmus_time, } } @@ -395,6 +408,22 @@ mod tests { assert!(!config.is_holocene_active(9)); } + #[test] + fn test_isthmus_active() { + let mut config = RollupConfig::default(); + assert!(!config.is_isthmus_active(0)); + config.isthmus_time = Some(10); + assert!(config.is_regolith_active(10)); + assert!(config.is_canyon_active(10)); + assert!(config.is_delta_active(10)); + assert!(config.is_ecotone_active(10)); + assert!(config.is_fjord_active(10)); + assert!(config.is_granite_active(10)); + assert!(config.is_holocene_active(10)); + assert!(config.is_isthmus_active(10)); + assert!(!config.is_isthmus_active(9)); + } + #[test] fn test_alt_da_enabled() { let mut config = RollupConfig::default(); diff --git a/crates/protocol/src/info/errors.rs b/crates/protocol/src/info/errors.rs index 89599e9a..9b2e6a34 100644 --- a/crates/protocol/src/info/errors.rs +++ b/crates/protocol/src/info/errors.rs @@ -17,6 +17,12 @@ pub enum BlockInfoError { /// Failed to parse the EIP-1559 elasticity parameter. #[error("Failed to parse the EIP-1559 elasticity parameter")] Eip1559Elasticity, + /// Failed to parse the Operator Fee Scalar. + #[error("Failed to parse the Operator fee scalar parameter")] + OperatorFeeScalar, + /// Failed to parse the Operator Fee Constant. + #[error("Failed to parse the Operator fee constant parameter")] + OperatorFeeConstant, } /// An error decoding an L1 block info transaction. diff --git a/crates/protocol/src/info/isthmus.rs b/crates/protocol/src/info/isthmus.rs new file mode 100644 index 00000000..695be9ed --- /dev/null +++ b/crates/protocol/src/info/isthmus.rs @@ -0,0 +1,137 @@ +//! Isthmus L1 Block Info transaction types. + +use alloc::{format, string::ToString, vec::Vec}; +use alloy_primitives::{Address, Bytes, B256, U256}; + +use crate::DecodeError; + +/// Represents the fields within an Isthnus L1 block info transaction. +/// +/// Holocene Binary Format +/// +---------+--------------------------+ +/// | Bytes | Field | +/// +---------+--------------------------+ +/// | 4 | Function signature | +/// | 4 | BaseFeeScalar | +/// | 4 | BlobBaseFeeScalar | +/// | 8 | SequenceNumber | +/// | 8 | Timestamp | +/// | 8 | L1BlockNumber | +/// | 32 | BaseFee | +/// | 32 | BlobBaseFee | +/// | 32 | BlockHash | +/// | 32 | BatcherHash | +/// | 4 | OperatorFeeScalar | +/// | 8 | OperatorFeeConstant | +/// +---------+--------------------------+ +#[derive(Debug, Clone, Hash, Eq, PartialEq, Default, Copy)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct L1BlockInfoIsthmus { + /// The current L1 origin block number + pub number: u64, + /// The current L1 origin block's timestamp + pub time: u64, + /// The current L1 origin block's basefee + pub base_fee: u64, + /// The current L1 origin block's hash + pub block_hash: B256, + /// The current sequence number + pub sequence_number: u64, + /// The address of the batch submitter + pub batcher_address: Address, + /// The current blob base fee on L1 + pub blob_base_fee: u128, + /// The fee scalar for L1 blobspace data + pub blob_base_fee_scalar: u32, + /// The fee scalar for L1 data + pub base_fee_scalar: u32, + /// The operator fee scalar + pub operator_fee_scalar: u32, + /// The operator fee constant + pub operator_fee_constant: u64, +} + +impl L1BlockInfoIsthmus { + /// The type byte identifier for the L1 scalar format in Isthmus. + pub const L1_SCALAR: u8 = 2; + + /// The length of an L1 info transaction in Isthmus. + pub const L1_INFO_TX_LEN: usize = 4 + 32 * 5 + 4 + 8; + + /// The 4 byte selector of "setL1BlockValuesIsthmus()" + pub const L1_INFO_TX_SELECTOR: [u8; 4] = [0x09, 0x89, 0x99, 0xbe]; + + /// Encodes the [L1BlockInfoIsthmus] object into Ethereum transaction calldata. + pub fn encode_calldata(&self) -> Bytes { + let mut buf = Vec::with_capacity(Self::L1_INFO_TX_LEN); + buf.extend_from_slice(Self::L1_INFO_TX_SELECTOR.as_ref()); + buf.extend_from_slice(self.base_fee_scalar.to_be_bytes().as_ref()); + buf.extend_from_slice(self.blob_base_fee_scalar.to_be_bytes().as_ref()); + buf.extend_from_slice(self.sequence_number.to_be_bytes().as_ref()); + buf.extend_from_slice(self.time.to_be_bytes().as_ref()); + buf.extend_from_slice(self.number.to_be_bytes().as_ref()); + buf.extend_from_slice(U256::from(self.base_fee).to_be_bytes::<32>().as_ref()); + buf.extend_from_slice(U256::from(self.blob_base_fee).to_be_bytes::<32>().as_ref()); + buf.extend_from_slice(self.block_hash.as_ref()); + buf.extend_from_slice(self.batcher_address.into_word().as_ref()); + buf.extend_from_slice(self.operator_fee_scalar.to_be_bytes().as_ref()); + buf.extend_from_slice(self.operator_fee_constant.to_be_bytes().as_ref()); + buf.into() + } + + /// Decodes the [L1BlockInfoIsthmus] object from ethereum transaction calldata. + pub fn decode_calldata(r: &[u8]) -> Result { + if r.len() != Self::L1_INFO_TX_LEN { + return Err(DecodeError::InvalidLength(format!( + "Invalid calldata length for Isthmus L1 info transaction, expected {}, got {}", + Self::L1_INFO_TX_LEN, + r.len() + ))); + } + let base_fee_scalar = u32::from_be_bytes(r[4..8].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for base fee scalar".to_string()) + })?); + let blob_base_fee_scalar = u32::from_be_bytes(r[8..12].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for blob base fee scalar".to_string()) + })?); + let sequence_number = u64::from_be_bytes(r[12..20].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for sequence number".to_string()) + })?); + let time = + u64::from_be_bytes(r[20..28].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for timestamp".to_string()) + })?); + let number = u64::from_be_bytes(r[28..36].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for L1 block number".to_string()) + })?); + let base_fee = + u64::from_be_bytes(r[60..68].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for base fee".to_string()) + })?); + let blob_base_fee = u128::from_be_bytes(r[84..100].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for blob base fee".to_string()) + })?); + let block_hash = B256::from_slice(r[100..132].as_ref()); + let batcher_address = Address::from_slice(r[144..164].as_ref()); + let operator_fee_scalar = u32::from_be_bytes(r[164..168].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for operator fee scalar".to_string()) + })?); + let operator_fee_constant = u64::from_be_bytes(r[168..176].try_into().map_err(|_| { + DecodeError::ParseError("Conversion error for operator fee constant".to_string()) + })?); + + Ok(Self { + number, + time, + base_fee, + block_hash, + sequence_number, + batcher_address, + blob_base_fee, + blob_base_fee_scalar, + base_fee_scalar, + operator_fee_scalar, + operator_fee_constant, + }) + } +} diff --git a/crates/protocol/src/info/mod.rs b/crates/protocol/src/info/mod.rs index 12e674c3..368b2bbe 100644 --- a/crates/protocol/src/info/mod.rs +++ b/crates/protocol/src/info/mod.rs @@ -9,5 +9,8 @@ pub use bedrock::L1BlockInfoBedrock; mod ecotone; pub use ecotone::L1BlockInfoEcotone; +mod isthmus; +pub use isthmus::L1BlockInfoIsthmus; + mod errors; pub use errors::{BlockInfoError, DecodeError}; diff --git a/crates/protocol/src/info/variant.rs b/crates/protocol/src/info/variant.rs index 2dd09bf1..c6f832d5 100644 --- a/crates/protocol/src/info/variant.rs +++ b/crates/protocol/src/info/variant.rs @@ -10,7 +10,7 @@ use op_alloy_genesis::{RollupConfig, SystemConfig}; use crate::{ BlockInfoError, DecodeError, DepositSourceDomain, L1BlockInfoBedrock, L1BlockInfoEcotone, - L1InfoDepositSource, + L1BlockInfoIsthmus, L1InfoDepositSource, }; /// The system transaction gas limit post-Regolith @@ -34,6 +34,8 @@ pub enum L1BlockInfoTx { Bedrock(L1BlockInfoBedrock), /// An Ecotone L1 info transaction Ecotone(L1BlockInfoEcotone), + /// An Isthmus L1 info transaction + Isthmus(L1BlockInfoIsthmus), } impl L1BlockInfoTx { @@ -45,6 +47,49 @@ impl L1BlockInfoTx { l1_header: &Header, l2_block_time: u64, ) -> Result { + if rollup_config.is_isthmus_active(l2_block_time) { + let scalar = system_config.scalar.to_be_bytes::<32>(); + let blob_base_fee_scalar = (scalar[0] >= L1BlockInfoEcotone::L1_SCALAR) + .then(|| { + Ok::(u32::from_be_bytes( + scalar[24..28] + .try_into() + .map_err(|_| BlockInfoError::L1BlobBaseFeeScalar)?, + )) + }) + .transpose()? + .unwrap_or_default(); + let base_fee_scalar = u32::from_be_bytes( + scalar[28..32].try_into().map_err(|_| BlockInfoError::BaseFeeScalar)?, + ); + let (operator_fee_scalar, operator_fee_constant) = if scalar[0] + == L1BlockInfoIsthmus::L1_SCALAR + { + let operator_fee_scalar = Ok::(u32::from_be_bytes( + scalar[12..16].try_into().map_err(|_| BlockInfoError::OperatorFeeScalar)?, + ))?; + let operator_fee_constant = Ok::(u64::from_be_bytes( + scalar[16..24].try_into().map_err(|_| BlockInfoError::OperatorFeeConstant)?, + ))?; + (operator_fee_scalar, operator_fee_constant) + } else { + (0, 0) + }; + return Ok(Self::Isthmus(L1BlockInfoIsthmus { + number: l1_header.number, + time: l1_header.timestamp, + base_fee: l1_header.base_fee_per_gas.unwrap_or(0), + block_hash: l1_header.hash_slow(), + sequence_number, + batcher_address: system_config.batcher_address, + blob_base_fee: l1_header.blob_fee().unwrap_or(1), + blob_base_fee_scalar, + base_fee_scalar, + operator_fee_scalar, + operator_fee_constant, + })); + } + // In the first block of Ecotone, the L1Block contract has not been upgraded yet due to the // upgrade transactions being placed after the L1 info transaction. Because of this, // for the first block of Ecotone, we send a Bedrock style L1 block info transaction @@ -145,6 +190,9 @@ impl L1BlockInfoTx { L1BlockInfoEcotone::L1_INFO_TX_SELECTOR => L1BlockInfoEcotone::decode_calldata(r) .map(Self::Ecotone) .map_err(|e| DecodeError::ParseError(format!("Ecotone decode error: {}", e))), + L1BlockInfoIsthmus::L1_INFO_TX_SELECTOR => L1BlockInfoIsthmus::decode_calldata(r) + .map(Self::Isthmus) + .map_err(|e| DecodeError::ParseError(format!("Isthmus decode error: {}", e))), _ => Err(DecodeError::InvalidSelector), } } @@ -154,6 +202,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(ref tx) => tx.block_hash, Self::Ecotone(ref tx) => tx.block_hash, + Self::Isthmus(ref tx) => tx.block_hash, } } @@ -162,6 +211,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(bedrock_tx) => bedrock_tx.encode_calldata(), Self::Ecotone(ecotone_tx) => ecotone_tx.encode_calldata(), + Self::Isthmus(isthmus_tx) => isthmus_tx.encode_calldata(), } } @@ -174,6 +224,9 @@ impl L1BlockInfoTx { Self::Bedrock(L1BlockInfoBedrock { number, block_hash, .. }) => { BlockNumHash { number: *number, hash: *block_hash } } + Self::Isthmus(L1BlockInfoIsthmus { number, block_hash, .. }) => { + BlockNumHash { number: *number, hash: *block_hash } + } } } @@ -182,6 +235,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(L1BlockInfoBedrock { l1_fee_overhead, .. }) => *l1_fee_overhead, Self::Ecotone(_) => U256::ZERO, + Self::Isthmus(_) => U256::ZERO, } } @@ -190,6 +244,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(L1BlockInfoBedrock { batcher_address, .. }) => *batcher_address, Self::Ecotone(L1BlockInfoEcotone { batcher_address, .. }) => *batcher_address, + Self::Isthmus(L1BlockInfoIsthmus { batcher_address, .. }) => *batcher_address, } } @@ -198,6 +253,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(L1BlockInfoBedrock { sequence_number, .. }) => *sequence_number, Self::Ecotone(L1BlockInfoEcotone { sequence_number, .. }) => *sequence_number, + Self::Isthmus(L1BlockInfoIsthmus { sequence_number, .. }) => *sequence_number, } } } @@ -210,6 +266,7 @@ mod test { const RAW_BEDROCK_INFO_TX: [u8; L1BlockInfoBedrock::L1_INFO_TX_LEN] = hex!("015d8eb9000000000000000000000000000000000000000000000000000000000117c4eb0000000000000000000000000000000000000000000000000000000065280377000000000000000000000000000000000000000000000000000000026d05d953392012032675be9f94aae5ab442de73c5f4fb1bf30fa7dd0d2442239899a40fc00000000000000000000000000000000000000000000000000000000000000040000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f3298500000000000000000000000000000000000000000000000000000000000000bc00000000000000000000000000000000000000000000000000000000000a6fe0"); const RAW_ECOTONE_INFO_TX: [u8; L1BlockInfoEcotone::L1_INFO_TX_LEN] = hex!("440a5e2000000558000c5fc5000000000000000500000000661c277300000000012bec20000000000000000000000000000000000000000000000000000000026e9f109900000000000000000000000000000000000000000000000000000000000000011c4c84c50740386c7dc081efddd644405f04cde73e30a2e381737acce9f5add30000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985"); + const RAW_ISTHMUS_INFO_TX: [u8; L1BlockInfoIsthmus::L1_INFO_TX_LEN] = hex!("098999be00000558000c5fc5000000000000000500000000661c277300000000012bec20000000000000000000000000000000000000000000000000000000026e9f109900000000000000000000000000000000000000000000000000000000000000011c4c84c50740386c7dc081efddd644405f04cde73e30a2e381737acce9f5add30000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f329850000abcd000000000000dcba"); #[test] fn bedrock_l1_block_info_invalid_len() { @@ -300,6 +357,31 @@ mod test { assert_eq!(decoded.encode_calldata().as_ref(), RAW_ECOTONE_INFO_TX); } + #[test] + fn test_isthmus_l1_block_info_tx_roundtrip() { + let expected = L1BlockInfoIsthmus { + number: 19655712, + time: 1713121139, + base_fee: 10445852825, + block_hash: b256!("1c4c84c50740386c7dc081efddd644405f04cde73e30a2e381737acce9f5add3"), + sequence_number: 5, + batcher_address: address!("6887246668a3b87f54deb3b94ba47a6f63f32985"), + blob_base_fee: 1, + blob_base_fee_scalar: 810949, + base_fee_scalar: 1368, + operator_fee_scalar: 0xabcd, + operator_fee_constant: 0xdcba, + }; + + let L1BlockInfoTx::Isthmus(decoded) = + L1BlockInfoTx::decode_calldata(RAW_ISTHMUS_INFO_TX.as_ref()).unwrap() + else { + panic!("Wrong fork"); + }; + assert_eq!(expected, decoded); + assert_eq!(decoded.encode_calldata().as_ref(), RAW_ISTHMUS_INFO_TX); + } + #[test] fn try_new_with_deposit_tx_bedrock() { let rollup_config = RollupConfig::default(); diff --git a/crates/protocol/src/lib.rs b/crates/protocol/src/lib.rs index 5693cbbb..ca1f7205 100644 --- a/crates/protocol/src/lib.rs +++ b/crates/protocol/src/lib.rs @@ -61,7 +61,8 @@ pub use deposits::{ mod info; pub use info::{ - BlockInfoError, DecodeError, L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoTx, + BlockInfoError, DecodeError, L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoIsthmus, + L1BlockInfoTx, }; mod fee; diff --git a/crates/protocol/src/utils.rs b/crates/protocol/src/utils.rs index a36e7bf0..77b0e215 100644 --- a/crates/protocol/src/utils.rs +++ b/crates/protocol/src/utils.rs @@ -8,8 +8,8 @@ use op_alloy_consensus::{OpBlock, OpTxEnvelope}; use op_alloy_genesis::{RollupConfig, SystemConfig}; use crate::{ - L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoTx, OpBlockConversionError, SpanBatchError, - SpanDecodingError, + L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoIsthmus, L1BlockInfoTx, + OpBlockConversionError, SpanBatchError, SpanDecodingError, }; /// Returns if the given `value` is a deposit transaction. @@ -54,6 +54,11 @@ pub fn to_system_config( base_fee_scalar, blob_base_fee_scalar, .. + }) + | L1BlockInfoTx::Isthmus(L1BlockInfoIsthmus { + base_fee_scalar, + blob_base_fee_scalar, + .. }) => { // Translate Ecotone values back into encoded scalar if needed. // We do not know if it was derived from a v0 or v1 scalar, diff --git a/crates/registry/src/test_utils/base_mainnet.rs b/crates/registry/src/test_utils/base_mainnet.rs index 6831e0a3..4a07f949 100644 --- a/crates/registry/src/test_utils/base_mainnet.rs +++ b/crates/registry/src/test_utils/base_mainnet.rs @@ -43,6 +43,7 @@ pub const BASE_MAINNET_CONFIG: RollupConfig = RollupConfig { fjord_time: Some(1720627201), granite_time: Some(1_726_070_401_u64), holocene_time: None, + isthmus_time: None, batch_inbox_address: address!("ff00000000000000000000000000000000008453"), deposit_contract_address: address!("49048044d57e1c92a77f79988d21fa8faf74e97e"), l1_system_config_address: address!("73a79fab69143498ed3712e519a88a918e1f4072"), diff --git a/crates/registry/src/test_utils/base_sepolia.rs b/crates/registry/src/test_utils/base_sepolia.rs index 9c44567c..b70f94c4 100644 --- a/crates/registry/src/test_utils/base_sepolia.rs +++ b/crates/registry/src/test_utils/base_sepolia.rs @@ -43,6 +43,7 @@ pub const BASE_SEPOLIA_CONFIG: RollupConfig = RollupConfig { fjord_time: Some(1716998400), granite_time: Some(1723478400), holocene_time: Some(1732633200), + isthmus_time: None, batch_inbox_address: address!("ff00000000000000000000000000000000084532"), deposit_contract_address: address!("49f53e41452c74589e85ca1677426ba426459e85"), l1_system_config_address: address!("f272670eb55e895584501d564afeb048bed26194"), diff --git a/crates/registry/src/test_utils/op_mainnet.rs b/crates/registry/src/test_utils/op_mainnet.rs index cb66d3d9..00228d6c 100644 --- a/crates/registry/src/test_utils/op_mainnet.rs +++ b/crates/registry/src/test_utils/op_mainnet.rs @@ -43,6 +43,7 @@ pub const OP_MAINNET_CONFIG: RollupConfig = RollupConfig { fjord_time: Some(1_720_627_201_u64), granite_time: Some(1_726_070_401_u64), holocene_time: None, + isthmus_time: None, batch_inbox_address: address!("ff00000000000000000000000000000000000010"), deposit_contract_address: address!("beb5fc579115071764c7423a4f12edde41f106ed"), l1_system_config_address: address!("229047fed2591dbec1ef1118d64f7af3db9eb290"), diff --git a/crates/registry/src/test_utils/op_sepolia.rs b/crates/registry/src/test_utils/op_sepolia.rs index 560ef53b..08044223 100644 --- a/crates/registry/src/test_utils/op_sepolia.rs +++ b/crates/registry/src/test_utils/op_sepolia.rs @@ -43,6 +43,7 @@ pub const OP_SEPOLIA_CONFIG: RollupConfig = RollupConfig { fjord_time: Some(1716998400), granite_time: Some(1723478400), holocene_time: Some(1732633200), + isthmus_time: None, batch_inbox_address: address!("ff00000000000000000000000000000011155420"), deposit_contract_address: address!("16fc5058f25648194471939df75cf27a2fdc48bc"), l1_system_config_address: address!("034edd2a225f7f429a63e0f1d2084b9e0a93b538"),