consolidated scripts

This commit is contained in:
johba 2025-08-19 17:35:43 +02:00
parent 10702f5aa3
commit 74e09bb38b
5 changed files with 383 additions and 377 deletions

View file

@ -47,9 +47,15 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager {
uint256 public totalSnatchesAttempted;
uint256 public totalSnatchesSucceeded;
// Staking tracking
mapping(address => uint256[]) public activePositions;
uint256[] public allPositionIds; // Track all positions for snatching
// OPTIMIZATION: Circular buffer for position tracking (max 50 positions)
uint256 constant MAX_TRACKED_POSITIONS = 50;
uint256[MAX_TRACKED_POSITIONS] public trackedPositions;
uint256 public positionWriteIndex;
uint256 public totalPositionsCreated;
mapping(uint256 => address) public positionOwners;
// Counter to limit CSV recording and prevent memory issues
uint256 private csvRecordCount;
// Configuration
uint256 public fuzzingRuns;
@ -78,9 +84,10 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager {
// Get optimizer
address optimizerAddress = _getOptimizerByClass(optimizerClass);
// Track profitable scenarios
// Track profitable scenarios (limit string concatenation to prevent memory issues)
string memory profitableCSV = "Scenario,Seed,Initial Balance,Final Balance,Profit,Profit %,Discovery Reached\n";
uint256 profitableCount;
uint256 maxProfitableRecords = 20; // Limit to prevent memory issues
for (uint256 seed = 0; seed < fuzzingRuns; seed++) {
if (seed % 10 == 0 && seed > 0) {
@ -118,9 +125,13 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager {
// Initialize position tracking for each seed
if (trackPositions) {
// Initialize CSV header for each seed (after clearCSV from previous run)
// Reset tracking for new scenario
_resetPositionTracking();
clearCSV(); // Clear any previous data
csvRecordCount = 0; // Reset counter
initializePositionsCSV();
_recordPositionData("Initial");
csvRecordCount = 1; // Count the initial record
}
// Run improved trading scenario
@ -141,16 +152,19 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager {
console.log(string.concat(" Profit: ", vm.toString(profit / 1e15), " finney (", vm.toString(profitPct), "%)"));
console.log(string.concat(" Discovery reached: ", reachedDiscovery ? "YES" : "NO"));
profitableCSV = string.concat(
profitableCSV,
optimizerClass, ",",
vm.toString(seed), ",",
vm.toString(initialBalance), ",",
vm.toString(finalBalance), ",",
vm.toString(profit), ",",
vm.toString(profitPct), ",",
reachedDiscovery ? "true" : "false", "\n"
);
// Only record limited profitable scenarios to prevent memory issues
if (profitableCount < maxProfitableRecords) {
profitableCSV = string.concat(
profitableCSV,
optimizerClass, ",",
vm.toString(seed), ",",
vm.toString(initialBalance), ",",
vm.toString(finalBalance), ",",
vm.toString(profit), ",",
vm.toString(profitPct), ",",
reachedDiscovery ? "true" : "false", "\n"
);
}
profitableCount++;
}
@ -286,9 +300,9 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager {
}
}
// Only record every 5th trade to avoid memory issues with large trade counts
if (trackPositions && i % 5 == 0) {
_recordPositionData("Trade");
// Record position data for visualization (always record all trades)
if (trackPositions) {
_recordPositionDataSafe(string.concat("T", vm.toString(i)));
}
}
}
@ -331,16 +345,26 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager {
optimizerClass = vm.envOr("OPTIMIZER_CLASS", string("BullMarketOptimizer"));
}
function _recordPositionData(string memory label) internal {
// Split into separate function calls to avoid stack too deep
_recordPositionDataInternal(label);
// Safe wrapper that prevents gas and memory issues
function _recordPositionDataSafe(string memory label) internal {
// Only record if we have enough gas remaining
if (gasleft() < 1_000_000) {
return; // Skip recording if low on gas
}
// Skip if CSV is getting extremely large (increased limit for all trades)
if (bytes(csv).length > 100000) {
return; // Skip to avoid memory issues
}
csvRecordCount++;
_recordPositionData(label);
}
function _recordPositionDataInternal(string memory label) private {
// Disable position tracking if it causes memory issues
if (bytes(csv).length > 50000) {
// CSV is getting too large, skip recording
return;
function _recordPositionData(string memory label) internal {
// Absolutely prevent recording if buffer is too large
if (bytes(csv).length > 100000) {
return; // Stop recording to prevent memory issues
}
(,int24 currentTick,,,,,) = pool.slot0();
@ -350,221 +374,205 @@ contract ImprovedFuzzingAnalysis 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);
// Use simpler row building to avoid memory issues
string memory row = label;
row = string.concat(row, ",", vm.toString(currentTick));
row = string.concat(row, ",", vm.toString(floorLower));
row = string.concat(row, ",", vm.toString(floorUpper));
row = string.concat(row, ",", vm.toString(floorLiq));
row = string.concat(row, ",", vm.toString(anchorLower));
row = string.concat(row, ",", vm.toString(anchorUpper));
row = string.concat(row, ",", vm.toString(anchorLiq));
row = string.concat(row, ",", vm.toString(discoveryLower));
row = string.concat(row, ",", vm.toString(discoveryUpper));
row = string.concat(row, ",", vm.toString(discoveryLiq));
row = string.concat(row, ",", token0isWeth ? "true" : "false");
row = string.concat(row, ",", vm.toString(stake.getPercentageStaked()));
row = string.concat(row, ",", vm.toString(stake.getAverageTaxRate()));
// Skip staking data for trades to save memory (only get for key events)
uint256 pctStaked = 0;
uint256 avgTax = 0;
if (enableStaking && bytes(label).length > 1 && bytes(label)[0] != 0x54) { // Not a "T" trade label
try stake.getPercentageStaked{gas: 30000}() returns (uint256 pct) {
pctStaked = pct;
} catch {}
try stake.getAverageTaxRate{gas: 30000}() returns (uint256 tax) {
avgTax = tax;
} catch {}
}
// Build CSV row with minimal concatenations
string memory row = string.concat(
label, ",",
vm.toString(currentTick), ",",
vm.toString(floorLower), ","
);
row = string.concat(
row,
vm.toString(floorUpper), ",",
vm.toString(floorLiq), ","
);
row = string.concat(
row,
vm.toString(anchorLower), ",",
vm.toString(anchorUpper), ","
);
row = string.concat(
row,
vm.toString(anchorLiq), ",",
vm.toString(discoveryLower), ","
);
row = string.concat(
row,
vm.toString(discoveryUpper), ",",
vm.toString(discoveryLiq), ","
);
row = string.concat(
row,
token0isWeth ? "1" : "0", ",",
vm.toString(pctStaked), ",",
vm.toString(avgTax)
);
appendCSVRow(row);
}
function _executeStakingAction(uint256 rand) internal {
uint256 action = rand % 100;
// 70% chance to stake, 5% chance to exit (to fill pool faster)
if (action < 70) {
_executeStake(rand);
} else if (action < 75) {
_executeExitPosition(rand);
}
}
function _executeStakeWithAmount(address staker, uint256 amount, uint32 taxRate) internal {
// Direct stake with specific amount and tax rate
_doStake(staker, amount, taxRate);
}
function _executeStake(uint256 rand) internal {
address staker = rand % 2 == 0 ? account : whale;
uint256 harbBalance = harberg.balanceOf(staker);
if (harbBalance > harberg.minStake()) {
// Stake between 30% and 80% of balance (increased from 10-50%)
uint256 amount = harbBalance * (30 + (rand % 50)) / 100;
if (amount < harberg.minStake()) {
amount = harberg.minStake();
}
// Random tax rate (index 0-29)
uint32 taxRate = uint32(rand % 30);
vm.prank(staker);
harberg.approve(address(stake), amount);
_doStake(staker, amount, taxRate);
totalStakesAttempted++;
vm.prank(staker);
try stake.snatch{gas: 10_000_000}(amount, staker, taxRate, new uint256[](0)) returns (uint256 positionId) {
totalStakesSucceeded++;
_addTrackedPosition(positionId, staker);
console.log(" STAKED:", amount / 1e18, "KRAIKEN");
if (trackPositions) {
_recordPositionDataSafe("Stake");
}
} catch {
// If regular stake fails, try snatching with higher tax rate
if (totalPositionsCreated > 0) {
_tryOptimizedSnatch(staker, amount);
}
}
}
}
function _doStake(address staker, uint256 amount, uint32 taxRate) internal {
vm.startPrank(staker);
// Check current pool capacity before attempting stake
uint256 currentPercentStaked = stake.getPercentageStaked();
// First try to stake without snatching
totalStakesAttempted++;
try stake.snatch(amount, staker, taxRate, new uint256[](0)) returns (uint256 positionId) {
totalStakesSucceeded++;
activePositions[staker].push(positionId);
allPositionIds.push(positionId);
console.log(" STAKED:", amount / 1e18);
console.log(" Tax rate index:", taxRate);
console.log(" Pool now at:", currentPercentStaked / 1e16);
function _tryOptimizedSnatch(address staker, uint256 amount) internal {
uint32 maxTaxRate = 29;
// Find up to 3 snatchable positions quickly
uint256[] memory toSnatch = _findSnatchableQuick(maxTaxRate, amount);
if (toSnatch.length > 0) {
totalSnatchesAttempted++;
vm.prank(staker);
try stake.snatch{gas: 15_000_000}(amount, staker, maxTaxRate, toSnatch) returns (uint256 positionId) {
totalSnatchesSucceeded++;
_addTrackedPosition(positionId, staker);
console.log(" SNATCHED", toSnatch.length, "positions");
if (trackPositions) {
_recordPositionData("Stake");
_recordPositionDataSafe("Snatch");
}
} catch Error(string memory reason) {
// If staking failed (likely pool is full), try snatching with max tax rate
console.log(" Stake failed:", reason);
console.log(" Pool at:", currentPercentStaked / 1e16, "percent - attempting snatch...");
// Use max tax rate (29) for snatching
uint32 maxTaxRate = 29;
// Find positions to snatch (those with lower tax rates)
uint256[] memory positionsToSnatch = _findSnatchablePositions(maxTaxRate, amount);
if (positionsToSnatch.length > 0) {
totalSnatchesAttempted++;
try stake.snatch(amount, staker, maxTaxRate, positionsToSnatch) returns (uint256 positionId) {
totalSnatchesSucceeded++;
activePositions[staker].push(positionId);
allPositionIds.push(positionId);
// Remove snatched positions from tracking
_removeSnatchedPositions(positionsToSnatch);
console.log(" SNATCHED positions:", positionsToSnatch.length);
console.log(" Staked amount:", amount / 1e18);
if (trackPositions) {
_recordPositionData("Snatch");
}
} catch Error(string memory sReason) {
console.log(" Snatching failed:", sReason);
} catch {
console.log(" Snatching failed with unknown error");
}
} else {
console.log(" No snatchable positions found");
}
} catch {
// Catch-all for non-string errors
console.log(" Stake failed (unknown error) at", currentPercentStaked / 1e16, "percent");
}
vm.stopPrank();
} catch {}
}
}
function _executeExitPosition(uint256 rand) internal {
address staker = rand % 2 == 0 ? account : whale;
if (activePositions[staker].length > 0) {
uint256 index = rand % activePositions[staker].length;
uint256 positionId = activePositions[staker][index];
// Find a position owned by this staker
uint256 positionToExit = _findOwnedPosition(staker);
if (positionToExit > 0) {
vm.prank(staker);
try stake.exitPosition(positionId) {
// Remove from array
activePositions[staker][index] = activePositions[staker][activePositions[staker].length - 1];
activePositions[staker].pop();
// Also remove from allPositionIds
for (uint256 j = 0; j < allPositionIds.length; j++) {
if (allPositionIds[j] == positionId) {
allPositionIds[j] = 0; // Mark as removed
break;
}
}
try stake.exitPosition{gas: 5_000_000}(positionToExit) {
_removeTrackedPosition(positionToExit);
if (trackPositions) {
_recordPositionData("ExitStake");
_recordPositionDataSafe("Unstake");
}
} catch {
// Exit failed (position might be liquidated), remove from tracking
activePositions[staker][index] = activePositions[staker][activePositions[staker].length - 1];
activePositions[staker].pop();
// Also remove from allPositionIds
for (uint256 j = 0; j < allPositionIds.length; j++) {
if (allPositionIds[j] == positionId) {
allPositionIds[j] = 0; // Mark as removed
break;
}
}
// Position might be already exited/snatched
_removeTrackedPosition(positionToExit);
}
}
}
function _findSnatchablePositions(uint32 maxTaxRate, uint256 amountNeeded) internal view returns (uint256[] memory) {
// Find positions with tax rates lower than maxTaxRate
uint256[] memory snatchable = new uint256[](10); // Max 10 positions to snatch
function _findSnatchableQuick(uint32 maxTaxRate, uint256 amountNeeded) internal view returns (uint256[] memory) {
uint256[] memory result = new uint256[](3); // Max 3 positions
uint256 count = 0;
uint256 totalShares = 0;
for (uint256 i = 0; i < allPositionIds.length && count < 10; i++) {
uint256 positionId = allPositionIds[i];
// Check only recent positions (last 20 in circular buffer)
uint256 checkCount = totalPositionsCreated < 20 ? totalPositionsCreated : 20;
uint256 startIdx = positionWriteIndex > checkCount ? positionWriteIndex - checkCount : 0;
for (uint256 i = 0; i < checkCount && count < 3; i++) {
uint256 idx = (startIdx + i) % MAX_TRACKED_POSITIONS;
uint256 positionId = trackedPositions[idx];
if (positionId == 0) continue;
// Get position info
(uint256 shares, address owner,, , uint32 taxRate) = stake.positions(positionId);
(uint256 shares,, , , uint32 taxRate) = stake.positions(positionId);
// Skip if position doesn't exist or tax rate is too high
if (shares == 0 || taxRate >= maxTaxRate) continue;
snatchable[count] = positionId;
totalShares += shares;
count++;
// Check if we have enough shares to cover the amount needed
uint256 assetsFromShares = stake.sharesToAssets(totalShares);
if (assetsFromShares >= amountNeeded) {
break;
}
}
// Resize array to actual count
uint256[] memory result = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
result[i] = snatchable[i];
}
return result;
}
function _removeSnatchedPositions(uint256[] memory snatchedIds) internal {
// Remove snatched positions from allPositionIds
for (uint256 i = 0; i < snatchedIds.length; i++) {
uint256 snatchedId = snatchedIds[i];
// Find and remove from allPositionIds
for (uint256 j = 0; j < allPositionIds.length; j++) {
if (allPositionIds[j] == snatchedId) {
allPositionIds[j] = 0; // Mark as removed
if (shares > 0 && taxRate < maxTaxRate) {
result[count] = positionId;
totalShares += shares;
count++;
if (stake.sharesToAssets(totalShares) >= amountNeeded) {
break;
}
}
}
// Resize result
uint256[] memory finalResult = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
finalResult[i] = result[i];
}
return finalResult;
}
// Helper functions for circular buffer position tracking
function _addTrackedPosition(uint256 positionId, address owner) internal {
trackedPositions[positionWriteIndex] = positionId;
positionOwners[positionId] = owner;
positionWriteIndex = (positionWriteIndex + 1) % MAX_TRACKED_POSITIONS;
totalPositionsCreated++;
}
function _removeTrackedPosition(uint256 positionId) internal {
delete positionOwners[positionId];
// Don't remove from circular buffer, just mark owner as deleted
}
function _resetPositionTracking() internal {
// Clear circular buffer
for (uint256 i = 0; i < MAX_TRACKED_POSITIONS; i++) {
trackedPositions[i] = 0;
}
positionWriteIndex = 0;
totalPositionsCreated = 0;
}
function _findOwnedPosition(address owner) internal view returns (uint256) {
// Check last 10 positions for ownership
uint256 checkCount = totalPositionsCreated < 10 ? totalPositionsCreated : 10;
uint256 startIdx = positionWriteIndex > checkCount ? positionWriteIndex - checkCount : 0;
for (uint256 i = 0; i < checkCount; i++) {
uint256 idx = (startIdx + i) % MAX_TRACKED_POSITIONS;
uint256 positionId = trackedPositions[idx];
// Remove from owner's activePositions
for (uint256 k = 0; k < 2; k++) {
address owner = k == 0 ? account : whale;
uint256[] storage ownerPositions = activePositions[owner];
for (uint256 m = 0; m < ownerPositions.length; m++) {
if (ownerPositions[m] == snatchedId) {
ownerPositions[m] = ownerPositions[ownerPositions.length - 1];
ownerPositions.pop();
break;
}
}
if (positionId > 0 && positionOwners[positionId] == owner) {
return positionId;
}
}
return 0;
}
}

View file

@ -18,8 +18,8 @@ This directory contains tools for fuzzing the KRAIKEN LiquidityManager to identi
## Files
### Core Scripts
- `FuzzingAnalysis.s.sol` - Main Solidity fuzzing script that tests trading scenarios
- `run-fuzzing.sh` - Shell script to orchestrate multiple fuzzing runs
- `ImprovedFuzzingAnalysis.s.sol` - Enhanced fuzzing script with staking support and memory optimizations
- `run-fuzzing.sh` - Shell script to orchestrate multiple fuzzing runs with configurable parameters
- `clean.sh` - Cleanup script to remove generated files
### Helpers
@ -47,19 +47,23 @@ This directory contains tools for fuzzing the KRAIKEN LiquidityManager to identi
```bash
# Basic usage
./run-fuzzing.sh <optimizer_class> [runs=N] [trades=N]
./run-fuzzing.sh <optimizer_class> [runs=N] [staking=on|off] [buybias=N] [trades=N] [stakingbias=N]
# Examples
./run-fuzzing.sh BullMarketOptimizer # Uses defaults
./run-fuzzing.sh WhaleOptimizer runs=100 # 100 runs
./run-fuzzing.sh BearMarketOptimizer trades=50 # 50 trades per run
./run-fuzzing.sh NeutralMarketOptimizer runs=25 trades=30 # Both params
./run-fuzzing.sh BullMarketOptimizer runs=50 staking=on buybias=85 trades=100 stakingbias=95 # Full config
```
Parameters:
- `optimizer_class` - Required. The optimizer class to use
- `runs=N` - Optional. Number of fuzzing runs (default: 50)
- `trades=N` - Optional. Trades per run (default: 20, actual will be ±5)
- `runs=N` - Optional. Number of fuzzing runs (default: 20)
- `staking=on|off` - Optional. Enable/disable staking (default: on)
- `buybias=N` - Optional. 0-100% bias towards buying vs selling (default: 50)
- `trades=N` - Optional. Trades per run (default: 15, supports 100+ trades)
- `stakingbias=N` - Optional. 0-100% bias towards staking vs unstaking (default: 80)
### Output
@ -96,19 +100,25 @@ The fuzzing script supports these environment variables:
- `FUZZING_RUNS` - Number of runs (overridden by script parameter)
- `OPTIMIZER_CLASS` - Optimizer to use (overridden by script parameter)
- `TRADES_PER_RUN` - Trades per run (overridden by script parameter)
- `TRACK_POSITIONS` - Enable detailed position tracking (default: false)
- `TRACK_POSITIONS` - Enable detailed position tracking (default: true)
- `ENABLE_STAKING` - Enable staking operations (default: true)
- `BUY_BIAS` - Buy bias percentage (default: 50)
- `STAKING_BIAS` - Staking bias percentage (default: 80)
## Development
To add a new optimizer:
1. Create the optimizer contract in `../test/mocks/`
2. Import it in `FuzzingAnalysis.s.sol`
2. Import it in `ImprovedFuzzingAnalysis.s.sol`
3. Add it to the `_getOptimizerByClass` function
4. Update this README
## Notes
- Each run deploys a fresh Uniswap V3 environment
- Gas limit is set to 200M for --via-ir compilation
- Gas limit is set to 200M for script execution
- Results are deterministic based on the seed
- The fuzzer tests random buy/sell patterns with periodic recenters
- The fuzzer tests random buy/sell patterns with periodic recenters
- Supports staking operations with position snatching mechanics
- Memory-optimized with circular buffer for position tracking
- Records all trades to CSV for complete visualization

View file

@ -1,12 +1,162 @@
#!/bin/bash
# This script now uses the improved recorded fuzzing system
# The old FuzzingAnalysis.s.sol has been replaced with RecordedFuzzingAnalysis.s.sol
# which uses larger trades that can actually reach the discovery position
# Usage: ./run-improved-fuzzing.sh [optimizer] [runs=N] [staking=on|off] [buybias=N] [trades=N] [stakingbias=N]
# Examples:
# ./run-improved-fuzzing.sh BullMarketOptimizer runs=50
# ./run-improved-fuzzing.sh WhaleOptimizer runs=20 staking=off
# ./run-improved-fuzzing.sh BullMarketOptimizer runs=200 staking=on buybias=100 trades=30 stakingbias=95
echo "Note: run-fuzzing.sh now uses the improved fuzzing with recording capabilities"
echo "Redirecting to run-recorded-fuzzing.sh..."
# 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}
STAKING=${3:-staking=on}
BUYBIAS=${4:-buybias=50}
TRADES=${5:-trades=15}
STAKINGBIAS=${6:-stakingbias=80}
# Parse runs parameter
if [[ $RUNS == runs=* ]]; then
RUNS_VALUE=${RUNS#runs=}
else
RUNS_VALUE=$RUNS
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
fi
# Parse buy bias parameter
BUYBIAS_VALUE="50"
if [[ $BUYBIAS == buybias=* ]]; then
BUYBIAS_VALUE=${BUYBIAS#buybias=}
fi
# Parse trades parameter
TRADES_VALUE="15"
if [[ $TRADES == trades=* ]]; then
TRADES_VALUE=${TRADES#trades=}
fi
# Parse staking bias parameter
STAKINGBIAS_VALUE="80"
if [[ $STAKINGBIAS == stakingbias=* ]]; then
STAKINGBIAS_VALUE=${STAKINGBIAS#stakingbias=}
fi
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_DIR="fuzzing_results_${OPTIMIZER}_${TIMESTAMP}"
echo -e "${GREEN}=== Fuzzing Analysis ===${NC}"
echo "Optimizer: $OPTIMIZER"
echo "Total runs: $RUNS_VALUE"
echo "Trades per run: $TRADES_VALUE"
echo "Staking: $([ "$STAKING_ENABLED" = "true" ] && echo "enabled" || echo "disabled")"
if [ "$STAKING_ENABLED" = "true" ]; then
echo "Staking bias: $STAKINGBIAS_VALUE%"
fi
echo "Buy bias: $BUYBIAS_VALUE%"
echo "Output directory: $OUTPUT_DIR"
echo ""
# Pass all arguments to the new script
exec ./analysis/run-recorded-fuzzing.sh "$@"
# 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 fuzzing analysis
echo -e "${YELLOW}Starting fuzzing analysis...${NC}"
echo ""
FUZZING_RUNS=$RUNS_VALUE \
OPTIMIZER_CLASS=$OPTIMIZER \
ENABLE_STAKING=$STAKING_ENABLED \
BUY_BIAS=$BUYBIAS_VALUE \
TRADES_PER_RUN=$TRADES_VALUE \
STAKING_BIAS=$STAKINGBIAS_VALUE \
TRACK_POSITIONS=true \
forge script analysis/ImprovedFuzzingAnalysis.s.sol:ImprovedFuzzingAnalysis --gas-limit 200000000 -vv 2>&1 | tee $OUTPUT_DIR/fuzzing.log
# Extract key metrics
echo ""
echo -e "${GREEN}=== ANALYSIS COMPLETE ===${NC}"
# Show summary from log
tail -20 $OUTPUT_DIR/fuzzing.log | grep -E "Total scenarios|Profitable|Discovery|Stakes|Snatches" || true
# Check for position CSVs
POSITION_CSV_COUNT=$(ls -1 improved_positions_*.csv 2>/dev/null | wc -l)
if [ $POSITION_CSV_COUNT -gt 0 ]; then
# Move position CSVs to output directory
mv improved_positions_*.csv $OUTPUT_DIR/
echo ""
echo -e "${GREEN}Position CSVs saved to: $OUTPUT_DIR/${NC}"
# Calculate max staking percentage
echo ""
echo -e "${YELLOW}=== Maximum Staking Level ===${NC}"
for f in $OUTPUT_DIR/improved_positions_*.csv; do
tail -1 "$f" | cut -d',' -f13
done | sort -n | tail -1 | awk '{
pct = $1/1e16
printf "%.2f%% of authorized stake (%.2f%% of KRAIKEN supply)\n", pct, pct*0.2
}'
fi
# Check for snatching activity
echo ""
echo -e "${YELLOW}=== Snatching Activity ===${NC}"
SNATCH_COUNT=$(grep -c "SNATCHED" $OUTPUT_DIR/fuzzing.log 2>/dev/null || true)
if [ -z "$SNATCH_COUNT" ]; then
SNATCH_COUNT="0"
fi
if [ "$SNATCH_COUNT" -gt "0" ]; then
echo -e "${GREEN}Snatching observed! Found $SNATCH_COUNT snatching events${NC}"
grep "SNATCHED" $OUTPUT_DIR/fuzzing.log | head -5
else
echo "No snatching observed in this run"
fi
# Check for profitable scenarios
PROFITABLE_COUNT=$(grep -c "PROFITABLE!" $OUTPUT_DIR/fuzzing.log 2>/dev/null || true)
if [ -z "$PROFITABLE_COUNT" ]; then
PROFITABLE_COUNT="0"
fi
if [ "$PROFITABLE_COUNT" -gt "0" ]; then
echo ""
echo -e "${GREEN}=== PROFITABLE SCENARIOS FOUND ===${NC}"
echo "Found $PROFITABLE_COUNT profitable scenarios"
grep "PROFITABLE!" $OUTPUT_DIR/fuzzing.log | head -5
fi
echo ""
echo -e "${GREEN}Full results saved to: $OUTPUT_DIR/${NC}"
echo ""
echo "To view detailed logs:"
echo " cat $OUTPUT_DIR/fuzzing.log"
echo ""
echo "To visualize position movements (if CSVs generated):"
echo " ./analysis/view-scenarios.sh $OUTPUT_DIR"

View file

@ -1,162 +0,0 @@
#!/bin/bash
# Usage: ./run-improved-fuzzing.sh [optimizer] [runs=N] [staking=on|off] [buybias=N] [trades=N] [stakingbias=N]
# Examples:
# ./run-improved-fuzzing.sh BullMarketOptimizer runs=50
# ./run-improved-fuzzing.sh WhaleOptimizer runs=20 staking=off
# ./run-improved-fuzzing.sh BullMarketOptimizer runs=200 staking=on buybias=100 trades=30 stakingbias=95
# 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}
STAKING=${3:-staking=on}
BUYBIAS=${4:-buybias=50}
TRADES=${5:-trades=15}
STAKINGBIAS=${6:-stakingbias=80}
# Parse runs parameter
if [[ $RUNS == runs=* ]]; then
RUNS_VALUE=${RUNS#runs=}
else
RUNS_VALUE=$RUNS
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
fi
# Parse buy bias parameter
BUYBIAS_VALUE="50"
if [[ $BUYBIAS == buybias=* ]]; then
BUYBIAS_VALUE=${BUYBIAS#buybias=}
fi
# Parse trades parameter
TRADES_VALUE="15"
if [[ $TRADES == trades=* ]]; then
TRADES_VALUE=${TRADES#trades=}
fi
# Parse staking bias parameter
STAKINGBIAS_VALUE="80"
if [[ $STAKINGBIAS == stakingbias=* ]]; then
STAKINGBIAS_VALUE=${STAKINGBIAS#stakingbias=}
fi
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_DIR="fuzzing_results_improved_${OPTIMIZER}_${TIMESTAMP}"
echo -e "${GREEN}=== Improved Fuzzing Analysis ===${NC}"
echo "Optimizer: $OPTIMIZER"
echo "Total runs: $RUNS_VALUE"
echo "Trades per run: $TRADES_VALUE"
echo "Staking: $([ "$STAKING_ENABLED" = "true" ] && echo "enabled" || echo "disabled")"
if [ "$STAKING_ENABLED" = "true" ]; then
echo "Staking bias: $STAKINGBIAS_VALUE%"
fi
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 improved fuzzing with buy bias
echo -e "${YELLOW}Starting improved fuzzing analysis with buy bias...${NC}"
echo ""
FUZZING_RUNS=$RUNS_VALUE \
OPTIMIZER_CLASS=$OPTIMIZER \
ENABLE_STAKING=$STAKING_ENABLED \
BUY_BIAS=$BUYBIAS_VALUE \
TRADES_PER_RUN=$TRADES_VALUE \
STAKING_BIAS=$STAKINGBIAS_VALUE \
TRACK_POSITIONS=true \
forge script analysis/ImprovedFuzzingAnalysis.s.sol:ImprovedFuzzingAnalysis --gas-limit 100000000 -vv 2>&1 | tee $OUTPUT_DIR/fuzzing.log
# Extract key metrics
echo ""
echo -e "${GREEN}=== ANALYSIS COMPLETE ===${NC}"
# Show summary from log
tail -20 $OUTPUT_DIR/fuzzing.log | grep -E "Total scenarios|Profitable|Discovery|Stakes|Snatches" || true
# Check for position CSVs
POSITION_CSV_COUNT=$(ls -1 improved_positions_*.csv 2>/dev/null | wc -l)
if [ $POSITION_CSV_COUNT -gt 0 ]; then
# Move position CSVs to output directory
mv improved_positions_*.csv $OUTPUT_DIR/
echo ""
echo -e "${GREEN}Position CSVs saved to: $OUTPUT_DIR/${NC}"
# Calculate max staking percentage
echo ""
echo -e "${YELLOW}=== Maximum Staking Level ===${NC}"
for f in $OUTPUT_DIR/improved_positions_*.csv; do
tail -1 "$f" | cut -d',' -f13
done | sort -n | tail -1 | awk '{
pct = $1/1e16
printf "%.2f%% of authorized stake (%.2f%% of KRAIKEN supply)\n", pct, pct*0.2
}'
fi
# Check for snatching activity
echo ""
echo -e "${YELLOW}=== Snatching Activity ===${NC}"
SNATCH_COUNT=$(grep -c "SNATCHED" $OUTPUT_DIR/fuzzing.log 2>/dev/null || true)
if [ -z "$SNATCH_COUNT" ]; then
SNATCH_COUNT="0"
fi
if [ "$SNATCH_COUNT" -gt "0" ]; then
echo -e "${GREEN}Snatching observed! Found $SNATCH_COUNT snatching events${NC}"
grep "SNATCHED" $OUTPUT_DIR/fuzzing.log | head -5
else
echo "No snatching observed in this run"
fi
# Check for profitable scenarios
PROFITABLE_COUNT=$(grep -c "PROFITABLE!" $OUTPUT_DIR/fuzzing.log 2>/dev/null || true)
if [ -z "$PROFITABLE_COUNT" ]; then
PROFITABLE_COUNT="0"
fi
if [ "$PROFITABLE_COUNT" -gt "0" ]; then
echo ""
echo -e "${GREEN}=== PROFITABLE SCENARIOS FOUND ===${NC}"
echo "Found $PROFITABLE_COUNT profitable scenarios"
grep "PROFITABLE!" $OUTPUT_DIR/fuzzing.log | head -5
fi
echo ""
echo -e "${GREEN}Full results saved to: $OUTPUT_DIR/${NC}"
echo ""
echo "To view detailed logs:"
echo " cat $OUTPUT_DIR/fuzzing.log"
echo ""
echo "To visualize position movements (if CSVs generated):"
echo " ./analysis/view-scenarios.sh $OUTPUT_DIR"