From 74e09bb38ba4b26b915011b9cfd34f6bd5ba4cb3 Mon Sep 17 00:00:00 2001 From: johba Date: Tue, 19 Aug 2025 17:35:43 +0200 Subject: [PATCH] consolidated scripts --- onchain/CLAUDE.md | 12 +- .../analysis/ImprovedFuzzingAnalysis.s.sol | 394 +++++++++--------- onchain/analysis/README.md | 28 +- onchain/analysis/run-fuzzing.sh | 164 +++++++- onchain/analysis/run-improved-fuzzing.sh | 162 ------- 5 files changed, 383 insertions(+), 377 deletions(-) delete mode 100755 onchain/analysis/run-improved-fuzzing.sh diff --git a/onchain/CLAUDE.md b/onchain/CLAUDE.md index 3d2d579..2983778 100644 --- a/onchain/CLAUDE.md +++ b/onchain/CLAUDE.md @@ -69,28 +69,28 @@ uint256 requiredEth = outstandingSupply.mulDiv(sqrtVwapX96, 1 << 96); ## Fuzzing Analysis -### Improved Fuzzing with Staking +### Fuzzing with Staking Test strategy resilience with configurable trading and staking: ```bash # Basic test with default parameters -./analysis/run-improved-fuzzing.sh BullMarketOptimizer runs=20 +./analysis/run-fuzzing.sh BullMarketOptimizer runs=20 # Advanced test with custom parameters -./analysis/run-improved-fuzzing.sh BullMarketOptimizer runs=50 staking=on buybias=85 trades=60 stakingbias=95 +./analysis/run-fuzzing.sh BullMarketOptimizer runs=50 staking=on buybias=85 trades=60 stakingbias=95 ``` **Parameters**: - `runs=N`: Number of fuzzing scenarios (default: 20) - `staking=on|off`: Enable/disable staking (default: on) - `buybias=N`: 0-100% bias towards buying vs selling (default: 50) -- `trades=N`: Number of trades per scenario (default: 15, max ~70 due to memory) +- `trades=N`: Number of trades per scenario (default: 15, supports 100+ with optimizations) - `stakingbias=N`: 0-100% bias towards staking vs unstaking (default: 80) **How it works**: - Uses random trading strategy with configurable biases - Staking/unstaking happens automatically every 3rd trade -- Records position data every 5th trade to avoid memory issues +- Records position data for every trade for complete visualization - Tracks staking metrics: attempts, successes, snatching events ### Advanced Recording & Replay System @@ -133,7 +133,7 @@ Test strategy resilience with configurable trading and staking: - `ExtremeOptimizer`: Cycles through parameter extremes - `MaliciousOptimizer`: Intentionally adversarial parameters -**Output**: `fuzzing_results_recorded_[optimizer]_[timestamp]/` +**Output**: `fuzzing_results_[optimizer]_[timestamp]/` - Unique Run ID for each campaign - JSON recordings of profitable scenarios - Replay scripts for exact reproduction diff --git a/onchain/analysis/ImprovedFuzzingAnalysis.s.sol b/onchain/analysis/ImprovedFuzzingAnalysis.s.sol index dfd7cc1..4369154 100644 --- a/onchain/analysis/ImprovedFuzzingAnalysis.s.sol +++ b/onchain/analysis/ImprovedFuzzingAnalysis.s.sol @@ -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; } } \ No newline at end of file diff --git a/onchain/analysis/README.md b/onchain/analysis/README.md index b6e943a..1853229 100644 --- a/onchain/analysis/README.md +++ b/onchain/analysis/README.md @@ -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 [runs=N] [trades=N] +./run-fuzzing.sh [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 \ No newline at end of file +- 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 \ No newline at end of file diff --git a/onchain/analysis/run-fuzzing.sh b/onchain/analysis/run-fuzzing.sh index e728117..c03ff9d 100755 --- a/onchain/analysis/run-fuzzing.sh +++ b/onchain/analysis/run-fuzzing.sh @@ -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 "$@" \ No newline at end of file +# 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" \ No newline at end of file diff --git a/onchain/analysis/run-improved-fuzzing.sh b/onchain/analysis/run-improved-fuzzing.sh deleted file mode 100755 index 6570803..0000000 --- a/onchain/analysis/run-improved-fuzzing.sh +++ /dev/null @@ -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" \ No newline at end of file