Skip to content

Commit

Permalink
feat(protocol): isthmus operator fee
Browse files Browse the repository at this point in the history
  • Loading branch information
refcell committed Feb 4, 2025
1 parent 598f5e9 commit d9bb360
Show file tree
Hide file tree
Showing 15 changed files with 464 additions and 66 deletions.
2 changes: 2 additions & 0 deletions crates/genesis/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}),
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/genesis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions crates/genesis/src/rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}
);
Expand Down
75 changes: 75 additions & 0 deletions crates/genesis/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ pub struct SystemConfig {
pub eip1559_denominator: Option<u32>,
/// EIP-1559 elasticity
pub eip1559_elasticity: Option<u32>,
/// The operator fee scalar (isthmus hardfork)
pub operator_fee_scalar: Option<u32>,
/// The operator fee constant (isthmus hardfork)
pub operator_fee_constant: Option<u64>,
}

/// Represents type of update to the system config.
Expand All @@ -52,6 +56,8 @@ pub enum SystemConfigUpdateType {
UnsafeBlockSigner = 3,
/// EIP-1559 parameters update type
Eip1559 = 4,
/// Operator fee parameter update
OperatorFee = 5,
}

impl TryFrom<u64> for SystemConfigUpdateType {
Expand All @@ -64,6 +70,7 @@ impl TryFrom<u64> for SystemConfigUpdateType {
2 => Ok(Self::GasLimit),
3 => Ok(Self::UnsafeBlockSigner),
4 => Ok(Self::Eip1559),
5 => Ok(Self::OperatorFee),
_ => Err(SystemConfigUpdateError::LogProcessing(
LogProcessingError::InvalidSystemConfigUpdateType(value),
)),
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<SystemConfigUpdateType, OperatorFeeUpdateError> {
if log_data.len() != 128 {
return Err(OperatorFeeUpdateError::InvalidDataLen(log_data.len()));
}

let Ok(pointer) = <sol!(uint64)>::abi_decode(&log_data[0..32], true) else {
return Err(OperatorFeeUpdateError::PointerDecodingError);
};
if pointer != 32 {
return Err(OperatorFeeUpdateError::InvalidDataPointer(pointer));
}
let Ok(length) = <sol!(uint64)>::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) = <sol!(uint32)>::abi_decode(&log_data[64..80], true) else {
return Err(OperatorFeeUpdateError::ScalarDecodingError);
};
let Ok(operator_fee_constant) = <sol!(uint64)>::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.
Expand All @@ -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.
Expand Down Expand Up @@ -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))]
Expand Down
6 changes: 6 additions & 0 deletions crates/protocol/src/info/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
136 changes: 136 additions & 0 deletions crates/protocol/src/info/isthmus.rs
Original file line number Diff line number Diff line change
@@ -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<Self, DecodeError> {
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,
})
}
}
3 changes: 3 additions & 0 deletions crates/protocol/src/info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
mod variant;
pub use variant::L1BlockInfoTx;

mod isthmus;
pub use isthmus::L1BlockInfoIsthmus;

mod bedrock;
pub use bedrock::L1BlockInfoBedrock;

Expand Down
Loading

0 comments on commit d9bb360

Please sign in to comment.