Coverage for src/alprina_cli/agents/web3_auditor/web3_auditor.py: 17%

293 statements  

« prev     ^ index     » next       coverage.py v7.11.3, created at 2025-11-14 11:27 +0100

1""" 

2Web3/DeFi Security Auditor Agent 

3 

4Enterprise-grade smart contract security analysis combining: 

51. Static vulnerability detection (OWASP Smart Contract Top 10) 

62. Economic risk assessment (AI-enhanced) 

73. Multi-chain support (Ethereum, Solana, Polygon, BSC) 

84. Flash loan attack vector analysis 

95. Real-time DeFi protocol monitoring 

10""" 

11 

12import asyncio 

13import json 

14from pathlib import Path 

15from typing import Dict, Any, List, Optional, Tuple 

16from dataclasses import dataclass, asdict 

17from enum import Enum 

18 

19from .solidity_analyzer import SolidityStaticAnalyzer, SolidityVulnerability 

20from .defi_risk_assessor import DeFiRiskAssessor, EconomicRisk, EconomicRiskType 

21from .multi_chain_scanner import MultiChainScanner, BlockchainType 

22 

23# LLM Enhancement (optional) 

24try: 

25 from ..llm_enhancer import LLMEnhancer 

26 from ..llm_config import LLMConfig 

27 LLM_AVAILABLE = True 

28except ImportError: 

29 LLM_AVAILABLE = False 

30 

31class VulnerabilitySeverity(Enum): 

32 CRITICAL = "critical" 

33 HIGH = "high" 

34 MEDIUM = "medium" 

35 LOW = "low" 

36 INFO = "info" 

37 

38@dataclass 

39class Web3SecurityReport: 

40 """Comprehensive Web3 security report""" 

41 agent: str 

42 status: str 

43 blockchain_type: str 

44 contracts_scanned: List[str] 

45 vulnerabilities: List[Dict[str, Any]] 

46 economic_risks: List[Dict[str, Any]] 

47 risk_score: int 

48 exploit_simulation: List[Dict[str, Any]] 

49 recommendations: List[str] 

50 summary: Dict[str, int] 

51 confidence_score: float 

52 

53class Web3AuditorAgent: 

54 """ 

55 Web3/DeFi Security Auditor - Startup-focused blockchain security analysis 

56  

57 Comprehensive security testing for smart contracts and DeFi protocols 

58 """ 

59 

60 def __init__(self): 

61 self.name = "Web3/DeFi Security Auditor" 

62 self.agent_type = "web3-security" 

63 self.description = "Enterprise-grade Web3 smart contract security analysis with AI-enhanced economic risk assessment" 

64 

65 # Core analysis engines 

66 self.solidity_analyzer = SolidityStaticAnalyzer() 

67 self.defi_assessor = DeFiRiskAssessor() 

68 self.multi_chain_scanner = MultiChainScanner() 

69 

70 # Vulnerability databases 

71 self.exploit_database = self._initialize_exploit_database() 

72 self.owasp_patterns = self._load_owasp_smart_contract_patterns() 

73 

74 # Supported blockchain platforms 

75 self.supported_chains = [ 

76 BlockchainType.ETHEREUM, 

77 BlockchainType.POLYGON, 

78 BlockchainType.BSC, 

79 BlockchainType.AVALANCHE, 

80 BlockchainType.ARBITRUM, 

81 BlockchainType.OPTIMISM 

82 ] 

83 

84 def analyze_directory(self, directory_path: str) -> Web3SecurityReport: 

85 """ 

86 Analyze a directory of smart contracts 

87  

88 Args: 

89 directory_path: Path to directory containing smart contracts 

90  

91 Returns: 

92 Comprehensive Web3 security report 

93 """ 

94 directory = Path(directory_path) 

95 

96 if not directory.exists(): 

97 return self._error_report(f"Directory not found: {directory_path}") 

98 

99 # Discover smart contracts 

