1use crate::Evm;
3use crate::EvmError;
4use ethers::providers::Middleware;
5use ethers::types::{Address, Bytes, H256};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::Arc;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ContractInfo {
13 pub address: Address,
14 pub bytecode: Bytes,
15 pub deployed_bytecode: Bytes,
16 pub is_contract: bool,
17 pub creation_block: Option<u64>,
18 pub creation_tx_hash: Option<H256>,
19 pub storage_slots: HashMap<H256, H256>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ContractABI {
25 pub raw_abi: Option<String>,
26 pub functions: Vec<FunctionInfo>,
27 pub events: Vec<EventInfo>,
28 pub errors: Vec<ErrorInfo>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct FunctionInfo {
34 pub name: String,
35 pub inputs: Vec<Param>,
36 pub outputs: Vec<Param>,
37 pub constant: bool,
38 pub payable: bool,
39 pub selector: Option<H256>,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct EventInfo {
45 pub name: String,
46 pub inputs: Vec<Param>,
47 pub anonymous: bool,
48 pub signature: Option<H256>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct ErrorInfo {
53 pub name: String,
54 pub inputs: Vec<Param>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct Param {
59 pub name: String,
60 pub type_: String,
61 pub indexed: bool,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct StorageLayout {
67 pub slots: Vec<StorageSlot>,
68 pub total_size: usize,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct StorageSlot {
74 pub slot: H256,
75 pub value: H256,
76 pub size: usize,
77}
78
79pub struct ContractAnalyzer {
81 evm: Arc<Evm>,
82}
83
84impl ContractAnalyzer {
85 pub fn new(evm: Arc<Evm>) -> Self {
86 Self { evm }
87 }
88
89 pub async fn get_contract_info(&self, address: Address) -> Result<ContractInfo, EvmError> {
102 let bytecode = self.get_contract_bytecode(address).await?;
103 let is_contract = !bytecode.is_empty();
104 let deployed_bytecode = self.get_deployed_bytecode(address).await?;
105 let (creation_block, creation_tx_hash) = self.find_creation_info(address).await?;
106 let storage_slots = self.sample_storage_slots(address, 100).await?;
107 Ok(ContractInfo {
108 address,
109 bytecode,
110 deployed_bytecode,
111 is_contract,
112 creation_block,
113 creation_tx_hash,
114 storage_slots,
115 })
116 }
117
118 pub async fn get_contract_bytecode(&self, address: Address) -> Result<Bytes, EvmError> {
126 self.evm
127 .client
128 .provider
129 .get_code(address, None)
130 .await
131 .map_err(|e| EvmError::RpcError(format!("Failed to get contract bytecode: {}", e)))
132 }
133
134 pub async fn get_deployed_bytecode(&self, address: Address) -> Result<Bytes, EvmError> {
136 self.get_contract_bytecode(address).await
137 }
138
139 async fn find_creation_info(
141 &self,
142 address: Address,
143 ) -> Result<(Option<u64>, Option<H256>), EvmError> {
144 let current_block = self.evm.get_block_number().await?;
145 let start_block = current_block.saturating_sub(1000);
146 for block_number in (start_block..=current_block).rev() {
147 if let Some(block) = self
148 .evm
149 .client
150 .provider
151 .get_block(block_number)
152 .await
153 .map_err(|e| {
154 EvmError::RpcError(format!("Failed to get block {}: {}", block_number, e))
155 })?
156 {
157 if let transactions = block.transactions {
158 for tx_hash in transactions {
159 if let Some(receipt) = self.evm.get_transaction_receipt(tx_hash).await? {
160 if let Some(contract_address) = receipt.contract_address {
161 if contract_address == address {
162 return Ok((Some(block_number), Some(tx_hash)));
163 }
164 }
165 }
166 }
167 }
168 }
169 }
170 Ok((None, None))
171 }
172
173 async fn sample_storage_slots(
175 &self,
176 address: Address,
177 sample_count: usize,
178 ) -> Result<HashMap<H256, H256>, EvmError> {
179 let mut slots = HashMap::new();
180 for i in 0..sample_count {
181 let slot = H256::from_low_u64_be(i as u64);
182 if let Some(value) = self.get_storage_at(address, slot).await? {
183 slots.insert(slot, value);
184 }
185 }
186 Ok(slots)
187 }
188
189 pub async fn get_storage_at(
200 &self,
201 address: Address,
202 slot: H256,
203 ) -> Result<Option<H256>, EvmError> {
204 self.evm
205 .client
206 .provider
207 .get_storage_at(address, slot, None)
208 .await
209 .map(Some)
210 .map_err(|e| {
211 EvmError::RpcError(format!("Failed to get storage at slot {:?}: {}", slot, e))
212 })
213 }
214
215 pub async fn analyze_storage_layout(
226 &self,
227 address: Address,
228 ) -> Result<StorageLayout, EvmError> {
229 let mut slots = Vec::new();
230 let mut total_size = 0;
231 for i in 0..50 {
232 let slot = H256::from_low_u64_be(i as u64);
233 if let Some(value) = self.get_storage_at(address, slot).await? {
234 let size = self.calculate_storage_size(value);
235 total_size += size;
236
237 slots.push(StorageSlot { slot, value, size });
238 }
239 }
240 Ok(StorageLayout { slots, total_size })
241 }
242
243 fn calculate_storage_size(&self, value: H256) -> usize {
245 value.as_bytes().iter().filter(|&&b| b != 0).count()
246 }
247
248 pub fn extract_function_selectors(&self, bytecode: &Bytes) -> Vec<H256> {
260 let mut selectors = Vec::new();
261 let code = bytecode.as_ref();
262 for i in 0..code.len().saturating_sub(4) {
263 if i > 0 && code[i - 1] == 0x63 {
264 let selector_bytes = [code[i], code[i + 1], code[i + 2], code[i + 3]];
265 let selector = H256::from_slice(&{
266 let mut full = [0u8; 32];
267 full[28..32].copy_from_slice(&selector_bytes);
268 full
269 });
270 selectors.push(selector);
271 }
272 }
273 selectors.dedup();
274 selectors
275 }
276
277 pub async fn analyze_bytecode_features(
287 &self,
288 address: Address,
289 ) -> Result<BytecodeFeatures, EvmError> {
290 let bytecode = self.get_contract_bytecode(address).await?;
291 let function_selectors = self.extract_function_selectors(&bytecode);
292 let is_proxy = self.detect_proxy_pattern(&bytecode).await;
293 let has_selfdestruct = bytecode.contains(&0xff); let has_delegatecall = bytecode.contains(&0xf4); Ok(BytecodeFeatures {
296 address,
297 bytecode_length: bytecode.len(),
298 function_selectors,
299 is_proxy,
300 has_selfdestruct,
301 has_delegatecall,
302 opcode_distribution: self.analyze_opcode_distribution(&bytecode),
303 })
304 }
305
306 async fn detect_proxy_pattern(&self, bytecode: &Bytes) -> bool {
308 let code = bytecode.as_ref();
309 let has_delegatecall = code.contains(&0xf4);
310 has_delegatecall
311 }
312
313 fn analyze_opcode_distribution(&self, bytecode: &Bytes) -> HashMap<u8, usize> {
315 let mut distribution = HashMap::new();
316 for &opcode in bytecode.as_ref() {
317 *distribution.entry(opcode).or_insert(0) += 1;
318 }
319 distribution
320 }
321
322 pub async fn compare_contracts(
334 &self,
335 address1: Address,
336 address2: Address,
337 ) -> Result<ContractSimilarity, EvmError> {
338 let bytecode1 = self.get_contract_bytecode(address1).await?;
339 let bytecode2 = self.get_contract_bytecode(address2).await?;
340 let similarity = self.calculate_bytecode_similarity(&bytecode1, &bytecode2);
341 let selectors1 = self.extract_function_selectors(&bytecode1);
342 let selectors2 = self.extract_function_selectors(&bytecode2);
343 let common_selectors: Vec<H256> = selectors1
344 .iter()
345 .filter(|s| selectors2.contains(s))
346 .cloned()
347 .collect();
348 Ok(ContractSimilarity {
349 address1,
350 address2,
351 bytecode_similarity: similarity,
352 common_function_selectors: common_selectors,
353 bytecode1_length: bytecode1.len(),
354 bytecode2_length: bytecode2.len(),
355 })
356 }
357
358 fn calculate_bytecode_similarity(&self, bytecode1: &Bytes, bytecode2: &Bytes) -> f64 {
360 if bytecode1.is_empty() && bytecode2.is_empty() {
361 return 1.0;
362 }
363 if bytecode1.is_empty() || bytecode2.is_empty() {
364 return 0.0;
365 }
366 let len1 = bytecode1.len();
367 let len2 = bytecode2.len();
368 let max_len = len1.max(len2) as f64;
369 if max_len == 0.0 {
370 return 1.0;
371 }
372 let common_prefix = bytecode1
373 .iter()
374 .zip(bytecode2.iter())
375 .take_while(|(a, b)| a == b)
376 .count();
377 common_prefix as f64 / max_len
378 }
379
380 pub async fn get_transaction_stats(
390 &self,
391 address: Address,
392 ) -> Result<TransactionStats, EvmError> {
393 let current_block = self.evm.get_block_number().await?;
394 let start_block = current_block.saturating_sub(10000);
395 let mut total_txs = 0;
396 let mut incoming_txs = 0;
397 let mut outgoing_txs = 0;
398 let filter = ethers::types::Filter::new()
399 .from_block(start_block)
400 .to_block(current_block)
401 .address(address);
402 let logs = self.evm.get_logs(filter).await?;
403 total_txs = logs.len();
404 Ok(TransactionStats {
405 address,
406 total_transactions: total_txs,
407 incoming_transactions: incoming_txs,
408 outgoing_transactions: outgoing_txs,
409 first_seen_block: start_block,
410 last_seen_block: current_block,
411 })
412 }
413}
414
415#[derive(Debug, Clone, Serialize, Deserialize)]
416pub struct BytecodeFeatures {
417 pub address: Address,
418 pub bytecode_length: usize,
419 pub function_selectors: Vec<H256>,
420 pub is_proxy: bool,
421 pub has_selfdestruct: bool,
422 pub has_delegatecall: bool,
423 pub opcode_distribution: HashMap<u8, usize>,
424}
425
426#[derive(Debug, Clone, Serialize, Deserialize)]
427pub struct ContractSimilarity {
428 pub address1: Address,
429 pub address2: Address,
430 pub bytecode_similarity: f64,
431 pub common_function_selectors: Vec<H256>,
432 pub bytecode1_length: usize,
433 pub bytecode2_length: usize,
434}
435
436#[derive(Debug, Clone, Serialize, Deserialize)]
437pub struct TransactionStats {
438 pub address: Address,
439 pub total_transactions: usize,
440 pub incoming_transactions: usize,
441 pub outgoing_transactions: usize,
442 pub first_seen_block: u64,
443 pub last_seen_block: u64,
444}
445
446impl From<ethers::providers::ProviderError> for EvmError {
447 fn from(error: ethers::providers::ProviderError) -> Self {
448 EvmError::RpcError(format!("Provider error: {}", error))
449 }
450}