use std::collections::HashMap;
#[derive(Debug, Clone, Default)]
pub struct StateOverride {
pub storages: HashMap<Address, Vec<(U256, U256)>>, pub balances: HashMap<Address, U256>, }
pub type StorageDiff = HashMap<Address, Vec<SlotAccess>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SlotAccessType {
Read,
Write,
All,
}
impl CallTrace {
fn collect_slot_accesses<'a>(&'a self, filter: SlotAccessType, out: &mut Vec<&'a SlotAccess>) {
for access in &self.slot_accesses {
match filter {
SlotAccessType::All => out.push(access),
SlotAccessType::Read if !access.is_write => out.push(access),
SlotAccessType::Write if access.is_write => out.push(access),
_ => {}
}
}
for sub in &self.subtraces {
sub.collect_slot_accesses(filter, out);
}
}
pub fn all_slot_accesses(&self, filter: SlotAccessType) -> Vec<&SlotAccess> {
let mut result = Vec::new();
self.collect_slot_accesses(filter, &mut result);
result
}
}
use crate::MyWrapDatabaseAsync;
use alloy::{
network::AnyNetwork,
primitives::{fixed_bytes, Address, Bytes, FixedBytes, Log, TxKind, U256},
providers::{
fillers::{BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller},
Identity, RootProvider,
},
};
pub use revm::{
context::BlockEnv,
database::AlloyDB,
interpreter::{CallScheme, CreateScheme},
};
use serde::{Deserialize, Serialize};
pub const ERC20_TRANSFER_EVENT_SIGNATURE: FixedBytes<32> =
fixed_bytes!("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");
pub const ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE: FixedBytes<32> =
fixed_bytes!("0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb");
pub const ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE: FixedBytes<32> =
fixed_bytes!("0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62");
type BaseFiller = JoinFill<NonceFiller, ChainIdFiller>;
type BlobFiller = JoinFill<BlobGasFiller, BaseFiller>;
type GasFillers = JoinFill<GasFiller, BlobFiller>;
type AllFillers = JoinFill<Identity, GasFillers>;
pub type AnyNetworkProvider = FillProvider<AllFillers, RootProvider<AnyNetwork>, AnyNetwork>;
pub type ArcAnyNetworkProvider = std::sync::Arc<AnyNetworkProvider>;
pub const NATIVE_TOKEN_ADDRESS: Address = Address::ZERO;
pub type AllDBType = MyWrapDatabaseAsync<AlloyDB<AnyNetwork, AnyNetworkProvider>>;
#[derive(Debug, Clone, Serialize)]
pub struct TokenInfo {
pub name: String,
pub symbol: String,
pub decimals: u8,
pub total_supply: U256,
}
#[derive(Debug, Clone)]
pub struct SimulationTx {
pub caller: Address,
pub value: U256,
pub data: Bytes,
pub transact_to: TxKind,
}
#[derive(Debug, Clone)]
pub struct SimulationBatch {
pub transactions: Vec<SimulationTx>,
pub is_stateful: bool,
pub overrides: Option<StateOverride>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub enum TokenType {
Native,
ERC20,
ERC721,
ERC1155,
}
#[derive(Debug, Clone, Serialize)]
pub struct TokenTransfer {
pub token: Address,
pub from: Address,
pub to: Option<Address>,
pub value: U256,
pub token_type: TokenType,
pub id: Option<U256>,
}
impl TokenTransfer {
pub fn is_native_token(&self) -> bool {
self.token == NATIVE_TOKEN_ADDRESS
}
}
#[derive(Debug, Clone)]
pub enum CallType {
Call,
Create,
}
#[derive(Debug, Clone, Serialize, Default)]
pub enum CallStatus {
#[default]
Success,
Revert(String),
Halt(String),
FatalError,
InProgress,
}
impl CallStatus {
pub fn is_success(&self) -> bool {
matches!(self, CallStatus::Success)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SlotAccess {
pub address: Address,
pub slot: U256,
pub old_value: U256,
pub new_value: U256,
pub is_write: bool, }
#[derive(Debug, Clone, Serialize, Default)]
pub struct CallTrace {
pub from: Address,
pub to: Address,
pub value: U256,
pub input: Bytes,
pub call_scheme: Option<CallScheme>,
pub create_scheme: Option<CreateScheme>,
pub gas_used: U256,
pub output: Bytes,
pub status: CallStatus,
pub error_origin: bool,
pub subtraces: Vec<CallTrace>,
pub trace_address: Vec<usize>,
pub slot_accesses: Vec<SlotAccess>,
}
impl TokenTransfer {
pub fn get_token_transfers(log: &Log) -> Vec<TokenTransfer> {
let mut results = vec![];
if log.topics()[0] == ERC20_TRANSFER_EVENT_SIGNATURE {
if log.topics().len() == 3 {
let from = Address::from_slice(&log.topics()[1].as_slice()[12..]);
let to = Address::from_slice(&log.topics()[2].as_slice()[12..]);
let data = &log.data.data;
let amount = U256::from_be_slice(data);
if !amount.is_zero() {
results.push(TokenTransfer {
token: log.address,
from,
to: Some(to),
value: amount,
token_type: TokenType::ERC20,
id: None,
});
}
} else if log.topics().len() == 4 {
let from = Address::from_slice(&log.topics()[1].as_slice()[12..]);
let to = Address::from_slice(&log.topics()[2].as_slice()[12..]);
let id = U256::from_be_slice(log.topics()[3].as_slice());
let amount = U256::from(1);
results.push(TokenTransfer {
token: log.address,
from,
to: Some(to),
value: amount,
token_type: TokenType::ERC721,
id: Some(id),
});
}
} else if log.topics()[0] == ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE
&& log.topics().len() == 4
{
let data = &log.data.data;
if data.len() >= 96 {
let from = Address::from_slice(&log.topics()[2].as_slice()[12..]);
let to = Address::from_slice(&log.topics()[3].as_slice()[12..]);
let ids_len = U256::from_be_slice(&data[64..96]).to::<usize>();
let mut ids = Vec::with_capacity(ids_len);
let mut offset = 96;
for _ in 0..ids_len {
ids.push(U256::from_be_slice(&data[offset..offset + 32]));
offset += 32;
}
let values_len = U256::from_be_slice(&data[offset..offset + 32]).to::<usize>();
offset += 32;
let mut values = Vec::with_capacity(values_len);
for _ in 0..values_len {
values.push(U256::from_be_slice(&data[offset..offset + 32]));
offset += 32;
}
for (id, value) in ids.into_iter().zip(values.into_iter()) {
results.push(TokenTransfer {
token: log.address,
from,
to: Some(to),
value,
token_type: TokenType::ERC1155,
id: Some(id),
});
}
}
} else if log.topics()[0] == ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE
&& log.topics().len() == 4
{
let data = &log.data.data;
if data.len() >= 64 {
let from = Address::from_slice(&log.topics()[2].as_slice()[12..]);
let to = Address::from_slice(&log.topics()[3].as_slice()[12..]);
let id = U256::from_be_slice(&data[..32]);
let value = U256::from_be_slice(&data[32..64]);
results.push(TokenTransfer {
token: log.address,
from,
to: Some(to),
value,
token_type: TokenType::ERC1155,
id: Some(id),
});
}
}
results
}
}