diff --git a/crates/rpc-types-eth/src/erc4337.rs b/crates/rpc-types-eth/src/erc4337.rs index 728bf56c9e0..5921c943962 100644 --- a/crates/rpc-types-eth/src/erc4337.rs +++ b/crates/rpc-types-eth/src/erc4337.rs @@ -34,6 +34,34 @@ pub struct ConditionalOptions { pub timestamp_max: Option, } +impl ConditionalOptions { + /// Computes the aggregate cost of the preconditions; total number of storage lookups required + pub fn cost(&self) -> u64 { + let mut cost = 0; + for account in self.known_accounts.values() { + // default cost to handle empty accounts + cost += 1; + match account { + AccountStorage::RootHash(_) => { + cost += 1; + } + AccountStorage::Slots(slots) => { + cost += slots.len() as u64; + } + } + } + + if self.block_number_min.is_some() || self.block_number_max.is_some() { + cost += 1; + } + if self.timestamp_min.is_some() || self.timestamp_max.is_some() { + cost += 1; + } + + cost + } +} + /// Represents the expected state of an account for a transaction to be conditionally accepted. #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -45,6 +73,21 @@ pub enum AccountStorage { Slots(HashMap), } +impl AccountStorage { + /// Returns `true` if the account storage is a root hash. + pub const fn is_root(&self) -> bool { + matches!(self, Self::RootHash(_)) + } + + /// Returns the slot values if the account storage is a slot map. + pub const fn as_slots(&self) -> Option<&HashMap> { + match self { + Self::Slots(slots) => Some(slots), + _ => None, + } + } +} + /// [`UserOperation`] in the spec: Entry Point V0.6 #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]