1use std::collections::HashMap;
2
3#[derive(Debug, Clone, Default)]
5pub struct StateOverride {
6 pub storages: HashMap<Address, Vec<(U256, U256)>>, pub balances: HashMap<Address, U256>, }
9
10pub type StorageDiff = HashMap<Address, Vec<SlotAccess>>;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum SlotAccessType {
15 Read,
16 Write,
17 All,
18}
19
20impl CallTrace {
21 fn collect_slot_accesses<'a>(&'a self, filter: SlotAccessType, out: &mut Vec<&'a SlotAccess>) {
23 for access in &self.slot_accesses {
24 match filter {
25 SlotAccessType::All => out.push(access),
26 SlotAccessType::Read if !access.is_write => out.push(access),
27 SlotAccessType::Write if access.is_write => out.push(access),
28 _ => {}
29 }
30 }
31 for sub in &self.subtraces {
32 sub.collect_slot_accesses(filter, out);
33 }
34 }
35
36 pub fn all_slot_accesses(&self, filter: SlotAccessType) -> Vec<&SlotAccess> {
38 let mut result = Vec::new();
39 self.collect_slot_accesses(filter, &mut result);
40 result
41 }
42}
43
44use crate::MyWrapDatabaseAsync;
45use alloy::{
46 network::AnyNetwork,
47 primitives::{fixed_bytes, Address, Bytes, FixedBytes, Log, TxKind, U256},
48 providers::{
49 fillers::{BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller},
50 Identity, RootProvider,
51 },
52};
53pub use revm::{
54 context::BlockEnv,
55 database::AlloyDB,
56 interpreter::{CallScheme, CreateScheme},
57};
58use serde::{Deserialize, Serialize};
59
60pub const ERC20_TRANSFER_EVENT_SIGNATURE: FixedBytes<32> =
61 fixed_bytes!("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");
62pub const ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE: FixedBytes<32> =
63 fixed_bytes!("0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb");
64pub const ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE: FixedBytes<32> =
65 fixed_bytes!("0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62");
66
67type BaseFiller = JoinFill<NonceFiller, ChainIdFiller>;
78
79type BlobFiller = JoinFill<BlobGasFiller, BaseFiller>;
84
85type GasFillers = JoinFill<GasFiller, BlobFiller>;
90
91type AllFillers = JoinFill<Identity, GasFillers>;
97
98pub type AnyNetworkProvider = FillProvider<AllFillers, RootProvider<AnyNetwork>, AnyNetwork>;
107
108pub type ArcAnyNetworkProvider = std::sync::Arc<AnyNetworkProvider>;
109
110pub const NATIVE_TOKEN_ADDRESS: Address = Address::ZERO;
111
112pub type AllDBType = MyWrapDatabaseAsync<AlloyDB<AnyNetwork, AnyNetworkProvider>>;
113
114#[derive(Debug, Clone, Serialize)]
115pub struct TokenInfo {
116 pub name: String,
117 pub symbol: String,
119 pub decimals: u8,
121 pub total_supply: U256,
123}
124
125#[derive(Debug, Clone)]
126pub struct SimulationTx {
127 pub caller: Address,
129 pub value: U256,
131 pub data: Bytes,
133 pub transact_to: TxKind,
135}
136
137#[derive(Debug, Clone)]
142pub struct SimulationBatch {
143 pub transactions: Vec<SimulationTx>,
145 pub is_stateful: bool,
156 pub overrides: Option<StateOverride>,
158}
159
160#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
162#[non_exhaustive]
163pub enum TokenType {
164 Native,
165 ERC20,
166 ERC721,
167 ERC1155,
168 }
170
171#[derive(Debug, Clone, Serialize)]
180pub struct TokenTransfer {
181 pub token: Address,
183 pub from: Address,
185 pub to: Option<Address>,
187 pub value: U256,
189 pub token_type: TokenType,
191 pub id: Option<U256>,
193}
194
195impl TokenTransfer {
196 pub fn is_native_token(&self) -> bool {
198 self.token == NATIVE_TOKEN_ADDRESS
199 }
200}
201
202#[derive(Debug, Clone)]
204pub enum CallType {
205 Call,
207 Create,
209}
210
211#[derive(Debug, Clone, Serialize, Default)]
213pub enum CallStatus {
214 #[default]
216 Success,
217 Revert(String),
219 Halt(String),
221 FatalError,
223 InProgress,
225}
226
227impl CallStatus {
228 pub fn is_success(&self) -> bool {
230 matches!(self, CallStatus::Success)
231 }
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize, Default)]
236pub struct SlotAccess {
237 pub address: Address,
238 pub slot: U256,
239 pub old_value: U256,
240 pub new_value: U256,
241 pub is_write: bool, }
243
244#[derive(Debug, Clone, Serialize, Default)]
246pub struct CallTrace {
247 pub from: Address,
249 pub to: Address,
251 pub value: U256,
253 pub input: Bytes,
255 pub call_scheme: Option<CallScheme>,
257 pub create_scheme: Option<CreateScheme>,
259 pub gas_used: U256,
261 pub output: Bytes,
263 pub status: CallStatus,
265 pub error_origin: bool,
267 pub subtraces: Vec<CallTrace>,
269 pub trace_address: Vec<usize>,
271 pub slot_accesses: Vec<SlotAccess>,
273}
274
275impl TokenTransfer {
276 pub fn get_token_transfers(log: &Log) -> Vec<TokenTransfer> {
278 let mut results = vec![];
279 if log.topics()[0] == ERC20_TRANSFER_EVENT_SIGNATURE {
281 if log.topics().len() == 3 {
282 let from = Address::from_slice(&log.topics()[1].as_slice()[12..]);
283 let to = Address::from_slice(&log.topics()[2].as_slice()[12..]);
284 let data = &log.data.data;
285 let amount = U256::from_be_slice(data);
286 if !amount.is_zero() {
287 results.push(TokenTransfer {
288 token: log.address,
289 from,
290 to: Some(to),
291 value: amount,
292 token_type: TokenType::ERC20,
293 id: None,
294 });
295 }
296 } else if log.topics().len() == 4 {
297 let from = Address::from_slice(&log.topics()[1].as_slice()[12..]);
298 let to = Address::from_slice(&log.topics()[2].as_slice()[12..]);
299 let id = U256::from_be_slice(log.topics()[3].as_slice());
300 let amount = U256::from(1);
301 results.push(TokenTransfer {
302 token: log.address,
303 from,
304 to: Some(to),
305 value: amount,
306 token_type: TokenType::ERC721,
307 id: Some(id),
308 });
309 }
310 } else if log.topics()[0] == ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE
311 && log.topics().len() == 4
312 {
313 let data = &log.data.data;
314 if data.len() >= 96 {
315 let from = Address::from_slice(&log.topics()[2].as_slice()[12..]);
316 let to = Address::from_slice(&log.topics()[3].as_slice()[12..]);
317 let ids_len = U256::from_be_slice(&data[64..96]).to::<usize>();
318 let mut ids = Vec::with_capacity(ids_len);
319 let mut offset = 96;
320 for _ in 0..ids_len {
321 ids.push(U256::from_be_slice(&data[offset..offset + 32]));
322 offset += 32;
323 }
324 let values_len = U256::from_be_slice(&data[offset..offset + 32]).to::<usize>();
326 offset += 32;
327 let mut values = Vec::with_capacity(values_len);
328 for _ in 0..values_len {
329 values.push(U256::from_be_slice(&data[offset..offset + 32]));
330 offset += 32;
331 }
332 for (id, value) in ids.into_iter().zip(values.into_iter()) {
334 results.push(TokenTransfer {
335 token: log.address,
336 from,
337 to: Some(to),
338 value,
339 token_type: TokenType::ERC1155,
340 id: Some(id),
341 });
342 }
343 }
344 } else if log.topics()[0] == ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE
345 && log.topics().len() == 4
346 {
347 let data = &log.data.data;
348 if data.len() >= 64 {
349 let from = Address::from_slice(&log.topics()[2].as_slice()[12..]);
350 let to = Address::from_slice(&log.topics()[3].as_slice()[12..]);
351 let id = U256::from_be_slice(&data[..32]);
352 let value = U256::from_be_slice(&data[32..64]);
353 results.push(TokenTransfer {
354 token: log.address,
355 from,
356 to: Some(to),
357 value,
358 token_type: TokenType::ERC1155,
359 id: Some(id),
360 });
361 }
362 }
363 results
364 }
365}