100 contract_files = self._discover_contract_files(directory) 

101 

102 if not contract_files: 

103 return self._error_report(f"No smart contracts found in {directory_path}") 

104 

105 all_vulnerabilities = [] 

106 all_economic_risks = [] 

107 contracts_scanned = [] 

108 

109 # Analyze each contract file 

110 for contract_file in contract_files: 

111 try: 

112 contract_report = self.analyze_contract_file(contract_file) 

113 

114 all_vulnerabilities.extend(contract_report.get('vulnerabilities', [])) 

115 all_economic_risks.extend(contract_report.get('economic_risks', [])) 

116 

117 if contract_report.get('contracts'): 

118 contracts_scanned.extend(contract_report['contracts']) 

119 

120 except Exception as e: 

121 error_vuln = { 

122 'severity': 'low', 

123 'type': 'Analysis Error', 

124 'title': f'Failed to analyze {contract_file}', 

125 'description': str(e), 

126 'file_path': str(contract_file), 

127 'confidence': 20 

128 } 

129 all_vulnerabilities.append(error_vuln) 

130 

131 # Calculate risk scores 

132 overall_risk_score = self._calculate_overall_risk_score(all_vulnerabilities, all_economic_risks) 

133 

134 # Generate recommendations 

135 recommendations = self._generate_recommendations(all_vulnerabilities, all_economic_risks) 

136 

137 # Mock exploit simulation results 

138 exploit_simulation = self._simulate_exploit_scenarios(all_vulnerabilities, all_economic_risks) 

139 

140 return Web3SecurityReport( 

141 agent=self.name, 

142 status="success", 

143 blockchain_type="multi-chain", 

144 contracts_scanned=list(set(contracts_scanned)), 

145 vulnerabilities=self._format_vulnerabilities(all_vulnerabilities), 

146 economic_risks=self._format_economic_risks(all_economic_risks), 

147 risk_score=overall_risk_score, 

148 exploit_simulation=exploit_simulation, 

149 recommendations=recommendations, 

150 summary= self._generate_summary(all_vulnerabilities, all_economic_risks), 

151 confidence_score=self._calculate_confidence_score(all_vulnerabilities, all_economic_risks) 

152 ) 

153 

154 def analyze_contract_file(self, file_path: str, blockchain_type: str = "ethereum") -> Dict[str, Any]: 

155 """ 

156 Analyze a single smart contract file 

157  

158 Args: 

159 file_path: Path to contract file 

160 blockchain_type: Target blockchain platform 

161  

162 Returns: 

163 Analysis results for the contract 

164 """ 

165 file_path = Path(file_path) 

166 

167 if not file_path.exists(): 

168 return { 

169 'status': 'error', 

170 'error': f'File not found: {file_path}', 

171 'vulnerabilities': [], 

172 'economic_risks': [], 

173 'contracts': [] 

174 } 

175 

176 try: 

177 contract_code = file_path.read_text(encoding='utf-8') 

178 

179 # Detect contract language 

180 contract_language = self._detect_contract_language(file_path, contract_code) 

181 

182 if contract_language == "solidity": 

183 return self._analyze_solidity_contract(contract_code, str(file_path)) 

184 elif contract_language == "solana": 

185 return self._analyze_solana_contract(contract_code, str(file_path)) 

186 else: 

187 return self._analyze_generic_contract(contract_code, str(file_path)) 

188 

189 except Exception as e: 

190 return { 

191 'status': 'error', 

192 'error': f'Failed to analyze {file_path}: {str(e)}', 

193 'vulnerabilities': [], 

194 'economic_risks': [], 

195 'contracts': [] 

196 } 

197 

198 def _analyze_solidity_contract(self, contract_code: str, file_path: str) -> Dict[str, Any]: 

199 """Analyze Solidity smart contract""" 

200 

201 # Static analysis 

202 static_vulnerabilities = self.solidity_analyzer.analyze_contract(contract_code, file_path) 

