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#[derive(Debug, Clone, Default, Eq, PartialEq)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
18pub struct TransactionConditional {
19 #[cfg_attr(feature = "serde", serde(default))]
22 pub known_accounts: AddressHashMap<AccountStorage>,
23 #[cfg_attr(
26 feature = "serde",
27 serde(
28 default,
29 with = "alloy_serde::quantity::opt",
30 skip_serializing_if = "Option::is_none"
31 )
32 )]
33 pub block_number_min: Option<BlockNumber>,
34 #[cfg_attr(
37 feature = "serde",
38 serde(
39 default,
40 with = "alloy_serde::quantity::opt",
41 skip_serializing_if = "Option::is_none"
42 )
43 )]
44 pub block_number_max: Option<BlockNumber>,
45 #[cfg_attr(
48 feature = "serde",
49 serde(
50 default,
51 with = "alloy_serde::quantity::opt",
52 skip_serializing_if = "Option::is_none"
53 )
54 )]
55 pub timestamp_min: Option<u64>,
56 #[cfg_attr(
59 feature = "serde",
60 serde(
61 default,
62 with = "alloy_serde::quantity::opt",
63 skip_serializing_if = "Option::is_none"
64 )
65 )]
66 pub timestamp_max: Option<u64>,
67}
68
69impl TransactionConditional {
70 pub const fn has_exceeded_block_attributes(&self, block: &BlockConditionalAttributes) -> bool {
75 self.has_exceeded_block_number(block.number) || self.has_exceeded_timestamp(block.timestamp)
76 }
77
78 pub const fn has_exceeded_block_number(&self, block_number: BlockNumber) -> bool {
81 let Some(max_num) = self.block_number_max else { return false };
82 block_number > max_num
83 }
84
85 pub const fn has_exceeded_timestamp(&self, timestamp: u64) -> bool {
87 let Some(max_timestamp) = self.timestamp_max else { return false };
88 timestamp > max_timestamp
89 }
90
91 pub const fn matches_block_attributes(&self, block: &BlockConditionalAttributes) -> bool {
93 self.matches_block_number(block.number) && self.matches_timestamp(block.timestamp)
94 }
95
96 pub const fn matches_block_number(&self, block_number: BlockNumber) -> bool {
98 if let Some(min) = self.block_number_min {
99 if block_number < min {
100 return false;
101 }
102 }
103 if let Some(max) = self.block_number_max {
104 if block_number > max {
105 return false;
106 }
107 }
108 true
109 }
110
111 pub const fn matches_timestamp(&self, timestamp: u64) -> bool {
113 if let Some(min) = self.timestamp_min {
114 if timestamp < min {
115 return false;
116 }
117 }
118 if let Some(max) = self.timestamp_max {
119 if timestamp > max {
120 return false;
121 }
122 }
123 true
124 }
125
126 pub fn cost(&self) -> u64 {
128 let mut cost = 0;
129 for account in self.known_accounts.values() {
130 cost += 1;
132 match account {
133 AccountStorage::RootHash(_) => {
134 cost += 1;
135 }
136 AccountStorage::Slots(slots) => {
137 cost += slots.len() as u64;
138 }
139 }
140 }
141
142 if self.block_number_min.is_some() || self.block_number_max.is_some() {
143 cost += 1;
144 }
145 if self.timestamp_min.is_some() || self.timestamp_max.is_some() {
146 cost += 1;
147 }
148
149 cost
150 }
151}
152
153#[derive(Debug, Clone, Eq, PartialEq)]
161#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
162#[cfg_attr(feature = "serde", serde(untagged))]
163pub enum AccountStorage {
164 RootHash(B256),
166 Slots(HashMap<U256, B256>),
168}
169
170impl AccountStorage {
171 pub const fn is_root(&self) -> bool {
173 matches!(self, Self::RootHash(_))
174 }
175
176 pub const fn as_slots(&self) -> Option<&HashMap<U256, B256>> {
178 match self {
179 Self::Slots(slots) => Some(slots),
180 _ => None,
181 }
182 }
183}
184
185#[derive(Debug, Clone, PartialEq, Eq)]
187#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
188#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
189pub struct UserOperation {
190 pub sender: Address,
192 pub nonce: U256,
194 pub init_code: Bytes,
196 pub call_data: Bytes,
198 pub call_gas_limit: U256,
200 pub verification_gas_limit: U256,
202 pub pre_verification_gas: U256,
204 pub max_fee_per_gas: U256,
206 pub max_priority_fee_per_gas: U256,
208 pub paymaster_and_data: Bytes,
211 pub signature: Bytes,
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
217#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
218#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
219pub struct PackedUserOperation {
220 pub sender: Address,
222 pub nonce: U256,
225 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
228 pub factory: Option<Address>,
229 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
232 pub factory_data: Option<Bytes>,
233 pub call_data: Bytes,
235 pub call_gas_limit: U256,
237 pub verification_gas_limit: U256,
239 pub pre_verification_gas: U256,
242 pub max_fee_per_gas: U256,
244 pub max_priority_fee_per_gas: U256,
246 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
249 pub paymaster: Option<Address>,
250 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
252 pub paymaster_verification_gas_limit: Option<U256>,
253 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
255 pub paymaster_post_op_gas_limit: Option<U256>,
256 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
258 pub paymaster_data: Option<Bytes>,
259 pub signature: Bytes,
261}
262
263#[derive(Debug, Clone, PartialEq, Eq)]
265#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
266pub enum SendUserOperation {
267 EntryPointV06(UserOperation),
269 EntryPointV07(PackedUserOperation),
271}
272
273#[derive(Debug, Clone, PartialEq, Eq)]
275#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
276#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
277pub struct SendUserOperationResponse {
278 pub user_op_hash: Bytes,
280}
281
282#[derive(Debug, Clone, PartialEq, Eq)]
284#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
285#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
286pub struct UserOperationReceipt {
287 pub user_op_hash: Bytes,
289 pub entry_point: Address,
291 pub sender: Address,
293 pub nonce: U256,
295 pub paymaster: Address,
297 pub actual_gas_cost: U256,
299 pub actual_gas_used: U256,
301 pub success: bool,
303 pub reason: Bytes,
305 pub logs: Vec<Log>,
307 pub receipt: TransactionReceipt,
309}
310
311#[derive(Debug, Clone, PartialEq, Eq)]
313#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
314#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
315pub struct UserOperationGasEstimation {
316 pub pre_verification_gas: U256,
318 pub verification_gas: U256,
320 pub paymaster_verification_gas: U256,
322 pub call_gas_limit: U256,
324}