#!/usr/bin/env bash # # Solidity Audit Pipeline for MEV Bot Smart Contracts # Integrates with harness/local-ci-pipeline.sh # # This script audits Solidity contracts using Docker-based security tools # Based on docs/solidity_audit_bundle.md specifications set -euo pipefail ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) cd "$ROOT_DIR" HARNESS_DIR="$ROOT_DIR/harness" LOG_DIR="${HARNESS_LOG_DIR:-$HARNESS_DIR/logs}/solidity" REPORT_DIR="${HARNESS_REPORT_DIR:-$HARNESS_DIR/reports}/solidity" mkdir -p "$LOG_DIR" "$REPORT_DIR" # Container runtime detection CONTAINER_RUNTIME="${HARNESS_RUNTIME:-}" if [[ -z "$CONTAINER_RUNTIME" ]]; then if command -v podman >/dev/null 2>&1; then CONTAINER_RUNTIME=podman elif command -v docker >/dev/null 2>&1; then CONTAINER_RUNTIME=docker else echo "ERROR: No container runtime found. Docker or Podman is required." >&2 exit 1 fi fi # Configuration SKIP_FOUNDRY="${HARNESS_SKIP_FOUNDRY:-false}" SKIP_SLITHER="${HARNESS_SKIP_SLITHER:-false}" SKIP_MYTHRIL="${HARNESS_SKIP_MYTHRIL:-false}" VERBOSE="${HARNESS_VERBOSE:-false}" log() { printf '[%s] [SOLIDITY] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" } run_step() { local name="$1" shift local logfile="$LOG_DIR/${name}.log" log "Starting $name" if "$@" |& tee "$logfile"; then log "✅ Completed $name" return 0 else log "❌ Failed $name - see $logfile" return 1 fi } check_contracts() { log "Checking for Solidity contracts..." if [[ ! -d "$ROOT_DIR/contracts" ]]; then log "No contracts directory found - skipping Solidity audit" exit 0 fi local contract_count=$(find "$ROOT_DIR/contracts" -name "*.sol" -type f | wc -l) if [[ $contract_count -eq 0 ]]; then log "No Solidity contracts found - skipping audit" exit 0 fi log "Found $contract_count Solidity contracts to audit" } run_foundry_tests() { if [[ "$SKIP_FOUNDRY" == "true" ]]; then log "Skipping Foundry tests (HARNESS_SKIP_FOUNDRY=true)" return 0 fi log "Running Foundry tests..." if ! command -v forge >/dev/null 2>&1; then log "Forge not found locally, using Docker image..." run_step "foundry-test" $CONTAINER_RUNTIME run --rm \ -v "$ROOT_DIR:/src" \ -w /src \ ghcr.io/foundry-rs/foundry:latest \ forge test --gas-report --ffi --json else log "Using local Forge installation" run_step "foundry-test" forge test --gas-report --ffi --json fi # Save gas report if [[ -f "reports/forge-gas.json" ]]; then cp reports/forge-gas.json "$REPORT_DIR/forge-gas.json" fi } run_slither_analysis() { if [[ "$SKIP_SLITHER" == "true" ]]; then log "Skipping Slither analysis (HARNESS_SKIP_SLITHER=true)" return 0 fi log "Running Slither static analysis..." local slither_args=( run --rm -v "$ROOT_DIR:/src" -w /src trailofbits/eth-security-toolbox:latest slither . --json "$REPORT_DIR/slither.json" --exclude-dependencies --exclude-informational ) if [[ "$VERBOSE" == "true" ]]; then slither_args+=(--print human-summary) fi run_step "slither-analysis" $CONTAINER_RUNTIME "${slither_args[@]}" || true } run_mythril_analysis() { if [[ "$SKIP_MYTHRIL" == "true" ]]; then log "Skipping Mythril analysis (HARNESS_SKIP_MYTHRIL=true)" return 0 fi log "Running Mythril symbolic execution..." # Mythril analysis for each contract while IFS= read -r -d '' contract; do local contract_name=$(basename "$contract" .sol) log "Analyzing $contract_name with Mythril..." $CONTAINER_RUNTIME run --rm \ -v "$ROOT_DIR:/src" \ -w /src \ mythril/myth:latest \ analyze "$contract" \ --solc-json "$REPORT_DIR/mythril-${contract_name}.json" \ --max-depth 128 || true done < <(find "$ROOT_DIR/contracts" -name "*.sol" -not -path "*/test/*" -print0) } generate_audit_report() { log "Generating consolidated audit report..." local report_file="$REPORT_DIR/audit-summary.md" cat > "$report_file" << 'EOF' # Solidity Contract Audit Report **Date**: $(date '+%Y-%m-%d %H:%M:%S') **MEV Bot Version**: $(git describe --tags --always 2>/dev/null || echo "unknown") ## Contracts Audited EOF find "$ROOT_DIR/contracts" -name "*.sol" -not -path "*/test/*" | while read contract; do echo "- $(basename "$contract")" >> "$report_file" done cat >> "$report_file" << 'EOF' ## Audit Tools Used - ✅ Foundry (forge test) - ✅ Slither (static analysis) - ✅ Mythril (symbolic execution) ## Results Summary ### Foundry Tests EOF if [[ -f "$REPORT_DIR/forge-gas.json" ]]; then echo "See \`reports/solidity/forge-gas.json\` for detailed gas analysis." >> "$report_file" else echo "⚠️ No Foundry test results found." >> "$report_file" fi cat >> "$report_file" << 'EOF' ### Slither Analysis EOF if [[ -f "$REPORT_DIR/slither.json" ]]; then echo "See \`reports/solidity/slither.json\` for detailed vulnerability analysis." >> "$report_file" else echo "⚠️ No Slither results found." >> "$report_file" fi cat >> "$report_file" << 'EOF' ### Mythril Analysis EOF local mythril_count=$(find "$REPORT_DIR" -name "mythril-*.json" 2>/dev/null | wc -l) if [[ $mythril_count -gt 0 ]]; then echo "Found $mythril_count Mythril analysis reports." >> "$report_file" else echo "⚠️ No Mythril results found." >> "$report_file" fi log "Audit report generated: $report_file" } # Main execution main() { log "Starting Solidity Contract Audit Pipeline" log "Container runtime: $CONTAINER_RUNTIME" check_contracts run_foundry_tests run_slither_analysis run_mythril_analysis generate_audit_report log "✅ Solidity audit pipeline completed successfully" log "Reports available in: $REPORT_DIR" } main "$@"