203 

204 # Economic risk assessment 

205 protocol_context = { 

206 'file_path': file_path, 

207 'language': 'solidity', 

208 'protocol_type': self._infer_protocol_type(contract_code) 

209 } 

210 economic_risks = self.defi_assessor.assess_economic_risks(contract_code, protocol_context) 

211 

212 # Extract contract names 

213 contract_names = self._extract_contract_names(contract_code) 

214 

215 return { 

216 'status': 'success', 

217 'language': 'solidity', 

218 'contracts': contract_names, 

219 'vulnerabilities': static_vulnerabilities, 

220 'economic_risks': economic_risks 

221 } 

222 

223 def _analyze_solana_contract(self, contract_code: str, file_path: str) -> Dict[str, Any]: 

224 """Analyze Solana program (Rust)""" 

225 

226 # Placeholder for Solana analysis - would implement Rust static analysis 

227 vulnerabilities = [] 

228 economic_risks = [] 

229 

230 # Basic Solana-specific checks 

231 rust_patterns = [ 

232 ('unsafe', 'code', 'high', 'Unsafe block detected - potential security risk'), 

233 ('vec', 'memory', 'medium', 'Vector usage may cause memory issues'), 

234 ('unwrap', 'error', 'medium', 'unwrap() calls may panic on error'), 

235 ] 

236 

237 lines = contract_code.split('\n') 

238 for i, line in enumerate(lines): 

239 for pattern, vuln_type, severity, description in rust_patterns: 

240 if pattern in line: 

241 vulnerabilities.append({ 

242 'vulnerability_type': vuln_type, 

243 'severity': severity, 

244 'title': f'{vuln_type.title()} Risk', 

245 'description': description, 

246 'file_path': file_path, 

247 'line_number': i + 1, 

248 'contract_name': 'solana_program', 

249 'code_snippet': line.strip(), 

250 'confidence': 70 

251 }) 

252 

253 program_names = self._extract_rust_program_names(contract_code) 

254 

255 return { 

256 'status': 'success', 

257 'language': 'rust', 

258 'contracts': program_names, 

259 'vulnerabilities': vulnerabilities, 

260 'economic_risks': economic_risks 

261 } 

262 

263 def _analyze_generic_contract(self, contract_code: str, file_path: str) -> Dict[str, Any]: 

264 """Analyze generic smart contract (fallback logic)""" 

265 

266 vulnerabilities = [] 

267 economic_risks = [] 

268 

269 # Basic pattern matching for common contract patterns 

270 suspicious_patterns = [ 

271 ('transfer', 'security', 'medium', 'Transfer function detected - manual audit recommended'), 

272 ('balance', 'security', 'medium', 'Balance manipulation detected'), 

273 ('owner', 'access', 'medium', 'Owner function - verify access controls'), 

274 ] 

275 

276 lines = contract_code.split('\n') 

277 for i, line in enumerate(lines): 

278 for pattern, category, severity, description in suspicious_patterns: 

279 if pattern in line.lower(): 

280 vulnerabilities.append({ 

281 'vulnerability_type': category, 

282 'severity': severity, 

283 'title': f'{category.title()} Pattern', 

284 'description': description, 

285 'file_path': file_path, 

286 'line_number': i + 1, 

287 'contract_name': 'unknown', 

288 'code_snippet': line.strip(), 

289 'confidence': 50 

290 }) 

291 

292 return { 

293 'status': 'success', 

294 'language': 'unknown', 

295 'contracts': ['generic_contract'], 

296 'vulnerabilities': vulnerabilities, 

297 'economic_risks': economic_risks 

298 } 

299 

300 def _discover_contract_files(self, directory: Path) -> List[Path]: 

301 """Discover smart contract files in directory""" 

302 contract_files = [] 

303 

304 # Solidity files 

305 sol_patterns = list(directory.rglob("*.sol")) 

306 contract_files.extend(sol_patterns) 

307 

