diff --git a/crates/genesis/src/genesis.rs b/crates/genesis/src/genesis.rs index 1cbd4023..f2d9b653 100644 --- a/crates/genesis/src/genesis.rs +++ b/crates/genesis/src/genesis.rs @@ -60,6 +60,8 @@ mod tests { blob_base_fee_scalar: None, eip1559_denominator: None, eip1559_elasticity: None, + operator_fee_scalar: None, + operator_fee_constant: None, }), } } diff --git a/crates/genesis/src/lib.rs b/crates/genesis/src/lib.rs index 7676f9d8..5cb5b813 100644 --- a/crates/genesis/src/lib.rs +++ b/crates/genesis/src/lib.rs @@ -33,8 +33,9 @@ pub use addresses::AddressList; mod system; pub use system::{ BatcherUpdateError, EIP1559UpdateError, GasConfigUpdateError, GasLimitUpdateError, - LogProcessingError, SystemAccounts, SystemConfig, SystemConfigUpdateError, - SystemConfigUpdateType, CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC, + LogProcessingError, OperatorFeeUpdateError, SystemAccounts, SystemConfig, + SystemConfigUpdateError, SystemConfigUpdateType, CONFIG_UPDATE_EVENT_VERSION_0, + CONFIG_UPDATE_TOPIC, }; mod chain; diff --git a/crates/genesis/src/rollup.rs b/crates/genesis/src/rollup.rs index 6cdd33f0..3a2c523c 100644 --- a/crates/genesis/src/rollup.rs +++ b/crates/genesis/src/rollup.rs @@ -600,6 +600,8 @@ mod tests { blob_base_fee_scalar: None, eip1559_denominator: None, eip1559_elasticity: None, + operator_fee_scalar: None, + operator_fee_constant: None, }) } ); diff --git a/crates/genesis/src/system.rs b/crates/genesis/src/system.rs index 45d15ad1..656ef653 100644 --- a/crates/genesis/src/system.rs +++ b/crates/genesis/src/system.rs @@ -36,6 +36,10 @@ pub struct SystemConfig { pub eip1559_denominator: Option, /// EIP-1559 elasticity pub eip1559_elasticity: Option, + /// The operator fee scalar (isthmus hardfork) + pub operator_fee_scalar: Option, + /// The operator fee constant (isthmus hardfork) + pub operator_fee_constant: Option, } /// Represents type of update to the system config. @@ -52,6 +56,8 @@ pub enum SystemConfigUpdateType { UnsafeBlockSigner = 3, /// EIP-1559 parameters update type Eip1559 = 4, + /// Operator fee parameter update + OperatorFee = 5, } impl TryFrom for SystemConfigUpdateType { @@ -64,6 +70,7 @@ impl TryFrom for SystemConfigUpdateType { 2 => Ok(Self::GasLimit), 3 => Ok(Self::UnsafeBlockSigner), 4 => Ok(Self::Eip1559), + 5 => Ok(Self::OperatorFee), _ => Err(SystemConfigUpdateError::LogProcessing( LogProcessingError::InvalidSystemConfigUpdateType(value), )), @@ -180,6 +187,9 @@ impl SystemConfig { SystemConfigUpdateType::Eip1559 => { self.update_eip1559_params(log_data).map_err(SystemConfigUpdateError::Eip1559) } + SystemConfigUpdateType::OperatorFee => self + .update_operator_fee_params(log_data) + .map_err(SystemConfigUpdateError::OperatorFee), // Ignored in derivation SystemConfigUpdateType::UnsafeBlockSigner => { Ok(SystemConfigUpdateType::UnsafeBlockSigner) @@ -323,6 +333,41 @@ impl SystemConfig { Ok(SystemConfigUpdateType::Eip1559) } + + /// Updates the operator fee parameters of the [SystemConfig] given the log data. + pub fn update_operator_fee_params( + &mut self, + log_data: &[u8], + ) -> Result { + if log_data.len() != 128 { + return Err(OperatorFeeUpdateError::InvalidDataLen(log_data.len())); + } + + let Ok(pointer) = ::abi_decode(&log_data[0..32], true) else { + return Err(OperatorFeeUpdateError::PointerDecodingError); + }; + if pointer != 32 { + return Err(OperatorFeeUpdateError::InvalidDataPointer(pointer)); + } + let Ok(length) = ::abi_decode(&log_data[32..64], true) else { + return Err(OperatorFeeUpdateError::LengthDecodingError); + }; + if length != 64 { + return Err(OperatorFeeUpdateError::InvalidDataLength(length)); + } + + let Ok(operator_fee_scalar) = ::abi_decode(&log_data[64..80], true) else { + return Err(OperatorFeeUpdateError::ScalarDecodingError); + }; + let Ok(operator_fee_constant) = ::abi_decode(&log_data[80..], true) else { + return Err(OperatorFeeUpdateError::ConstantDecodingError); + }; + + self.operator_fee_scalar = Some(operator_fee_scalar); + self.operator_fee_constant = Some(operator_fee_constant); + + Ok(SystemConfigUpdateType::OperatorFee) + } } /// An error for processing the [SystemConfig] update log. @@ -344,6 +389,9 @@ pub enum SystemConfigUpdateError { /// An EIP-1559 parameter update error. #[error("EIP-1559 parameter update error: {0}")] Eip1559(EIP1559UpdateError), + /// An operator fee parameter update error. + #[error("Operator fee parameter update error: {0}")] + OperatorFee(OperatorFeeUpdateError), } /// An error occurred while processing the update log. @@ -466,6 +514,33 @@ pub enum EIP1559UpdateError { EIP1559DecodingError, } +/// An error for updating the operator fee parameters on the [SystemConfig]. +#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OperatorFeeUpdateError { + /// Invalid data length. + #[error("Invalid config update log: invalid data length: {0}")] + InvalidDataLen(usize), + /// Failed to decode the data pointer argument from the eip 1559 update log. + #[error("Failed to decode eip1559 parameter update log: data pointer")] + PointerDecodingError, + /// The data pointer is invalid. + #[error("Invalid config update log: invalid data pointer: {0}")] + InvalidDataPointer(u64), + /// Failed to decode the data length argument from the eip 1559 update log. + #[error("Failed to decode eip1559 parameter update log: data length")] + LengthDecodingError, + /// The data length is invalid. + #[error("Invalid config update log: invalid data length: {0}")] + InvalidDataLength(u64), + /// Failed to decode the scalar argument from the update log. + #[error("Failed to decode operator fee parameter update log: scalar")] + ScalarDecodingError, + /// Failed to decode the constant argument from the update log. + #[error("Failed to decode operator fee parameter update log: constant")] + ConstantDecodingError, +} + /// System accounts #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 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..425ba96f --- /dev/null +++ b/crates/protocol/src/info/isthmus.rs @@ -0,0 +1,136 @@ +//! 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. +/// +/// Isthmus 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 fc184b08..108a52dd 100644 --- a/crates/protocol/src/info/mod.rs +++ b/crates/protocol/src/info/mod.rs @@ -3,6 +3,9 @@ mod variant; pub use variant::L1BlockInfoTx; +mod isthmus; +pub use isthmus::L1BlockInfoIsthmus; + mod bedrock; pub use bedrock::L1BlockInfoBedrock; diff --git a/crates/protocol/src/info/variant.rs b/crates/protocol/src/info/variant.rs index 34d094dd..0f4abda4 100644 --- a/crates/protocol/src/info/variant.rs +++ b/crates/protocol/src/info/variant.rs @@ -8,9 +8,10 @@ use alloy_primitives::{address, Address, Bytes, Sealable, Sealed, TxKind, B256, use maili_genesis::{RollupConfig, SystemConfig}; use op_alloy_consensus::{DepositSourceDomain, L1InfoDepositSource, TxDeposit}; -use crate::{BlockInfoError, DecodeError, L1BlockInfoBedrock, L1BlockInfoEcotone}; - -use super::L1BlockInfoInterop; +use crate::{ + BlockInfoError, DecodeError, L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoInterop, + L1BlockInfoIsthmus, +}; /// The system transaction gas limit post-Regolith const REGOLITH_SYSTEM_TX_GAS: u64 = 1_000_000; @@ -36,6 +37,8 @@ pub enum L1BlockInfoTx { Ecotone(L1BlockInfoEcotone), /// An Interop L1 info transaction Interop(L1BlockInfoInterop), + /// An Isthmus L1 info transaction + Isthmus(L1BlockInfoIsthmus), } impl L1BlockInfoTx { @@ -85,7 +88,7 @@ impl L1BlockInfoTx { if rollup_config.is_interop_active(l2_block_time) && rollup_config.interop_time.unwrap_or_default() != l2_block_time { - Ok(Self::Interop(L1BlockInfoInterop { + return Ok(Self::Interop(L1BlockInfoInterop { number: l1_header.number, time: l1_header.timestamp, base_fee: l1_header.base_fee_per_gas.unwrap_or(0), @@ -95,9 +98,15 @@ impl L1BlockInfoTx { blob_base_fee: l1_header.blob_fee(BlobParams::cancun()).unwrap_or(1), blob_base_fee_scalar, base_fee_scalar, - })) - } else { - Ok(Self::Ecotone(L1BlockInfoEcotone { + })); + } + + if rollup_config.is_isthmus_active(l2_block_time) + && rollup_config.isthmus_time.unwrap_or_default() != l2_block_time + { + let operator_fee_scalar = system_config.operator_fee_scalar.unwrap_or_default(); + let operator_fee_constant = system_config.operator_fee_constant.unwrap_or_default(); + return Ok(Self::Isthmus(L1BlockInfoIsthmus { number: l1_header.number, time: l1_header.timestamp, base_fee: l1_header.base_fee_per_gas.unwrap_or(0), @@ -107,10 +116,24 @@ impl L1BlockInfoTx { blob_base_fee: l1_header.blob_fee(BlobParams::cancun()).unwrap_or(1), blob_base_fee_scalar, base_fee_scalar, - empty_scalars: false, - l1_fee_overhead: U256::ZERO, - })) + operator_fee_scalar, + operator_fee_constant, + })); } + + Ok(Self::Ecotone(L1BlockInfoEcotone { + 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(BlobParams::cancun()).unwrap_or(1), + blob_base_fee_scalar, + base_fee_scalar, + empty_scalars: false, + l1_fee_overhead: U256::ZERO, + })) } /// Creates a new [L1BlockInfoTx] from the given information and returns a typed [TxDeposit] to @@ -171,6 +194,9 @@ impl L1BlockInfoTx { L1BlockInfoInterop::L1_INFO_TX_SELECTOR => L1BlockInfoInterop::decode_calldata(r) .map(Self::Interop) .map_err(|e| DecodeError::ParseError(format!("Interop 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), } } @@ -178,7 +204,7 @@ impl L1BlockInfoTx { /// Returns whether the scalars are empty. pub const fn empty_scalars(&self) -> bool { match self { - Self::Bedrock(_) | Self::Interop(_) => false, + Self::Bedrock(_) | Self::Interop(_) | Self::Isthmus(..) => false, Self::Ecotone(L1BlockInfoEcotone { empty_scalars, .. }) => *empty_scalars, } } @@ -189,6 +215,7 @@ impl L1BlockInfoTx { Self::Bedrock(ref tx) => tx.block_hash, Self::Ecotone(ref tx) => tx.block_hash, Self::Interop(ref tx) => tx.block_hash, + Self::Isthmus(ref tx) => tx.block_hash, } } @@ -198,6 +225,7 @@ impl L1BlockInfoTx { Self::Bedrock(bedrock_tx) => bedrock_tx.encode_calldata(), Self::Ecotone(ecotone_tx) => ecotone_tx.encode_calldata(), Self::Interop(interop_tx) => interop_tx.encode_calldata(), + Self::Isthmus(isthmus_tx) => isthmus_tx.encode_calldata(), } } @@ -206,6 +234,7 @@ impl L1BlockInfoTx { match self { Self::Ecotone(L1BlockInfoEcotone { number, block_hash, .. }) | Self::Bedrock(L1BlockInfoBedrock { number, block_hash, .. }) + | Self::Isthmus(L1BlockInfoIsthmus { number, block_hash, .. }) | Self::Interop(L1BlockInfoInterop { number, block_hash, .. }) => { BlockNumHash { number: *number, hash: *block_hash } } @@ -217,6 +246,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(L1BlockInfoBedrock { base_fee, .. }) | Self::Ecotone(L1BlockInfoEcotone { base_fee, .. }) + | Self::Isthmus(L1BlockInfoIsthmus { base_fee, .. }) | Self::Interop(L1BlockInfoInterop { base_fee, .. }) => U256::from(*base_fee), } } @@ -226,6 +256,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(L1BlockInfoBedrock { l1_fee_scalar, .. }) => *l1_fee_scalar, Self::Ecotone(L1BlockInfoEcotone { base_fee_scalar, .. }) + | Self::Isthmus(L1BlockInfoIsthmus { base_fee_scalar, .. }) | Self::Interop(L1BlockInfoInterop { base_fee_scalar, .. }) => { U256::from(*base_fee_scalar) } @@ -237,6 +268,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(_) => U256::ZERO, Self::Ecotone(L1BlockInfoEcotone { blob_base_fee, .. }) + | Self::Isthmus(L1BlockInfoIsthmus { blob_base_fee, .. }) | Self::Interop(L1BlockInfoInterop { blob_base_fee, .. }) => U256::from(*blob_base_fee), } } @@ -246,6 +278,7 @@ impl L1BlockInfoTx { match self { Self::Bedrock(_) => U256::ZERO, Self::Ecotone(L1BlockInfoEcotone { blob_base_fee_scalar, .. }) + | Self::Isthmus(L1BlockInfoIsthmus { blob_base_fee_scalar, .. }) | Self::Interop(L1BlockInfoInterop { blob_base_fee_scalar, .. }) => { U256::from(*blob_base_fee_scalar) } @@ -258,6 +291,7 @@ impl L1BlockInfoTx { Self::Bedrock(L1BlockInfoBedrock { l1_fee_overhead, .. }) => *l1_fee_overhead, Self::Ecotone(L1BlockInfoEcotone { l1_fee_overhead, .. }) => *l1_fee_overhead, Self::Interop(_) => U256::ZERO, + Self::Isthmus(_) => U256::ZERO, } } @@ -266,7 +300,8 @@ impl L1BlockInfoTx { match self { Self::Bedrock(L1BlockInfoBedrock { batcher_address, .. }) | Self::Ecotone(L1BlockInfoEcotone { batcher_address, .. }) - | Self::Interop(L1BlockInfoInterop { batcher_address, .. }) => *batcher_address, + | Self::Interop(L1BlockInfoInterop { batcher_address, .. }) + | Self::Isthmus(L1BlockInfoIsthmus { batcher_address, .. }) => *batcher_address, } } @@ -275,7 +310,8 @@ impl L1BlockInfoTx { match self { Self::Bedrock(L1BlockInfoBedrock { sequence_number, .. }) | Self::Ecotone(L1BlockInfoEcotone { sequence_number, .. }) - | Self::Interop(L1BlockInfoInterop { sequence_number, .. }) => *sequence_number, + | Self::Interop(L1BlockInfoInterop { sequence_number, .. }) + | Self::Isthmus(L1BlockInfoIsthmus { sequence_number, .. }) => *sequence_number, } } } @@ -289,6 +325,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_INTEROP_INFO_TX: [u8; L1BlockInfoInterop::L1_INFO_TX_LEN] = hex!("760ee04d00000558000c5fc50000000000000001000000006789ab380000000000000000000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000014f98b83baf52c498b49bfff33e59965b27da7febbea9a2fcc4719d06dc06932a000000000000000000000000c0658ee336b551ff83216fbdf85ec92613d23602"); + const RAW_ISTHMUS_INFO_TX: [u8; L1BlockInfoIsthmus::L1_INFO_TX_LEN] = hex!("098999be00000558000c5fc5000000000000000500000000661c277300000000012bec20000000000000000000000000000000000000000000000000000000026e9f109900000000000000000000000000000000000000000000000000000000000000011c4c84c50740386c7dc081efddd644405f04cde73e30a2e381737acce9f5add30000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f329850000abcd000000000000dcba"); #[test] fn bedrock_l1_block_info_invalid_len() { @@ -457,6 +494,31 @@ mod test { assert!(!ecotone.empty_scalars()); } + #[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 bedrock_l1_block_info_tx_roundtrip() { let expected = L1BlockInfoBedrock { diff --git a/crates/protocol/src/lib.rs b/crates/protocol/src/lib.rs index 1f2b420d..6dfe8396 100644 --- a/crates/protocol/src/lib.rs +++ b/crates/protocol/src/lib.rs @@ -66,7 +66,7 @@ pub use deposits::{ mod info; pub use info::{ closing_deposit_context_tx, BlockInfoError, DecodeError, L1BlockInfoBedrock, - L1BlockInfoEcotone, L1BlockInfoInterop, L1BlockInfoTx, + L1BlockInfoEcotone, L1BlockInfoInterop, L1BlockInfoIsthmus, L1BlockInfoTx, }; mod fee; diff --git a/crates/protocol/src/utils.rs b/crates/protocol/src/utils.rs index 0787bf18..589b816e 100644 --- a/crates/protocol/src/utils.rs +++ b/crates/protocol/src/utils.rs @@ -8,7 +8,7 @@ use maili_genesis::{RollupConfig, SystemConfig}; use op_alloy_consensus::OpBlock; use crate::{ - info::L1BlockInfoInterop, L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoTx, + L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoInterop, L1BlockInfoIsthmus, L1BlockInfoTx, OpBlockConversionError, SpanBatchError, SpanDecodingError, }; @@ -57,6 +57,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/etc/configs.json b/crates/registry/etc/configs.json index 69f55478..d293a7d9 100644 --- a/crates/registry/etc/configs.json +++ b/crates/registry/etc/configs.json @@ -62,7 +62,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -142,7 +144,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -222,7 +226,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -302,7 +308,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -382,7 +390,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -462,7 +472,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -542,7 +554,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -622,7 +636,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -702,7 +718,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -786,7 +804,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -866,7 +886,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -946,7 +968,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1026,7 +1050,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1106,7 +1132,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1186,7 +1214,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1266,7 +1296,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1346,7 +1378,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1430,7 +1464,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1510,7 +1546,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1590,7 +1628,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1670,7 +1710,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1754,7 +1796,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1834,7 +1878,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1914,7 +1960,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -1994,7 +2042,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2078,7 +2128,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2162,7 +2214,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2242,7 +2296,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2338,7 +2394,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2418,7 +2476,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2498,7 +2558,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2578,7 +2640,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2658,7 +2722,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2738,7 +2804,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2818,7 +2886,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2898,7 +2968,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -2978,7 +3050,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3058,7 +3132,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3138,7 +3214,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3218,7 +3296,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3298,7 +3378,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3378,7 +3460,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3458,7 +3542,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3542,7 +3628,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3622,7 +3710,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3702,7 +3792,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3782,7 +3874,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3878,7 +3972,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { @@ -3958,7 +4054,9 @@ "baseFeeScalar": null, "blobBaseFeeScalar": null, "eip1559Denominator": null, - "eip1559Elasticity": null + "eip1559Elasticity": null, + "operatorFeeScalar": null, + "operatorFeeConstant": null } }, "Addresses": { diff --git a/crates/registry/src/test_utils/base_mainnet.rs b/crates/registry/src/test_utils/base_mainnet.rs index 385aba56..49e2fe4a 100644 --- a/crates/registry/src/test_utils/base_mainnet.rs +++ b/crates/registry/src/test_utils/base_mainnet.rs @@ -28,6 +28,8 @@ pub const BASE_MAINNET_CONFIG: RollupConfig = RollupConfig { blob_base_fee_scalar: None, eip1559_denominator: None, eip1559_elasticity: None, + operator_fee_scalar: None, + operator_fee_constant: None, }), }, block_time: 2, diff --git a/crates/registry/src/test_utils/base_sepolia.rs b/crates/registry/src/test_utils/base_sepolia.rs index dc1e604e..ee70774e 100644 --- a/crates/registry/src/test_utils/base_sepolia.rs +++ b/crates/registry/src/test_utils/base_sepolia.rs @@ -28,6 +28,8 @@ pub const BASE_SEPOLIA_CONFIG: RollupConfig = RollupConfig { blob_base_fee_scalar: None, eip1559_denominator: None, eip1559_elasticity: None, + operator_fee_scalar: None, + operator_fee_constant: None, }), }, block_time: 2, diff --git a/crates/registry/src/test_utils/op_mainnet.rs b/crates/registry/src/test_utils/op_mainnet.rs index 413555ac..f6ee81b4 100644 --- a/crates/registry/src/test_utils/op_mainnet.rs +++ b/crates/registry/src/test_utils/op_mainnet.rs @@ -28,6 +28,8 @@ pub const OP_MAINNET_CONFIG: RollupConfig = RollupConfig { blob_base_fee_scalar: None, eip1559_denominator: None, eip1559_elasticity: None, + operator_fee_scalar: None, + operator_fee_constant: None, }), }, block_time: 2_u64, diff --git a/crates/registry/src/test_utils/op_sepolia.rs b/crates/registry/src/test_utils/op_sepolia.rs index 4d736bab..2eeaf79a 100644 --- a/crates/registry/src/test_utils/op_sepolia.rs +++ b/crates/registry/src/test_utils/op_sepolia.rs @@ -28,6 +28,8 @@ pub const OP_SEPOLIA_CONFIG: RollupConfig = RollupConfig { blob_base_fee_scalar: None, eip1559_denominator: None, eip1559_elasticity: None, + operator_fee_scalar: None, + operator_fee_constant: None, }), }, block_time: 2,