From e021aff97850d80ab68187327df3e2bdcc6cb4f0 Mon Sep 17 00:00:00 2001 From: johba Date: Sat, 9 Aug 2025 19:17:46 +0200 Subject: [PATCH] better scripts --- onchain/analysis/FuzzingAnalysis.s.sol | 112 +++++++++--- onchain/analysis/run-fuzzing.sh | 202 +++++++++++++++++++-- onchain/analysis/test-auto-launch.sh | 3 + onchain/analysis/view-scenarios.sh | 15 +- onchain/test/mocks/BullMarketOptimizer.sol | 10 +- 5 files changed, 290 insertions(+), 52 deletions(-) create mode 100755 onchain/analysis/test-auto-launch.sh diff --git a/onchain/analysis/FuzzingAnalysis.s.sol b/onchain/analysis/FuzzingAnalysis.s.sol index f11e1a9..ec4b80f 100644 --- a/onchain/analysis/FuzzingAnalysis.s.sol +++ b/onchain/analysis/FuzzingAnalysis.s.sol @@ -49,6 +49,7 @@ contract FuzzingAnalysis is Test, CSVManager { bool public trackPositions; string public optimizerClass; uint256 public tradesPerRun; + uint256 public seedOffset; // Optimizers BullMarketOptimizer bullOptimizer; @@ -80,7 +81,7 @@ contract FuzzingAnalysis is Test, CSVManager { console.log(string.concat("=== FUZZING with ", optimizerClass, " ===")); - for (uint256 seed = 0; seed < fuzzingRuns; seed++) { + for (uint256 seed = seedOffset; seed < seedOffset + fuzzingRuns; seed++) { if (seed % 10 == 0 && seed > 0) { console.log(string.concat("Progress: ", vm.toString(seed), "/", vm.toString(fuzzingRuns))); } @@ -107,15 +108,18 @@ contract FuzzingAnalysis is Test, CSVManager { scenariosAnalyzed++; - // Check profitability - if (finalBalance > initialBalance) { + // Calculate profit/loss + bool isProfitable = finalBalance > initialBalance; + uint256 profitOrLoss; + uint256 profitOrLossPercentage; + + if (isProfitable) { + profitOrLoss = finalBalance - initialBalance; + profitOrLossPercentage = (profitOrLoss * 100) / initialBalance; profitableScenarios++; marketProfitable++; - uint256 profit = finalBalance - initialBalance; - uint256 profitPercentage = (profit * 100) / initialBalance; - - console.log(string.concat("PROFITABLE! Seed: ", vm.toString(seed), " Profit: ", vm.toString(profitPercentage), "%")); + console.log(string.concat("PROFITABLE! Seed: ", vm.toString(seed), " Profit: ", vm.toString(profitOrLossPercentage), "%")); // Add to CSV profitableCSV = string.concat( @@ -124,11 +128,17 @@ contract FuzzingAnalysis is Test, CSVManager { vm.toString(seed), ",", vm.toString(initialBalance), ",", vm.toString(finalBalance), ",", - vm.toString(profit), ",", - vm.toString(profitPercentage), "\n" + vm.toString(profitOrLoss), ",", + vm.toString(profitOrLossPercentage), "\n" ); profitableCount++; + } else { + profitOrLoss = initialBalance - finalBalance; + profitOrLossPercentage = (profitOrLoss * 100) / initialBalance; } + + // Always log result for cumulative tracking + console.log(string.concat("RESULT|SEED:", vm.toString(seed), "|INITIAL:", vm.toString(initialBalance), "|FINAL:", vm.toString(finalBalance), "|PNL:", isProfitable ? "+" : "-", vm.toString(profitOrLoss))); } console.log(string.concat("\nResults for ", optimizerClass, ":")); @@ -138,6 +148,7 @@ contract FuzzingAnalysis is Test, CSVManager { console.log("=== ANALYSIS COMPLETE ==="); console.log(string.concat("Total scenarios analyzed: ", vm.toString(scenariosAnalyzed))); console.log(string.concat("Total profitable scenarios: ", vm.toString(profitableScenarios))); + console.log(string.concat("Profitable rate: ", vm.toString((profitableScenarios * 100) / scenariosAnalyzed), "%")); // Write profitable scenarios CSV if any found if (profitableCount > 0) { @@ -157,6 +168,7 @@ contract FuzzingAnalysis is Test, CSVManager { trackPositions = vm.envOr("TRACK_POSITIONS", false); optimizerClass = vm.envOr("OPTIMIZER_CLASS", string("BullMarketOptimizer")); tradesPerRun = vm.envOr("TRADES_PER_RUN", uint256(20)); + seedOffset = vm.envOr("SEED_OFFSET", uint256(0)); } function _runFuzzedScenario(string memory scenarioName, uint256 seed) internal returns (uint256) { @@ -189,14 +201,24 @@ contract FuzzingAnalysis is Test, CSVManager { if (wethBal > 0) { uint256 buyPercent = 1 + (rand % 1000); // 0.1% to 100% uint256 buyAmount = (wethBal * buyPercent) / 1000; - if (buyAmount > 0) _executeBuy(buyAmount); + if (buyAmount > 0) { + _executeBuy(buyAmount); + if (trackPositions) { + _recordPositionData(string.concat("Buy_", vm.toString(i))); + } + } } } else if (action < 80) { // 40% chance sell uint256 harbBal = harberg.balanceOf(account); if (harbBal > 0) { uint256 sellPercent = 1 + (rand % 1000); // 0.1% to 100% uint256 sellAmount = (harbBal * sellPercent) / 1000; - if (sellAmount > 0) _executeSell(sellAmount); + if (sellAmount > 0) { + _executeSell(sellAmount); + if (trackPositions) { + _recordPositionData(string.concat("Sell_", vm.toString(i))); + } + } } } else if (action < 95) { // 15% chance recenter uint256 waitTime = 1 minutes + (rand % 10 hours); @@ -218,7 +240,12 @@ contract FuzzingAnalysis is Test, CSVManager { // Sell remaining HARB uint256 finalHarb = harberg.balanceOf(account); - if (finalHarb > 0) _executeSell(finalHarb); + if (finalHarb > 0) { + _executeSell(finalHarb); + if (trackPositions) { + _recordPositionData("Final_Sell"); + } + } // Final recenters for (uint256 j = 0; j < 1 + (rand % 3); j++) { @@ -229,10 +256,12 @@ contract FuzzingAnalysis is Test, CSVManager { // Write position tracking CSV if enabled if (trackPositions) { + _recordPositionData("Final"); string memory positionFilename = string.concat( "positions_", scenarioName, "_", vm.toString(seed), ".csv" ); writeCSVToFile(positionFilename); + console.log(string.concat("Position tracking CSV written to: ", positionFilename)); } return weth.balanceOf(account); @@ -308,21 +337,52 @@ contract FuzzingAnalysis is Test, CSVManager { (uint128 anchorLiq, int24 anchorLower, int24 anchorUpper) = lm.positions(ThreePositionStrategy.Stage.ANCHOR); (uint128 discoveryLiq, int24 discoveryLower, int24 discoveryUpper) = lm.positions(ThreePositionStrategy.Stage.DISCOVERY); - // Create position data row + // Calculate ETH and HARB amounts in each position + // For visualization purposes, we'll estimate based on liquidity distribution + uint256 totalLiq = uint256(floorLiq) + uint256(anchorLiq) + uint256(discoveryLiq); + uint256 totalEth = weth.balanceOf(address(lm)); + uint256 totalHarb = harberg.balanceOf(address(lm)); + + uint256 floorEth = 0; + uint256 floorHarb = 0; + uint256 anchorEth = 0; + uint256 anchorHarb = 0; + uint256 discoveryEth = 0; + uint256 discoveryHarb = 0; + + if (totalLiq > 0) { + // Rough approximation based on whether current tick is in range + if (currentTick >= floorLower && currentTick < floorUpper && floorLiq > 0) { + floorEth = (totalEth * uint256(floorLiq)) / totalLiq / 2; + floorHarb = (totalHarb * uint256(floorLiq)) / totalLiq / 2; + } + if (currentTick >= anchorLower && currentTick < anchorUpper && anchorLiq > 0) { + anchorEth = (totalEth * uint256(anchorLiq)) / totalLiq / 2; + anchorHarb = (totalHarb * uint256(anchorLiq)) / totalLiq / 2; + } + if (currentTick >= discoveryLower && currentTick < discoveryUpper && discoveryLiq > 0) { + discoveryEth = (totalEth * uint256(discoveryLiq)) / totalLiq / 2; + discoveryHarb = (totalHarb * uint256(discoveryLiq)) / totalLiq / 2; + } + } + + // Create position data row matching the expected CSV format string memory row = string.concat( - label, ",", - vm.toString(currentTick), ",", - vm.toString(floorLiq), ",", - vm.toString(floorLower), ",", - vm.toString(floorUpper), ",", - vm.toString(anchorLiq), ",", - vm.toString(anchorLower), ",", - vm.toString(anchorUpper), ",", - vm.toString(discoveryLiq), ",", - vm.toString(discoveryLower), ",", - vm.toString(discoveryUpper), ",", - vm.toString(weth.balanceOf(address(lm))), ",", - vm.toString(harberg.balanceOf(address(lm))) + label, ", ", + vm.toString(currentTick), ", ", + vm.toString(floorLower), ", ", + vm.toString(floorUpper), ", ", + vm.toString(floorEth), ", ", + vm.toString(floorHarb), ", ", + vm.toString(anchorLower), ", ", + vm.toString(anchorUpper), ", ", + vm.toString(anchorEth), ", ", + vm.toString(anchorHarb), ", ", + vm.toString(discoveryLower), ", ", + vm.toString(discoveryUpper), ", ", + vm.toString(discoveryEth), ", ", + vm.toString(discoveryHarb), ", ", + token0isWeth ? "true" : "false" ); appendCSVRow(row); } diff --git a/onchain/analysis/run-fuzzing.sh b/onchain/analysis/run-fuzzing.sh index e614756..63e4300 100755 --- a/onchain/analysis/run-fuzzing.sh +++ b/onchain/analysis/run-fuzzing.sh @@ -3,25 +3,43 @@ # Change to the analysis directory (where this script is located) cd "$(dirname "$0")" +# Function to cleanup on exit +cleanup() { + if [ -n "$VIEWER_PID" ]; then + echo -e "\n${YELLOW}Stopping viewer...${NC}" + # Kill the entire process group + pkill -TERM -g $VIEWER_PID 2>/dev/null || true + sleep 1 + pkill -KILL -g $VIEWER_PID 2>/dev/null || true + fi + rm -f profitable_scenario.csv 2>/dev/null || true +} + +# Set trap to cleanup on script exit +trap cleanup EXIT + # Default values OPTIMIZER_CLASS="" TOTAL_RUNS=50 TRADES_PER_RUN=20 +DEBUG_CSV=false # Function to show usage show_usage() { - echo "Usage: $0 [runs=N] [trades=N]" + echo "Usage: $0 [runs=N] [trades=N] [debugCSV]" echo "" echo "Parameters:" echo " optimizer_class Required. The optimizer class to use" echo " runs=N Optional. Number of fuzzing runs (default: 50)" echo " trades=N Optional. Trades per run (default: 20, actual will be ±5)" + echo " debugCSV Optional. Enable debug mode with position tracking CSV (forces runs=1)" echo "" echo "Examples:" echo " $0 BullMarketOptimizer" echo " $0 WhaleOptimizer runs=100" echo " $0 BearMarketOptimizer runs=10 trades=50" echo " $0 NeutralMarketOptimizer trades=30 runs=25" + echo " $0 BullMarketOptimizer debugCSV" echo "" echo "Available optimizers:" echo " - BullMarketOptimizer" @@ -60,6 +78,10 @@ for arg in "$@"; do exit 1 fi ;; + debugCSV) + DEBUG_CSV=true + TOTAL_RUNS=1 + ;; *) echo "Error: Unknown parameter '$arg'" show_usage @@ -81,19 +103,30 @@ echo -e "${GREEN}=== Fuzzing Campaign ===${NC}" echo "Optimizer: $OPTIMIZER_CLASS" echo "Total runs: $TOTAL_RUNS" echo "Trades per run: $TRADES_PER_RUN (±5)" +if [ "$DEBUG_CSV" = true ]; then + echo -e "${YELLOW}Debug mode: ENABLED (position tracking CSV will be generated)${NC}" +fi echo "Output directory: $OUTPUT_DIR" echo "" # Validate that the optimizer class exists by doing a dry run echo "Validating optimizer class..." -OPTIMIZER_CLASS="$OPTIMIZER_CLASS" FUZZING_RUNS=0 forge script FuzzingAnalysis.s.sol --ffi --via-ir > /tmp/optimizer_check.log 2>&1 +OPTIMIZER_CLASS="$OPTIMIZER_CLASS" FUZZING_RUNS=1 TRADES_PER_RUN=1 forge script FuzzingAnalysis.s.sol --ffi --via-ir --gas-limit 200000000 > /tmp/optimizer_check.log 2>&1 if [ $? -ne 0 ]; then - echo -e "${RED}Error: Invalid optimizer class '${OPTIMIZER_CLASS}'${NC}" - echo -e "${RED}Check the error:${NC}" - grep -E "(Unknown optimizer|revert)" /tmp/optimizer_check.log - echo "" - show_usage - exit 1 + # Check specifically for unknown optimizer error + if grep -q "Unknown optimizer class" /tmp/optimizer_check.log; then + echo -e "${RED}Error: Invalid optimizer class '${OPTIMIZER_CLASS}'${NC}" + echo -e "${RED}Check the error:${NC}" + grep "Unknown optimizer" /tmp/optimizer_check.log + echo "" + show_usage + exit 1 + else + # Other errors are ok during validation, we just want to check the optimizer exists + echo "Optimizer validation passed (non-optimizer errors ignored)" + fi +else + echo "Optimizer validation passed" fi # Create output directory @@ -105,6 +138,9 @@ echo "Scenario,Seed,Initial Balance,Final Balance,Profit,Profit %" > "$MERGED_CS # Track statistics TOTAL_PROFITABLE=0 FAILED_RUNS=0 +CUMULATIVE_PNL=0 +CSV_GENERATED=false +LATEST_CSV="" # Save configuration CONFIG_FILE="$OUTPUT_DIR/config.txt" @@ -122,28 +158,90 @@ for i in $(seq 1 $TOTAL_RUNS); do echo -e "${YELLOW}Running fuzzing iteration $i/$TOTAL_RUNS...${NC}" # Run single fuzzing iteration with specified optimizer and trades - OPTIMIZER_CLASS="$OPTIMIZER_CLASS" TRADES_PER_RUN="$TRADES_PER_RUN" FUZZING_RUNS=1 forge script FuzzingAnalysis.s.sol --ffi --via-ir --gas-limit 200000000 > "$OUTPUT_DIR/run_$i.log" 2>&1 + # Use iteration number as seed offset to ensure different scenarios + # Enable position tracking if debugCSV is set + if [ "$DEBUG_CSV" = true ]; then + TRACK_POSITIONS=true SEED_OFFSET=$((i - 1)) OPTIMIZER_CLASS="$OPTIMIZER_CLASS" TRADES_PER_RUN="$TRADES_PER_RUN" FUZZING_RUNS=1 forge script FuzzingAnalysis.s.sol --ffi --via-ir --gas-limit 200000000 > "$OUTPUT_DIR/run_$i.log" 2>&1 + else + SEED_OFFSET=$((i - 1)) OPTIMIZER_CLASS="$OPTIMIZER_CLASS" TRADES_PER_RUN="$TRADES_PER_RUN" FUZZING_RUNS=1 forge script FuzzingAnalysis.s.sol --ffi --via-ir --gas-limit 200000000 > "$OUTPUT_DIR/run_$i.log" 2>&1 + fi if [ $? -eq 0 ]; then echo -e "${GREEN}✓ Run $i completed${NC}" - # Check if profitable scenarios were found - if grep -q "PROFITABLE!" "$OUTPUT_DIR/run_$i.log"; then - echo -e "${GREEN} Found profitable scenario!${NC}" - ((TOTAL_PROFITABLE++)) + # Extract P&L from RESULT line (may have leading spaces from forge output) + RESULT_LINE=$(grep "RESULT|" "$OUTPUT_DIR/run_$i.log") + if [ -n "$RESULT_LINE" ]; then + # Parse the RESULT line to extract P&L + PNL_VALUE=$(echo "$RESULT_LINE" | awk -F'|' '{print $5}' | sed 's/PNL://' | tr -d ' ') - # Extract profit percentage - PROFIT_PCT=$(grep "PROFITABLE!" "$OUTPUT_DIR/run_$i.log" | grep -oE "Profit: [0-9]+%" | grep -oE "[0-9]+") - echo -e "${GREEN} Profit: ${PROFIT_PCT}%${NC}" + # Debug: show values before calculation + # echo "DEBUG: Current cumulative: $CUMULATIVE_PNL, New P&L: $PNL_VALUE" - # Extract CSV file path if generated + # Add to cumulative P&L using awk (handles large numbers better than bash arithmetic) + CUMULATIVE_PNL=$(LC_NUMERIC=C awk -v cum="$CUMULATIVE_PNL" -v pnl="$PNL_VALUE" 'BEGIN {printf "%.0f", cum + pnl}') + + # Format cumulative P&L for display (convert from wei to ETH) + CUMULATIVE_ETH=$(LC_NUMERIC=C awk -v cum="$CUMULATIVE_PNL" 'BEGIN {printf "%.6f", cum / 1000000000000000000}') + + # Check if profitable + if [[ "$PNL_VALUE" == +* ]]; then + echo -e "${GREEN} Found profitable scenario!${NC}" + ((TOTAL_PROFITABLE++)) + + # Extract profit percentage + PROFIT_PCT=$(grep "PROFITABLE!" "$OUTPUT_DIR/run_$i.log" | grep -oE "Profit: [0-9]+%" | grep -oE "[0-9]+") + echo -e "${GREEN} Profit: ${PROFIT_PCT}%${NC}" + else + echo -e "${YELLOW} Loss scenario${NC}" + fi + + # Display cumulative P&L + if awk -v cum="$CUMULATIVE_PNL" 'BEGIN {exit !(cum >= 0)}'; then + echo -e "${GREEN} Cumulative P&L: +${CUMULATIVE_ETH} ETH${NC}" + else + echo -e "${RED} Cumulative P&L: ${CUMULATIVE_ETH} ETH${NC}" + fi + + # Extract CSV file path if generated (for profitable scenarios) CSV_FILE=$(grep "Profitable scenarios written to:" "$OUTPUT_DIR/run_$i.log" | awk '{print $NF}') if [ -n "$CSV_FILE" ] && [ -f "$CSV_FILE" ]; then # Append data rows (skip header) to merged CSV tail -n +2 "$CSV_FILE" >> "$MERGED_CSV" # Move individual CSV to output directory mv "$CSV_FILE" "$OUTPUT_DIR/" + CSV_GENERATED=true + LATEST_CSV="$OUTPUT_DIR/$(basename "$CSV_FILE")" fi + + # In debug mode, also look for position tracking CSV + if [ "$DEBUG_CSV" = true ]; then + # Look for position CSV mentioned in the log + POSITION_CSV=$(grep "Position tracking CSV written to:" "$OUTPUT_DIR/run_$i.log" | awk -F': ' '{print $2}') + if [ -n "$POSITION_CSV" ]; then + # The CSV is generated in the parent directory (onchain), so check there + PARENT_CSV="../$POSITION_CSV" + if [ -f "$PARENT_CSV" ]; then + echo -e "${GREEN} Position tracking CSV generated: $POSITION_CSV${NC}" + # Move to output directory with a more descriptive name + FINAL_CSV_NAME="debug_positions_${OPTIMIZER_CLASS}_seed${SEED_OFFSET}.csv" + mv "$PARENT_CSV" "$OUTPUT_DIR/$FINAL_CSV_NAME" + echo -e "${GREEN} Moved to: $OUTPUT_DIR/$FINAL_CSV_NAME${NC}" + CSV_GENERATED=true + LATEST_CSV="$OUTPUT_DIR/$FINAL_CSV_NAME" + elif [ -f "$POSITION_CSV" ]; then + # Fallback if it's in the current directory + echo -e "${GREEN} Position tracking CSV generated: $POSITION_CSV${NC}" + FINAL_CSV_NAME="debug_positions_${OPTIMIZER_CLASS}_seed${SEED_OFFSET}.csv" + mv "$POSITION_CSV" "$OUTPUT_DIR/$FINAL_CSV_NAME" + echo -e "${GREEN} Moved to: $OUTPUT_DIR/$FINAL_CSV_NAME${NC}" + CSV_GENERATED=true + LATEST_CSV="$OUTPUT_DIR/$FINAL_CSV_NAME" + fi + fi + fi + else + echo -e "${YELLOW} Warning: No RESULT line found in output${NC}" fi else echo -e "${RED}✗ Run $i failed${NC}" @@ -168,6 +266,15 @@ echo "Trades per run: $TRADES_PER_RUN (±5)" echo "Successful runs: $((TOTAL_RUNS - FAILED_RUNS))" echo "Failed runs: $FAILED_RUNS" echo "Total profitable scenarios: $TOTAL_PROFITABLE" + +# Display final cumulative P&L +FINAL_CUMULATIVE_ETH=$(LC_NUMERIC=C awk -v cum="$CUMULATIVE_PNL" 'BEGIN {printf "%.6f", cum / 1000000000000000000}') +if awk -v cum="$CUMULATIVE_PNL" 'BEGIN {exit !(cum >= 0)}'; then + echo -e "${GREEN}Final Cumulative P&L: +${FINAL_CUMULATIVE_ETH} ETH${NC}" +else + echo -e "${RED}Final Cumulative P&L: ${FINAL_CUMULATIVE_ETH} ETH${NC}" +fi + echo "" echo "Results saved in: $OUTPUT_DIR" echo "Merged CSV: $MERGED_CSV" @@ -188,6 +295,11 @@ SUMMARY="$OUTPUT_DIR/summary.txt" echo "Failed runs: $FAILED_RUNS" echo "Total profitable scenarios: $TOTAL_PROFITABLE / $((TOTAL_RUNS - FAILED_RUNS))" echo "Success rate: $(awk "BEGIN {if ($TOTAL_RUNS - $FAILED_RUNS > 0) printf \"%.2f\", $TOTAL_PROFITABLE/($TOTAL_RUNS-$FAILED_RUNS)*100; else print \"0.00\"}")%" + echo "" + echo "Profit/Loss Analysis:" + echo "--------------------" + echo "Cumulative P&L: $FINAL_CUMULATIVE_ETH ETH" + echo "Average P&L per run: $(awk -v cumeth="$FINAL_CUMULATIVE_ETH" -v total="$TOTAL_RUNS" -v failed="$FAILED_RUNS" 'BEGIN {if (total - failed > 0) printf "%.6f ETH", cumeth/(total-failed); else print "0.000000 ETH"}')" } > "$SUMMARY" echo "" @@ -198,4 +310,60 @@ if [ $TOTAL_PROFITABLE -gt 0 ]; then echo "" echo -e "${GREEN}Sample profitable scenarios:${NC}" head -5 "$MERGED_CSV" +fi + +# If debug mode was used, mention the position tracking CSV +if [ "$DEBUG_CSV" = true ]; then + echo "" + echo -e "${GREEN}Debug position tracking CSV generated!${NC}" + echo "View it with: ./view-scenarios.sh" + echo "Then navigate to the output directory and select the debug CSV file" +fi + +# If any CSV was generated, launch the viewer +if [ "$CSV_GENERATED" = true ] && [ -n "$LATEST_CSV" ]; then + echo "" + echo -e "${GREEN}=== Launching Scenario Visualizer ===${NC}" + echo "CSV file: $LATEST_CSV" + + # Create a temporary symlink to the CSV for the viewer + TEMP_LINK="profitable_scenario.csv" + if [ -f "$TEMP_LINK" ] || [ -L "$TEMP_LINK" ]; then + rm -f "$TEMP_LINK" + fi + # Use absolute path for the symlink + ln -s "$(pwd)/$LATEST_CSV" "$TEMP_LINK" + + # Start the viewer in background in its own process group + setsid ./view-scenarios.sh & + VIEWER_PID=$! + + # Give the server time to start and browser to open + sleep 2 + + # Show the URL + echo "" + echo -e "${GREEN}Browser should open to: http://localhost:8000/scenario-visualizer.html${NC}" + echo "(If port 8000 was busy, check the port number mentioned above)" + echo "If browser didn't open, manually navigate to that URL" + + # Wait for user input + echo "" + echo -e "${YELLOW}Press Enter to stop the viewer and exit...${NC}" + read -r + + # Kill the viewer process and its children + if [ -n "$VIEWER_PID" ]; then + # Kill the entire process group (includes python server) + pkill -TERM -g $VIEWER_PID 2>/dev/null || true + # Give it a moment to clean up + sleep 1 + # Force kill if still running + pkill -KILL -g $VIEWER_PID 2>/dev/null || true + fi + + # Clean up the symlink + rm -f "$TEMP_LINK" + + echo -e "${GREEN}Viewer stopped.${NC}" fi \ No newline at end of file diff --git a/onchain/analysis/test-auto-launch.sh b/onchain/analysis/test-auto-launch.sh new file mode 100755 index 0000000..c0cde05 --- /dev/null +++ b/onchain/analysis/test-auto-launch.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd "$(dirname "$0")" +echo -e "\n" | timeout 15 ./run-fuzzing.sh BullMarketOptimizer debugCSV trades=3 \ No newline at end of file diff --git a/onchain/analysis/view-scenarios.sh b/onchain/analysis/view-scenarios.sh index 6c217d2..9f869e4 100755 --- a/onchain/analysis/view-scenarios.sh +++ b/onchain/analysis/view-scenarios.sh @@ -40,17 +40,24 @@ start_server() { echo "Press Ctrl+C to stop the server" echo "==================================" + # Start server in background first + $python_cmd -m http.server $port & + SERVER_PID=$! + + # Give server a moment to start + sleep 1 + # Try to open browser (works on most systems) if command -v xdg-open &> /dev/null; then - xdg-open "http://localhost:$port/scenario-visualizer.html" & + xdg-open "http://localhost:$port/scenario-visualizer.html" 2>/dev/null & elif command -v open &> /dev/null; then - open "http://localhost:$port/scenario-visualizer.html" & + open "http://localhost:$port/scenario-visualizer.html" 2>/dev/null & else echo "🔗 Manual: Open http://localhost:$port/scenario-visualizer.html in your browser" fi - # Start server (this will block until Ctrl+C) - $python_cmd -m http.server $port + # Wait for the server process + wait $SERVER_PID } # Main execution diff --git a/onchain/test/mocks/BullMarketOptimizer.sol b/onchain/test/mocks/BullMarketOptimizer.sol index 43429cf..e686931 100644 --- a/onchain/test/mocks/BullMarketOptimizer.sol +++ b/onchain/test/mocks/BullMarketOptimizer.sol @@ -25,13 +25,13 @@ contract BullMarketOptimizer { pure returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) { - capitalInefficiency = 1e17; // 10% - very aggressive - anchorShare = 95e16; // 95% - massive anchor position - anchorWidth = 80; // moderate width (was 10) - discoveryDepth = 5e16; // 5% - minimal discovery + capitalInefficiency = 0; // 10% - very aggressive + anchorShare = 1e18; // 95% - massive anchor position + anchorWidth = 50; // moderate width (was 10) + discoveryDepth = 1e18; // 5% - minimal discovery } function getDescription() external pure returns (string memory) { return "Bull Market (Whale Attack Parameters)"; } -} \ No newline at end of file +}