308 # Solana/Rust files 

309 rs_patterns = [] 

310 for rust_file in directory.rglob("*.rs"): 

311 # Check if it's likely a Solana program 

312 rust_content = rust_file.read_text(encoding='utf-8', errors='ignore') 

313 if any(solana_keyword in rust_content for solana_keyword in ['sol_program', 'account_info', 'pubkey']): 

314 rs_patterns.append(rust_file) 

315 contract_files.extend(rs_patterns) 

316 

317 # Move files 

318 move_patterns = list(directory.rglob("*.move")) 

319 contract_files.extend(move_patterns) 

320 

321 return contract_files 

322 

323 def _detect_contract_language(self, file_path: Path, contract_code: str) -> str: 

324 """Detect smart contract programming language""" 

325 

326 file_extension = file_path.suffix.lower() 

327 

328 if file_extension == '.sol': 

329 return 'solidity' 

330 elif file_extension == '.rs': 

331 if 'sol_program' in contract_code or 'account_info' in contract_code: 

332 return 'solana' 

333 else: 

334 return 'rust' 

335 elif file_extension == '.move': 

336 return 'move' 

337 else: 

338 # Try to detect from content 

339 if any(keyword in contract_code for keyword in ['contract', 'function', 'modifier']): 

340 return 'solidity' 

341 elif any(keyword in contract_code for keyword in ['program', 'account_info', 'pubkey']): 

342 return 'solana' 

343 else: 

344 return 'unknown' 

345 

346 def _extract_contract_names(self, contract_code: str) -> List[str]: 

347 """Extract contract names from Solidity code""" 

348 import re 

349 contract_pattern = r'(abstract\s+)?contract\s+(\w+)' 

350 contracts = re.findall(contract_pattern, contract_code) 

351 return [name for _, name in contracts] 

352 

353 def _extract_rust_program_names(self, contract_code: str) -> List[str]: 

354 """Extract program names from Solana Rust code""" 

355 import re 

356 program_pattern = r'sol_program!\s*\[(.*?)\]\s*fn\s*(\w+)' 

357 programs = re.findall(program_pattern, contract_code) 

358 return [name for _, name in programs] 

359 

360 def _infer_protocol_type(self, contract_code: str) -> str: 

361 """Infer DeFi protocol type from contract code""" 

362 contract_lower = contract_code.lower() 

363 

364 if any(token in contract_lower for token in ['uniswap', 'swap', 'liquidity']): 

365 return 'Decentralized Exchange (DEX)' 

366 elif any(token in contract_lower for token in ['lending', 'borrow', 'interest']): 

367 return 'Lending Protocol' 

368 elif any(token in contract_lower for token in ['price', 'oracle', 'feed']): 

369 return 'Price Oracle' 

370 elif any(token in contract_lower for token in ['governance', 'vote', 'propose']): 

371 return 'Governance Protocol' 

372 elif any(token in contract_lower for token in ['token', 'mint', 'burn']): 

373 return 'Token Contract' 

374 else: 

375 return 'General DeFi Protocol' 

376 

377 def _calculate_overall_risk_score(self, vulnerabilities: List, economic_risks: List) -> int: 

378 """Calculate overall risk score 0-100""" 

379 if not vulnerabilities and not economic_risks: 

380 return 0 

381 

382 severity_weights = { 

383 'critical': 25, 

384 'high': 15, 

385 'medium': 8, 

386 'low': 3 

387 } 

388 

389 # Calculate vulnerability score 

390 vulnerability_score = sum( 

391 severity_weights.get(vuln.get('severity', 'low'), 3) 

392 for vuln in vulnerabilities 

393 ) 

394 

395 # Economic risks are weighted higher as they typically have bigger impact 

396 economic_risk_score = sum( 

397 severity_weights.get(risk.get('severity', 'medium'), 8) * 1.2 

398 for risk in economic_risks 

399 ) 

400 

401 total_score = vulnerability_score + economic_risk_score 

