- Added BUY_BIAS environment variable (0-100%) to control trading direction - Implemented biased trading logic in all strategies (Random, Whale, Volatile, etc.) - Created run-improved-fuzzing.sh script with buy bias support - Fixed memory issues in CSV generation by simplifying string concatenation - Fixed console.log parameter issues in staking functions - Updated run-recorded-fuzzing.sh to accept buybias parameter - Testing shows up to 99% of authorized stake reached with 100% buy bias Co-Authored-By: Claude <noreply@anthropic.com>
256 lines
No EOL
8.6 KiB
Bash
Executable file
256 lines
No EOL
8.6 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# Usage: ./run-recorded-fuzzing.sh [optimizer] [runs=N] [trades=N] [staking=on|off] [buybias=N]
|
|
# Examples:
|
|
# ./run-recorded-fuzzing.sh BullMarketOptimizer runs=50
|
|
# ./run-recorded-fuzzing.sh WhaleOptimizer runs=20 trades=30 staking=off
|
|
# ./run-recorded-fuzzing.sh ExtremeOptimizer runs=100 trades=default staking=on buybias=80
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
BOLD='\033[1m'
|
|
|
|
# Configuration
|
|
OPTIMIZER=${1:-BullMarketOptimizer}
|
|
RUNS=${2:-runs=20}
|
|
TRADES=${3:-trades=default}
|
|
STAKING=${4:-staking=on}
|
|
BUYBIAS=${5:-buybias=50}
|
|
|
|
# Parse runs parameter
|
|
if [[ $RUNS == runs=* ]]; then
|
|
RUNS_VALUE=${RUNS#runs=}
|
|
else
|
|
RUNS_VALUE=$RUNS
|
|
RUNS="runs=$RUNS"
|
|
fi
|
|
|
|
# Parse trades parameter (for future use)
|
|
TRADES_VALUE=""
|
|
if [[ $TRADES == trades=* ]]; then
|
|
TRADES_VALUE=${TRADES#trades=}
|
|
fi
|
|
|
|
# Parse staking parameter
|
|
STAKING_ENABLED="true"
|
|
if [[ $STAKING == staking=* ]]; then
|
|
STAKING_VALUE=${STAKING#staking=}
|
|
if [[ $STAKING_VALUE == "off" ]] || [[ $STAKING_VALUE == "false" ]] || [[ $STAKING_VALUE == "0" ]]; then
|
|
STAKING_ENABLED="false"
|
|
fi
|
|
elif [[ $STAKING == "nostaking" ]]; then
|
|
STAKING_ENABLED="false"
|
|
fi
|
|
|
|
# Parse buy bias parameter
|
|
BUYBIAS_VALUE="50"
|
|
if [[ $BUYBIAS == buybias=* ]]; then
|
|
BUYBIAS_VALUE=${BUYBIAS#buybias=}
|
|
fi
|
|
|
|
# Generate unique run ID (6 chars from timestamp + random)
|
|
RUN_ID=$(date +%y%m%d)-$(head /dev/urandom | tr -dc A-Z0-9 | head -c 4)
|
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
OUTPUT_DIR="fuzzing_results_recorded_${OPTIMIZER}_${TIMESTAMP}"
|
|
|
|
echo -e "${GREEN}=== Recorded Fuzzing Campaign ===${NC}"
|
|
echo -e "Run ID: ${BOLD}${RUN_ID}${NC}"
|
|
echo "Optimizer: $OPTIMIZER"
|
|
echo "Total runs: $RUNS_VALUE"
|
|
echo "Staking: $([ "$STAKING_ENABLED" = "true" ] && echo "enabled" || echo "disabled")"
|
|
echo "Buy bias: $BUYBIAS_VALUE%"
|
|
echo "Output directory: $OUTPUT_DIR"
|
|
echo ""
|
|
|
|
# Validate optimizer
|
|
case $OPTIMIZER in
|
|
BullMarketOptimizer|BearMarketOptimizer|NeutralMarketOptimizer|WhaleOptimizer|ExtremeOptimizer|MaliciousOptimizer)
|
|
echo "Optimizer validation passed"
|
|
;;
|
|
*)
|
|
echo -e "${RED}Error: Invalid optimizer class${NC}"
|
|
echo "Valid options: BullMarketOptimizer, BearMarketOptimizer, NeutralMarketOptimizer, WhaleOptimizer, ExtremeOptimizer, MaliciousOptimizer"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Create output directory
|
|
mkdir -p $OUTPUT_DIR
|
|
|
|
# Run the recorded fuzzing
|
|
echo -e "${YELLOW}Starting recorded fuzzing analysis...${NC}"
|
|
FUZZING_RUNS=$RUNS_VALUE \
|
|
OPTIMIZER_CLASS=$OPTIMIZER \
|
|
ENABLE_STAKING=$STAKING_ENABLED \
|
|
BUY_BIAS=$BUYBIAS_VALUE \
|
|
RUN_ID=$RUN_ID \
|
|
forge script analysis/RecordedFuzzingAnalysis.s.sol:RecordedFuzzingAnalysis --gas-limit 1000000000 -vv 2>&1 | tee $OUTPUT_DIR/fuzzing.log
|
|
|
|
# Check for generated scenario files (check for summaries, they're always generated)
|
|
SCENARIO_COUNT=$(ls -1 scenario_summary_seed*.txt 2>/dev/null | wc -l)
|
|
|
|
if [ $SCENARIO_COUNT -gt 0 ]; then
|
|
echo ""
|
|
echo -e "${GREEN}=== INVARIANT VIOLATIONS FOUND! ===${NC}"
|
|
echo -e "${BOLD}Found $SCENARIO_COUNT profitable scenarios${NC}"
|
|
echo ""
|
|
|
|
# Move recording files to output directory with run ID
|
|
for file in recorded_scenario_seed*.json; do
|
|
if [ -f "$file" ]; then
|
|
SEED=$(echo $file | sed 's/recorded_scenario_seed\(.*\)\.json/\1/')
|
|
NEW_NAME="scenario_${RUN_ID}_seed${SEED}.json"
|
|
mv "$file" "$OUTPUT_DIR/$NEW_NAME"
|
|
echo -e " Scenario JSON: ${BLUE}$OUTPUT_DIR/$NEW_NAME${NC}"
|
|
fi
|
|
done
|
|
|
|
for file in replay_script_seed*.sol; do
|
|
if [ -f "$file" ]; then
|
|
SEED=$(echo $file | sed 's/replay_script_seed\(.*\)\.sol/\1/')
|
|
NEW_NAME="replay_${RUN_ID}_seed${SEED}.sol"
|
|
mv "$file" "$OUTPUT_DIR/$NEW_NAME"
|
|
echo -e " Replay script: ${BLUE}$OUTPUT_DIR/$NEW_NAME${NC}"
|
|
fi
|
|
done
|
|
|
|
for file in scenario_summary_seed*.txt; do
|
|
if [ -f "$file" ]; then
|
|
SEED=$(echo $file | sed 's/scenario_summary_seed\(.*\)\.txt/\1/')
|
|
NEW_NAME="summary_${RUN_ID}_seed${SEED}.txt"
|
|
mv "$file" "$OUTPUT_DIR/$NEW_NAME"
|
|
echo -e " Summary: ${BLUE}$OUTPUT_DIR/$NEW_NAME${NC}"
|
|
|
|
# Display summary preview
|
|
echo ""
|
|
echo -e "${YELLOW}--- Preview of $NEW_NAME ---${NC}"
|
|
head -n 15 "$OUTPUT_DIR/$NEW_NAME"
|
|
echo "..."
|
|
fi
|
|
done
|
|
|
|
# Move position CSVs if they exist
|
|
if ls improved_positions_*.csv 1> /dev/null 2>&1; then
|
|
mv improved_positions_*.csv $OUTPUT_DIR/
|
|
echo -e "\n Position CSVs for visualization moved to: ${BLUE}$OUTPUT_DIR/${NC}"
|
|
fi
|
|
|
|
# Create index file
|
|
cat > $OUTPUT_DIR/index.txt << EOF
|
|
Recorded Fuzzing Results
|
|
========================
|
|
Run ID: $RUN_ID
|
|
Date: $(date)
|
|
Optimizer: $OPTIMIZER
|
|
Total Runs: $RUNS_VALUE
|
|
Profitable Scenarios: $SCENARIO_COUNT
|
|
|
|
Files:
|
|
------
|
|
EOF
|
|
|
|
for file in $OUTPUT_DIR/*; do
|
|
echo "- $(basename $file)" >> $OUTPUT_DIR/index.txt
|
|
done
|
|
|
|
echo ""
|
|
echo -e "${GREEN}=== NEXT STEPS ===${NC}"
|
|
echo "1. Review summaries:"
|
|
echo " cat $OUTPUT_DIR/summary_${RUN_ID}_seed*.txt"
|
|
echo ""
|
|
echo "2. Replay a specific scenario:"
|
|
echo " ./analysis/replay-scenario.sh ${RUN_ID} <seed_number>"
|
|
echo ""
|
|
echo "3. Visualize positions (if CSV tracking enabled):"
|
|
echo " ./analysis/view-scenarios.sh $OUTPUT_DIR"
|
|
echo ""
|
|
echo "4. Share with team:"
|
|
echo -e " ${BOLD}Reference ID: ${RUN_ID}${NC}"
|
|
echo " \"Found exploit ${RUN_ID} with ${SCENARIO_COUNT} profitable scenarios\""
|
|
|
|
else
|
|
echo ""
|
|
echo -e "${YELLOW}=== No Profitable Scenarios Found ===${NC}"
|
|
echo "This could mean the protocol is secure under these conditions."
|
|
echo ""
|
|
echo "Try adjusting parameters:"
|
|
echo " - Increase runs: ./analysis/run-recorded-fuzzing.sh $OPTIMIZER runs=100"
|
|
echo " - Try different optimizer: ./analysis/run-recorded-fuzzing.sh WhaleOptimizer"
|
|
echo " - Use extreme optimizer: ./analysis/run-recorded-fuzzing.sh ExtremeOptimizer"
|
|
echo " - Disable staking: ./analysis/run-recorded-fuzzing.sh $OPTIMIZER runs=$RUNS_VALUE trades=default staking=off"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}Results saved to: $OUTPUT_DIR/${NC}"
|
|
echo -e "Run ID: ${BOLD}${RUN_ID}${NC}"
|
|
|
|
# Launch visualizer if position CSVs were generated
|
|
POSITION_CSV_COUNT=$(ls -1 $OUTPUT_DIR/improved_positions_*.csv 2>/dev/null | wc -l)
|
|
|
|
if [ $POSITION_CSV_COUNT -gt 0 ] && [ $SCENARIO_COUNT -gt 0 ]; then
|
|
echo ""
|
|
echo -e "${GREEN}=== Launching Scenario Visualizer ===${NC}"
|
|
|
|
# Get the first position CSV for visualization
|
|
FIRST_CSV=$(ls -1 $OUTPUT_DIR/improved_positions_*.csv 2>/dev/null | head -1)
|
|
echo "CSV file: $FIRST_CSV"
|
|
|
|
# Create a temporary symlink to the CSV for the viewer in the analysis directory
|
|
TEMP_LINK="analysis/profitable_scenario.csv"
|
|
if [ -f "$TEMP_LINK" ] || [ -L "$TEMP_LINK" ]; then
|
|
rm -f "$TEMP_LINK"
|
|
fi
|
|
# Use absolute path for the symlink
|
|
ln -s "$(realpath $FIRST_CSV)" "$TEMP_LINK"
|
|
echo "Created symlink: $TEMP_LINK -> $FIRST_CSV"
|
|
|
|
# Check if server is already running on common ports
|
|
SERVER_RUNNING=false
|
|
EXISTING_PORT=""
|
|
for PORT in 8000 8001 8002; do
|
|
if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null 2>&1; then
|
|
# Check if it's a python http server in our analysis directory
|
|
if lsof -Pi :$PORT -sTCP:LISTEN 2>/dev/null | grep -q "python.*http.server"; then
|
|
SERVER_RUNNING=true
|
|
EXISTING_PORT=$PORT
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ "$SERVER_RUNNING" = true ]; then
|
|
echo -e "${YELLOW}Server already running on port $EXISTING_PORT${NC}"
|
|
echo -e "${GREEN}Open browser to: http://localhost:$EXISTING_PORT/scenario-visualizer.html${NC}"
|
|
echo ""
|
|
echo -e "${YELLOW}Press Enter to exit (server will keep running)...${NC}"
|
|
read -r
|
|
else
|
|
# Start the viewer in background
|
|
./analysis/view-scenarios.sh &
|
|
VIEWER_PID=$!
|
|
|
|
# Give the server time to start
|
|
sleep 2
|
|
|
|
echo ""
|
|
echo -e "${GREEN}Browser should open to: http://localhost:8000/scenario-visualizer.html${NC}"
|
|
echo ""
|
|
echo -e "${YELLOW}Press Enter to stop the viewer and exit...${NC}"
|
|
read -r
|
|
|
|
# Kill the viewer process
|
|
if [ -n "$VIEWER_PID" ]; then
|
|
pkill -P $VIEWER_PID 2>/dev/null || true
|
|
kill $VIEWER_PID 2>/dev/null || true
|
|
fi
|
|
|
|
echo -e "${GREEN}Viewer stopped.${NC}"
|
|
fi
|
|
|
|
# Clean up the symlink
|
|
rm -f "$TEMP_LINK"
|
|
fi |