#!/bin/bash set -euo pipefail # Usage: ./analysis/run-fuzzing.sh [--help] [runs=N] [buybias=N] [trades=N] [uncapped=bool] [ci=N] [as=N] [aw=N] [dd=N] [debugCSV] show_help() { cat <<'EOF' Usage: ./analysis/run-fuzzing.sh [--help] [runs=N] [buybias=N] [trades=N] [uncapped=bool] [ci=N] [as=N] [aw=N] [dd=N] [debugCSV] Run StreamlinedFuzzing against a named optimizer. Each run generates a CSV file with per-trade position snapshots for analysis. Includes random stake/unstake actions (~10% of trades). Arguments: optimizer Required. One of: BullMarketOptimizer, BearMarketOptimizer, NeutralMarketOptimizer, WhaleOptimizer, ExtremeOptimizer, MaliciousOptimizer, ConfigurableOptimizer runs=N Number of fuzzing runs (default: 20) buybias=N Buy probability 0-100% (default: 50) trades=N Trades per run (default: 15) uncapped=true Enable uncapped swaps (default: false) debugCSV Run 3 short runs and launch the HTML visualizer ConfigurableOptimizer params (only used when optimizer=ConfigurableOptimizer): ci=N Capital inefficiency (uint256, default: 0) as=N Anchor share (uint256, default: 100000000000000000) aw=N Anchor width in ticks (uint24, default: 20, max 100) dd=N Discovery depth (uint256, default: 500000000000000000) Examples: ./analysis/run-fuzzing.sh BullMarketOptimizer ./analysis/run-fuzzing.sh WhaleOptimizer runs=100 trades=50 ./analysis/run-fuzzing.sh BearMarketOptimizer buybias=80 ./analysis/run-fuzzing.sh BullMarketOptimizer debugCSV ./analysis/run-fuzzing.sh ConfigurableOptimizer ci=0 as=100000000000000000 aw=20 dd=500000000000000000 runs=200 trades=100 uncapped=true EOF exit 0 } # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # Handle --help if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then show_help fi # Configuration OPTIMIZER=${1:-BullMarketOptimizer} # Check if second parameter is debugCSV DEBUG_CSV=false if [[ "${2:-}" == "debugCSV" ]]; then DEBUG_CSV=true RUNS_VALUE=3 BUYBIAS_VALUE=50 TRADES_VALUE=5 UNCAPPED_VALUE=false CI_VALUE=0 AS_VALUE=100000000000000000 AW_VALUE=20 DD_VALUE=500000000000000000 else # Parse key=value parameters from remaining args RUNS_VALUE=20 BUYBIAS_VALUE=50 TRADES_VALUE=15 UNCAPPED_VALUE=false CI_VALUE=0 AS_VALUE=100000000000000000 AW_VALUE=20 DD_VALUE=500000000000000000 shift || true # skip optimizer arg for arg in "$@"; do case "$arg" in runs=*) RUNS_VALUE=${arg#runs=} ;; buybias=*) BUYBIAS_VALUE=${arg#buybias=} ;; trades=*) TRADES_VALUE=${arg#trades=} ;; uncapped=*) UNCAPPED_VALUE=${arg#uncapped=} ;; ci=*) CI_VALUE=${arg#ci=} ;; as=*) AS_VALUE=${arg#as=} ;; aw=*) AW_VALUE=${arg#aw=} ;; dd=*) DD_VALUE=${arg#dd=} ;; debugCSV) DEBUG_CSV=true; RUNS_VALUE=3; TRADES_VALUE=5 ;; *) echo -e "${RED}Unknown parameter: $arg${NC}"; show_help ;; esac done fi # Ensure we're in the onchain directory cd "$(dirname "$0")/.." echo -e "${GREEN}=== Fuzzing Analysis ===${NC}" echo "Optimizer: $OPTIMIZER" echo "Total runs: $RUNS_VALUE" echo "Trades per run: $TRADES_VALUE" echo "Buy bias: $BUYBIAS_VALUE%" echo "Uncapped: $UNCAPPED_VALUE" if [ "$OPTIMIZER" = "ConfigurableOptimizer" ]; then echo "CI: $CI_VALUE AS: $AS_VALUE AW: $AW_VALUE DD: $DD_VALUE" fi echo "" # Validate optimizer case $OPTIMIZER in BullMarketOptimizer|BearMarketOptimizer|NeutralMarketOptimizer|WhaleOptimizer|ExtremeOptimizer|MaliciousOptimizer|ConfigurableOptimizer) ;; *) echo -e "${RED}Error: Invalid optimizer class '$OPTIMIZER'${NC}" echo "Valid: BullMarketOptimizer, BearMarketOptimizer, NeutralMarketOptimizer, WhaleOptimizer, ExtremeOptimizer, MaliciousOptimizer, ConfigurableOptimizer" exit 1 ;; esac # Record existing CSV files before running EXISTING_CSVS=$(ls -1 analysis/fuzz-????-???.csv 2>/dev/null | sort || true) echo -e "${YELLOW}Starting fuzzing analysis...${NC}" echo "" FUZZING_RUNS=$RUNS_VALUE \ OPTIMIZER_CLASS=$OPTIMIZER \ BUY_BIAS=$BUYBIAS_VALUE \ TRADES_PER_RUN=$TRADES_VALUE \ UNCAPPED_SWAPS=$UNCAPPED_VALUE \ CI_VALUE=$CI_VALUE \ AS_VALUE=$AS_VALUE \ AW_VALUE=$AW_VALUE \ DD_VALUE=$DD_VALUE \ forge script analysis/StreamlinedFuzzing.s.sol:StreamlinedFuzzing --skip-simulation --gas-estimate-multiplier 300 -vv 2>&1 echo "" echo -e "${GREEN}=== ANALYSIS COMPLETE ===${NC}" # Find newly generated CSV files NEW_CSVS=$(ls -1 analysis/fuzz-????-???.csv 2>/dev/null | sort || true) if [ "$EXISTING_CSVS" != "$NEW_CSVS" ]; then SCENARIO_CODE=$(echo "$NEW_CSVS" | grep -v -F "$EXISTING_CSVS" 2>/dev/null | head -1 | sed 's|.*/fuzz-\(....\).*|\1|' || echo "UNKN") else SCENARIO_CODE="UNKN" fi CSV_COUNT=$(ls -1 analysis/fuzz-${SCENARIO_CODE}-*.csv 2>/dev/null | wc -l || true) echo "Generated $CSV_COUNT CSV files with scenario ID: ${SCENARIO_CODE}" # Check for profitable scenarios echo "" echo -e "${YELLOW}=== Checking for Profitable Scenarios ===${NC}" PROFITABLE_COUNT=0 for csv in analysis/fuzz-${SCENARIO_CODE}-*.csv; do if [ -f "$csv" ]; then INIT_ETH=$(grep "^INIT," "$csv" | cut -d',' -f13 || true) FINAL_ETH=$(grep "^FINAL," "$csv" | cut -d',' -f13 || true) if [ -n "$INIT_ETH" ] && [ -n "$FINAL_ETH" ]; then if [ "$FINAL_ETH" -gt "$INIT_ETH" ] 2>/dev/null; then PROFIT_PCT=$(echo "scale=1; ($FINAL_ETH - $INIT_ETH) * 100 / $INIT_ETH" | bc -l 2>/dev/null || echo "?") echo -e "${GREEN} $csv: PROFITABLE (+${PROFIT_PCT}%)${NC}" ((PROFITABLE_COUNT++)) || true fi fi fi done if [ $PROFITABLE_COUNT -eq 0 ]; then echo " No profitable scenarios found" else echo -e "${GREEN}Found $PROFITABLE_COUNT profitable scenarios${NC}" fi echo "" echo -e "${GREEN}CSV files generated with scenario ID: ${SCENARIO_CODE}${NC}" # Launch HTML visualizer if debugCSV mode if [ "$DEBUG_CSV" = true ]; then echo "" echo -e "${YELLOW}Launching HTML visualizer...${NC}" if command -v python3 &> /dev/null; then echo "Starting local server at http://localhost:8000" echo "Open http://localhost:8000/run-visualizer.html to view results" cd analysis python3 -m http.server 8000 --bind 127.0.0.1 & SERVER_PID=$! sleep 1 if command -v open &> /dev/null; then open "http://localhost:8000/run-visualizer.html" elif command -v xdg-open &> /dev/null; then xdg-open "http://localhost:8000/run-visualizer.html" fi echo "" echo "Press Ctrl+C to stop the server" wait $SERVER_PID else echo "Python3 not found. To view results:" echo " cd analysis && python3 -m http.server 8000" echo " Then open http://localhost:8000/run-visualizer.html" fi fi