402 return min(100, int(total_score)) 

403 

404 def _generate_recommendations(self, vulnerabilities: List, economic_risks: List) -> List[str]: 

405 """Generate actionable security recommendations""" 

406 recommendations = [] 

407 

408 # Based on vulnerability types 

409 vuln_types = {v.get('vulnerability_type') for v in vulnerabilities} 

410 

411 if 'reentrancy' in vuln_types: 

412 recommendations.append("Implement ReentrancyGuard modifier and follow checks-effects-interactions pattern") 

413 

414 if 'access_control' in vuln_types: 

415 recommendations.append("Review and implement proper access control for all critical functions") 

416 

417 if 'integer_overflow_underflow' in vuln_types: 

418 recommendations.append("Use SafeMath library or Solidity 0.8+ which has built-in overflow protection") 

419 

420 # Based on economic risk types  

421 economic_types = {r.get('risk_type') for r in economic_risks} 

422 

423 if EconomicRiskType.FLASH_LOAN_ATTACK.value in economic_types: 

424 recommendations.append("Implement flash loan protection and validate price calculations") 

425 

426 if EconomicRiskType.PRICE_ORACLE_MANIPULATION.value in economic_types: 

427 recommendations.append("Use multiple oracle sources and implement price deviation checks") 

428 

429 if EconomicRiskType.LIQUIDITY_DRAIN.value in economic_types: 

430 recommendations.append("Add withdrawal limits and implement emergency pause mechanisms") 

431 

432 # General recommendations 

433 recommendations.extend([ 

434 "Consider professional security audit before mainnet deployment", 

435 "Implement comprehensive testing including fuzzing and property-based testing", 

436 "Set up monitoring and alerting for suspicious activities" 

437 ]) 

438 

439 return list(set(recommendations)) # Remove duplicates 

440 

441 def _simulate_exploit_scenarios(self, vulnerabilities: List, economic_risks: List) -> List[Dict[str, Any]]: 

442 """Simulate potential exploit scenarios""" 

443 scenarios = [] 

444 

445 # Flash loan attack simulation 

446 flash_loan_vulns = [v for v in vulnerabilities if v.get('vulnerability_type') == 'reentrancy'] 

447 if flash_loan_vulns: 

448 scenarios.append({ 

449 'attack_type': 'Flash Loan Manipulation', 

450 'probability': 'High', 

451 'potential_loss': 'Complete fund drain', 

452 'description': 'Attacker uses flash loan to manipulate prices and exploit reentrancy', 

453 'prevention': 'Add reentrancy protection and price validation' 

454 }) 

455 

456 # Governance attack simulation 

457 governance_vulns = [v for v in vulnerabilities if v.get('vulnerability_type') == 'access_control'] 

458 if governance_vulns: 

459 scenarios.append({ 

460 'attack_type': 'Governance Takeover', 

461 'probability': 'Medium', 

462 'potential_loss': 'Protocol control loss', 

463 'description': 'Attaker gains voting power and passes malicious proposals', 

464 'prevention': 'Implement voting time-locks and access controls' 

465 }) 

466 

467 return scenarios 

468 

469 def _generate_summary(self, vulnerabilities: List, economic_risks: List) -> Dict[str, int]: 

470 """Generate summary statistics""" 

471 summary = { 

472 'critical': 0, 

473 'high': 0, 

474 'medium': 0, 

475 'low': 0 

476 } 

477 

478 for vuln in vulnerabilities: 

479 severity = vuln.get('severity', 'low') 

480 summary[severity] = summary.get(severity, 0) + 1 

481 

482 for risk in economic_risks: 

483 severity = risk.get('severity', 'medium') 

484 summary[severity] = summary.get(severity, 0) + 1 

485 

486 return summary 

487 

488 def _calculate_confidence_score(self, vulnerabilities: List, economic_risks: List) -> float: 

489 """Calculate confidence score for analysis accuracy""" 

