1use crate::{Log, TransactionReceipt};
2use alloc::vec::Vec;
3use alloy_consensus::conditional::BlockConditionalAttributes;
4use alloy_primitives::{
5 map::{AddressHashMap, HashMap},
6 Address, BlockNumber, Bytes, B256, U256,
7};
8
9#[deprecated(since = "0.8.4", note = "use `TransactionConditional` instead")]
11pub type ConditionalOptions = TransactionConditional;
12
13#[derive(Debug, Clone, Default, Eq, PartialEq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
22pub struct TransactionConditional {
23 #[cfg_attr(feature = "serde", serde(default))]
26 pub known_accounts: AddressHashMap<AccountStorage>,
27 #[cfg_attr(
30 feature = "serde",
31 serde(
32 default,
33 with = "alloy_serde::quantity::opt",
34 skip_serializing_if = "Option::is_none"
35 )
36 )]
37 pub block_number_min: Option<BlockNumber>,
38 #[cfg_attr(
41 feature = "serde",
42 serde(
43 default,
44 with = "alloy_serde::quantity::opt",
45 skip_serializing_if = "Option::is_none"
46 )
47 )]
48 pub block_number_max: Option<BlockNumber>,
49 #[cfg_attr(
52 feature = "serde",
53 serde(
54 default,
55 with = "alloy_serde::quantity::opt",
56 skip_serializing_if = "Option::is_none"
57 )
58 )]
59 pub timestamp_min: Option<u64>,
60 #[cfg_attr(
63 feature = "serde",
64 serde(
65 default,
66 with = "alloy_serde::quantity::opt",
67 skip_serializing_if = "Option::is_none"
68 )
69 )]
70 pub timestamp_max: Option<u64>,
71}
72
73impl TransactionConditional {
74 pub const fn has_exceeded_block_attributes(&self, block: &BlockConditionalAttributes) -> bool {
79 self.has_exceeded_block_number(block.number) || self.has_exceeded_timestamp(block.timestamp)
80 }
81
82 pub const fn has_exceeded_block_number(&self, block_number: BlockNumber) -> bool {
85 let Some(max_num) = self.block_number_max else { return false };
86 block_number >= max_num
87 }
88
89 pub const fn has_exceeded_timestamp(&self, timestamp: u64) -> bool {
91 let Some(max_timestamp) = self.timestamp_max else { return false };
92 timestamp >= max_timestamp
93 }
94
95 pub const fn matches_block_attributes(&self, block: &BlockConditionalAttributes) -> bool {
97 self.matches_block_number(block.number) && self.matches_timestamp(block.timestamp)
98 }
99
100 pub const fn matches_block_number(&self, block_number: BlockNumber) -> bool {
102 if let Some(min) = self.block_number_min {
103 if block_number < min {
104 return false;
105 }
106 }
107 if let Some(max) = self.block_number_max {
108 if block_number > max {
109 return false;
110 }
111 }
112 true
113 }
114
115 pub const fn matches_timestamp(&self, timestamp: u64) -> bool {
117 if let Some(min) = self.timestamp_min {
118 if timestamp < min {
119 return false;
120 }
121 }
122 if let Some(max) = self.timestamp_max {
123 if timestamp > max {
124 return false;
125 }
126 }
127 true
128 }
129
130 pub fn cost(&self) -> u64 {
132 let mut cost = 0;
133 for account in self.known_accounts.values() {
134 cost += 1;
136 match account {
137 AccountStorage::RootHash(_) => {
138 cost += 1;
139 }
140 AccountStorage::Slots(slots) => {
141 cost += slots.len() as u64;
142 }
143 }
144 }
145
146 if self.block_number_min.is_some() || self.block_number_max.is_some() {
147 cost += 1;
148 }
149 if self.timestamp_min.is_some() || self.timestamp_max.is_some() {
150 cost += 1;
151 }
152
153 cost
154 }
155}
156
157#[derive(Debug, Clone, Eq, PartialEq)]
165#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
166#[cfg_attr(feature = "serde", serde(untagged))]
167pub enum AccountStorage {
168 RootHash(B256),
170 Slots(HashMap<U256, B256>),
172}
173
174impl AccountStorage {
175 pub const fn is_root(&self) -> bool {
177 matches!(self, Self::RootHash(_))
178 }
179
180 pub const fn as_slots(&self) -> Option<&HashMap<U256, B256>> {
182 match self {
183 Self::Slots(slots) => Some(slots),
184 _ => None,
185 }
186 }
187}
188
189#[derive(Debug, Clone, PartialEq, Eq)]
191#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
192#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
193pub struct UserOperation {
194 pub sender: Address,
196 pub nonce: U256,
198 pub init_code: Bytes,
200 pub call_data: Bytes,
202 pub call_gas_limit: U256,
204 pub verification_gas_limit: U256,
206 pub pre_verification_gas: U256,
208 pub max_fee_per_gas: U256,
210 pub max_priority_fee_per_gas: U256,
212 pub paymaster_and_data: Bytes,
215 pub signature: Bytes,
217}
218
219#[derive(Debug, Clone, PartialEq, Eq)]
221#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
222#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
223pub struct PackedUserOperation {
224 pub sender: Address,
226 pub nonce: U256,
229 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
232 pub factory: Option<Address>,
233 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
236 pub factory_data: Option<Bytes>,
237 pub call_data: Bytes,
239 pub call_gas_limit: U256,
241 pub verification_gas_limit: U256,
243 pub pre_verification_gas: U256,
246 pub max_fee_per_gas: U256,
248 pub max_priority_fee_per_gas: U256,
250 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
253 pub paymaster: Option<Address>,
254 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
256 pub paymaster_verification_gas_limit: Option<U256>,
257 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
259 pub paymaster_post_op_gas_limit: Option<U256>,
260 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
262 pub paymaster_data: Option<Bytes>,
263 pub signature: Bytes,
265}
266
267#[derive(Debug, Clone, PartialEq, Eq)]
269#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
270pub enum SendUserOperation {
271 EntryPointV06(UserOperation),
273 EntryPointV07(PackedUserOperation),
275}
276
277#[derive(Debug, Clone, PartialEq, Eq)]
279#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
280#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
281pub struct SendUserOperationResponse {
282 pub user_op_hash: Bytes,
284}
285
286#[derive(Debug, Clone, PartialEq, Eq)]
288#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
289#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
290pub struct UserOperationReceipt {
291 pub user_op_hash: Bytes,
293 pub entry_point: Address,
295 pub sender: Address,
297 pub nonce: U256,
299 pub paymaster: Address,
301 pub actual_gas_cost: U256,
303 pub actual_gas_used: U256,
305 pub success: bool,
307 pub reason: Bytes,
309 pub logs: Vec<Log>,
311 pub receipt: TransactionReceipt,
313}
314
315#[derive(Debug, Clone, PartialEq, Eq)]
317#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
318#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
319pub struct UserOperationGasEstimation {
320 pub pre_verification_gas: U256,
322 pub verification_gas: U256,
324 pub paymaster_verification_gas: U256,
326 pub call_gas_limit: U256,
328}