490 if not vulnerabilities and not economic_risks: 

491 return 100.0 # High confidence if no issues found 

492 

493 total_findings = len(vulnerabilities) + len(economic_risks) 

494 confidence_sum = sum(v.get('confidence', 70) for v in vulnerabilities) + \ 

495 sum(r.get('confidence', 80) for r in economic_risks) 

496 

497 return min(100.0, round(confidence_sum / total_findings, 1)) 

498 

499 def _format_vulnerabilities(self, vulnerabilities: List) -> List[Dict[str, Any]]: 

500 """Format vulnerabilities for JSON serialization""" 

501 return [v if isinstance(v, dict) else asdict(v) for v in vulnerabilities] 

502 

503 def _format_economic_risks(self, economic_risks: List) -> List[Dict[str, Any]]: 

504 """Format economic risks for JSON serialization""" 

505 return [r if isinstance(r, dict) else asdict(r) for r in economic_risks] 

506 

507 def _error_report(self, error_message: str) -> Web3SecurityReport: 

508 """Generate error report""" 

509 return Web3SecurityReport( 

510 agent=self.name, 

511 status="error", 

512 blockchain_type="unknown", 

513 contracts_scanned=[], 

514 vulnerabilities=[], 

515 economic_risks=[], 

516 risk_score=0, 

517 exploit_simulation=[], 

518 recommendations=["Verify file path and ensure smart contracts are present"], 

519 summary={'error': 1}, 

520 confidence_score=0.0 

521 ) 

522 

523 def _initialize_exploit_database(self) -> Dict[str, Any]: 

524 """Initialize historical exploit database""" 

525 return { 

526 'flash_loan_attacks': { 

527 "bzx_exploit_2020": "Attacker used flash loan to manipulate BZX price oracles", 

528 "harvest_finance_2020": "Flash loan manipulation exploited pricing mechanism", 

529 "pancakebunny_2022": "Flash loan attack on PancakeBunny liquidity pool" 

530 }, 

531 'access_control_breaches': { 

532 "parsec_finance_2022": "Access control bug allowed unlimited minting", 

533 "iron_finance_2021": "Access control vulnerability in token contract" 

534 }, 

535 'oracle_manipulation': { 

536 "cream_finance_2021": "Oracle manipulation led to financial losses" 

537 } 

538 } 

539 

540 def _load_owasp_smart_contract_patterns(self) -> Dict[str, List[str]]: 

541 """Load OWASP Smart Contract Top 10 patterns""" 

542 return { 

543 "reentrancy": ["call", "send", "transfer"], 

544 "access_control": ["onlyOwner", "require", "if"], 

545 "arithmetic": ["+", "-", "*", "/"], 

546 "unchecked_calls": [".call(", ".delegatecall("], 

547 "logic_errors": ["require", "revert", "assert"], 

548 "oracles": ["uniswap", "chainlink", "price"], 

549 "gas": ["gas", "block.gaslimit"] 

550 } 

551 

552# Integration wrapper for existing agent system 

553class Web3AuditorAgentWrapper: 

554 """Integration wrapper for Web3/DeFi Security Auditor Agent""" 

555 

556 def __init__(self): 

557 self.name = "Web3/DeFi Security Auditor" 

558 self.agent_type = "web3-security" 

559 self.description = "Enterprise-grade Web3 smart contract security analysis with AI-enhanced economic risk assessment" 

560 self.auditor = Web3AuditorAgent() 

561 

562 # LLM enhancer (optional) 

563 self.llm_enhancer = None 

564 self.llm_enabled = False 

565 

566 if LLM_AVAILABLE: 

567 try: 

568 from loguru import logger 

569 self.llm_enhancer = LLMEnhancer() 

570 self.llm_enabled = True 

571 logger.info("✅ LLM enhancement enabled (Claude AI)") 

572 except Exception as e: 

573 from loguru import logger 

574 logger.info(f"LLM enhancement disabled: {e}") 

575 

576 def analyze(self, target: str, options: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: 

577 """ 

578 Analyze target for Web3 security vulnerabilities 

579  

580 Args: 

581 target: Path to directory or file to analyze 

582 options: Additional analysis options 

583  

584 Returns: 

585 Dict containing analysis results 

586 """ 

587 try: 

588 target_path = Path(target) 

589 

590 if target_path.is_file(): 

591 # Single file analysis 

592 blockchain_type = options.get('blockchain', 'ethereum') if options else 'ethereum' 

593 result = self.auditor.analyze_contract_file(target, blockchain_type) 

594 

595 # Convert single file result to full report format 

596 contracts = result.get('contracts', ['unknown']) 

597 vulnerabilities = [v if isinstance(v, dict) else asdict(v) 

598 for v in result.get('vulnerabilities', [])] 

599 economic_risks = [r if isinstance(r, dict) else asdict(r) 

600 for r in result.get('economic_risks', [])] 

601 

602 # ENHANCE with LLM if enabled 

603 if self.llm_enabled and vulnerabilities: 

604 vulnerabilities = self._enhance_vulnerabilities_with_llm( 

605 vulnerabilities, 

606 target_path.read_text(encoding='utf-8') 

607 ) 

608 

609 # Count LLM-enhanced vulnerabilities 

610 llm_enhanced_count = sum( 

611 1 for v in vulnerabilities if v.get('llm_enhanced', False) 

612 ) 

613 

614 return { 

615 'agent': self.name, 

616 'status': result.get('status', 'error'), 

617 'blockchain_type': blockchain_type, 

618 'contracts_scanned': contracts, 

619 'risk_score': self._calculate_single_file_risk_score(vulnerabilities, economic_risks), 

620 'vulnerabilities_count': len(vulnerabilities), 

621 'economic_risks_count': len(economic_risks), 

622 'vulnerabilities': vulnerabilities, 

623 'economic_risks': economic_risks, 

624 'summary': self._generate_single_file_summary(vulnerabilities, economic_risks), 

625 'recommendations': self._generate_recommendations(vulnerabilities, economic_risks), 

626 'llm_enhanced': self.llm_enabled, 

627 'llm_enhanced_count': llm_enhanced_count 

628 } 

629 

630 else: 

631 # Directory analysis 

632 report = self.auditor.analyze_directory(target) 

633 

634 return { 

635 'agent': self.name, 

636 'status': report.status, 

637 'blockchain_type': report.blockchain_type, 

638 'contracts_scanned': report.contracts_scanned, 

639 'risk_score': report.risk_score, 

640 'vulnerabilities_count': len(report.vulnerabilities), 

641 'economic_risks_count': len(report.economic_risks), 

642 'vulnerabilities': report.vulnerabilities, 

643 'economic_risks': report.economic_risks, 

644 'summary': report.summary, 

645 'recommendations': report.recommendations, 

646 'confidence_score': report.confidence_score, 

647 'exploit_simulation': report.exploit_simulation 

648 } 

649 

650 except Exception as e: 

651 return { 

652 'agent': self.name, 

653 'status': 'error', 

654 'error': str(e), 

655 'vulnerabilities_count': 0, 

656 'economic_risks_count': 0, 

657 'risk_score': 0 

658 } 

659 

660 def _calculate_single_file_risk_score(self, vulnerabilities: List, economic_risks: List) -> int: 

661 """Calculate risk score for single file analysis""" 

662 if not vulnerabilities and not economic_risks: 

663 return 0 

664 

665 weights = {'critical': 25, 'high': 15, 'medium': 8, 'low': 3} 

666 vuln_score = sum(weights.get(v.get('severity', 'low'), 3) for v in vulnerabilities) 

667 econ_score = sum(weights.get(r.get('severity', 'medium'), 8) * 1.2 for r in economic_risks) 

668 

669 return min(100, int(vuln_score + econ_score)) 

670 

671 def _generate_single_file_summary(self, vulnerabilities: List, economic_risks: List) -> Dict[str, int]: 

672 """Generate summary for single file analysis""" 

673 summary = {'critical': 0, 'high': 0, 'medium': 0, 'low': 0} 

674 

675 for vuln in vulnerabilities: 

676 severity = vuln.get('severity', 'low') 

677 summary[severity] = summary.get(severity, 0) + 1 

678 

679 for risk in economic_risks: 

680 severity = risk.get('severity', 'medium') 

681 summary[severity] = summary.get(severity, 0) + 1 

682 

683 return summary 

684 

685 def _generate_recommendations(self, vulnerabilities: List, economic_risks: List) -> List[str]: 

686 """Generate recommendations for single file analysis""" 

687 recommendations = [] 

688 

689 if any(v.get('vulnerability_type') == 'reentrancy' for v in vulnerabilities): 

690 recommendations.append("Implement ReentrancyGuard modifier") 

691 

692 if any(v.get('vulnerability_type') == 'access_control' for v in vulnerabilities): 

693 recommendations.append("Review and fix access control mechanisms") 

694 

695 if any(r.get('risk_type') in ['flash_loan_attack', 'price_oracle_manipulation'] for r in economic_risks): 

696 recommendations.append("Implement flash loan protection and oracle validation") 

697 

698 recommendations.extend([ 

699 "Consider professional security audit", 

700 "Add comprehensive testing", 

701 "Implement monitoring and alerting" 

702 ]) 

703 

704 return list(set(recommendations)) 

705 

706 def _enhance_vulnerabilities_with_llm( 

707 self, 

708 vulnerabilities: List[Dict[str, Any]], 

709 contract_code: str 

710 ) -> List[Dict[str, Any]]: 

711 """ 

712 Enhance vulnerabilities with LLM analysis 

713 

714 Args: 

715 vulnerabilities: List of vulnerability dictionaries 

716 contract_code: Full contract source code 

717 

718 Returns: 

719 Enhanced vulnerability list 

720 """ 

721 from loguru import logger 

722 

723 if not self.llm_enhancer or not vulnerabilities: 

724 return vulnerabilities 

725 

726 # Sort vulnerabilities by severity (critical/high first) 

727 severity_order = {'critical': 0, 'high': 1, 'medium': 2, 'low': 3} 

728 sorted_vulns = sorted( 

729 vulnerabilities, 

730 key=lambda v: severity_order.get(v.get('severity', 'low'), 4) 

731 ) 

732 

733 enhanced_vulns = [] 

734 enhanced_count = 0 

735 

736 for vuln in vulnerabilities: 

737 # Only enhance top 5 critical/high vulnerabilities (cost optimization) 

738 should_enhance = ( 

739 vuln in sorted_vulns[:LLMConfig.MAX_VULNS_TO_ENHANCE] and 

740 vuln.get('severity', '').lower() in ['critical', 'high', 'medium'] 

741 ) 

742 

743 if should_enhance and enhanced_count < LLMConfig.MAX_VULNS_TO_ENHANCE: 

744 try: 

745 # Enhance with LLM 

746 enhanced = self.llm_enhancer.enhance_vulnerability(vuln, contract_code) 

747 enhanced_dict = enhanced.to_dict() 

748 enhanced_vulns.append(enhanced_dict) 

749 enhanced_count += 1 

750 logger.debug(f"✅ Enhanced: {vuln.get('title', 'Unknown')}") 

751 except Exception as e: 

752 logger.warning(f"LLM enhancement failed for {vuln.get('title', 'Unknown')}: {e}") 

753 enhanced_vulns.append(vuln) 

754 else: 

755 # Keep original vulnerability without enhancement 

756 enhanced_vulns.append(vuln) 

757 

758 logger.info(f"LLM enhanced {enhanced_count}/{len(vulnerabilities)} vulnerabilities") 

759 return enhanced_vulns