From 10702f5aa3b59f5204099ea69aeec9edb3418677 Mon Sep 17 00:00:00 2001 From: johba Date: Tue, 19 Aug 2025 14:57:49 +0200 Subject: [PATCH] feat: Enhance fuzzing with staking integration and configurable parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add staking/unstaking actions to fuzzing scenarios (stake every 3rd trade) - Implement snatching logic when stake pool reaches capacity (uses max tax rate) - Add configurable parameters: - buyBias: Control buy vs sell ratio (0-100%) - stakingBias: Control stake vs unstake ratio (0-100%) - tradesPerRun: Configure number of trades per scenario - staking: Enable/disable staking entirely - Simplify to single trading strategy (_executeRandomLargeTrades) - Fix memory issues by recording only every 5th trade to CSV - Track staking metrics (stakes attempted/succeeded, snatches attempted/succeeded) - Update CLAUDE.md with new fuzzing parameters and usage examples - Clean up old TODO files and unused code 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- onchain/CLAUDE.md | 25 +- onchain/TODO_DEBUGGING_IMPROVEMENTS.md | 75 ----- .../analysis/ImprovedFuzzingAnalysis.s.sol | 282 ++---------------- onchain/analysis/helpers/CSVHelper.sol | 2 +- onchain/analysis/run-improved-fuzzing.sh | 26 +- onchain/analysis/scenario-visualizer.html | 31 +- onchain/improved_profitable_3601.csv | 3 + onchain/improved_profitable_84051.csv | 5 + onchain/lib/pt-v5-twab-controller | 2 +- onchain/lib/solmate | 2 +- 10 files changed, 110 insertions(+), 343 deletions(-) delete mode 100644 onchain/TODO_DEBUGGING_IMPROVEMENTS.md create mode 100644 onchain/improved_profitable_3601.csv create mode 100644 onchain/improved_profitable_84051.csv diff --git a/onchain/CLAUDE.md b/onchain/CLAUDE.md index c9be966..3d2d579 100644 --- a/onchain/CLAUDE.md +++ b/onchain/CLAUDE.md @@ -69,17 +69,30 @@ uint256 requiredEth = outstandingSupply.mulDiv(sqrtVwapX96, 1 << 96); ## Fuzzing Analysis -### Standard Fuzzing -Test strategy resilience across market conditions: +### Improved Fuzzing with Staking +Test strategy resilience with configurable trading and staking: ```bash -# Quick test (50 runs, position CSV) -./analysis/run-fuzzing.sh BullMarketOptimizer debugCSV +# Basic test with default parameters +./analysis/run-improved-fuzzing.sh BullMarketOptimizer runs=20 -# Full campaign (custom runs/trades) -./analysis/run-fuzzing.sh WhaleOptimizer runs=100 trades=30 +# Advanced test with custom parameters +./analysis/run-improved-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) +- `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 +- Tracks staking metrics: attempts, successes, snatching events + ### Advanced Recording & Replay System **Find and Record Invariant Violations**: diff --git a/onchain/TODO_DEBUGGING_IMPROVEMENTS.md b/onchain/TODO_DEBUGGING_IMPROVEMENTS.md deleted file mode 100644 index 46da671..0000000 --- a/onchain/TODO_DEBUGGING_IMPROVEMENTS.md +++ /dev/null @@ -1,75 +0,0 @@ -# TODO: Debugging Improvements - -Based on the floor position calculation bug investigation, here are the key areas that need improvement: - -## 1. Document Uniswap V3 Mechanics & Token Flows -**Problem**: Confusion about ETH flow direction during trades and which token amounts are calculated in different positions. - -**Tasks**: -- Create a visual diagram showing token flows during trades (when ETH flows IN vs OUT) -- Document the relationship between token0/token1 and WETH/KRAIKEN -- Explain how `getAmount0ForLiquidity` vs `getAmount1ForLiquidity` work with different tick ranges -- Add examples showing what happens in each position type (ANCHOR, DISCOVERY, FLOOR) when token0isWeth=true -- Create a reference table: "When calculating X, use Y function to get Z token" - -**Acceptance Criteria**: Developer can quickly determine which token is being calculated in any liquidity operation without trial and error. - -## 2. Document Optimizer Parameters & Effects -**Problem**: Misunderstanding of how parameters like anchorShare and capitalInefficiency affect the protocol behavior. - -**Tasks**: -- Create detailed documentation for each optimizer parameter: - - `capitalInefficiency` (0-100%): How it affects KRAIKEN valuation for reserves (0% = 70% value, 100% = 170% value) - - `anchorShare` (0-100%): How it reduces floor ETH allocation (95% = 90.1% floor, not 95% anchor) - - `anchorWidth` (0-100): How it sets anchor position range as percentage of price - - `discoveryDepth` (0-100%): How it controls discovery liquidity density (2x-10x multiplier) -- Add examples showing how each parameter affects floor position placement -- Create scenarios: "In a bull market with X parameters, expect floor at Y" - -**Acceptance Criteria**: Developer can predict where positions will be placed given optimizer parameters and market conditions. - -## 3. Implement Calculation Tracing & Visualization Tools -**Problem**: Console.log doesn't work properly in Forge scripts, making it hard to debug complex calculations. Token flows are not visible. - -**Tasks**: -- Create a `DebugEvent` system that works in all contexts: - ```solidity - event DebugCalculation(string label, uint256 value, string unit); - event DebugTokenFlow(string from, string to, address token, uint256 amount); - ``` -- Build a script to parse these events and display them nicely: - ``` - [CALC] Outstanding Supply: 91,373,741 KRAIKEN - [FLOW] LiquidityManager -> UniswapPool: 96,159,882 KRAIKEN - [CALC] After subtraction: 91,373,741 KRAIKEN (ERROR: should be ~2.4M) - ``` -- Add debug mode flag to contracts that enables detailed calculation logging -- Create visualization tool that shows token balances at each step of recenter - -**Acceptance Criteria**: Developer can trace exact values through complex calculations without modifying contracts. - -## 4. Improve Code Quality: Type Safety, Tests & Invariants -**Problem**: Easy to mix up ETH and KRAIKEN amounts (both uint256). Tests don't catch intermediate calculation errors. - -**Tasks**: -- Implement type-safe token amounts: - ```solidity - library TokenAmounts { - struct EthAmount { uint256 value; } - struct KraikenAmount { uint256 value; } - } - ``` -- Add unit tests for intermediate calculations: - ```solidity - function test_discoveryAmountIsKraiken() { - // Test that discoveryAmount represents KRAIKEN, not ETH - } - ``` -- Implement runtime invariant checks: - ```solidity - require(floorTick - anchorUpperTick < 50000, "Floor too far from anchor"); - require(outstandingSupply < totalSupply / 2, "Outstanding supply unrealistic"); - ``` -- Add invariant fuzzing tests that verify protocol assumptions always hold - -**Acceptance Criteria**: Bugs like wrong token type in calculations are caught at compile time or immediately during testing. \ No newline at end of file diff --git a/onchain/analysis/ImprovedFuzzingAnalysis.s.sol b/onchain/analysis/ImprovedFuzzingAnalysis.s.sol index ea3b78d..dfd7cc1 100644 --- a/onchain/analysis/ImprovedFuzzingAnalysis.s.sol +++ b/onchain/analysis/ImprovedFuzzingAnalysis.s.sol @@ -56,6 +56,8 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager { bool public trackPositions; bool public enableStaking; uint256 public buyBias; // 0-100, percentage bias towards buying vs selling + uint256 public tradesPerRun; // Number of trades/actions per scenario + uint256 public stakingBias; // 0-100, percentage bias towards staking vs unstaking string public optimizerClass; function run() public virtual { @@ -112,7 +114,7 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager { // Initial recenter vm.prank(feeDestination); - lm.recenter(); + try lm.recenter{gas: 50_000_000}() {} catch {} // Initialize position tracking for each seed if (trackPositions) { @@ -198,74 +200,13 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager { // Get initial discovery position (, int24 discoveryLower, int24 discoveryUpper) = lm.positions(ThreePositionStrategy.Stage.DISCOVERY); - // First do some trading to generate KRAIKEN tokens - // Buy KRAIKEN with ETH so accounts have tokens to stake - // Need MUCH more KRAIKEN to fill the 20% pool - _executeBuy(account, weth.balanceOf(account) * 3 / 4); // Buy 75% of ETH worth - _executeBuy(whale, weth.balanceOf(whale) * 4 / 5); // Whale buys 80% of ETH worth + // Initial buy to generate some KRAIKEN tokens for trading/staking + _executeBuy(account, weth.balanceOf(account) / 4); // Buy 25% of ETH worth + _executeBuy(whale, weth.balanceOf(whale) / 4); // Whale buys 25% of ETH worth - // Now execute staking actions if enabled (accounts should have KRAIKEN now) - if (enableStaking) { - // More aggressive staking to fill the pool - console.log(" === Starting initial staking round ==="); - for (uint256 i = 0; i < 30; i++) { // Increased to 30 to approach limit - _executeStakingAction(rand + i * 1000); - } - } + // Always use random trading strategy for consistent behavior + _executeRandomLargeTrades(rand); - // Strategy selection based on seed - uint256 strategy = seed % 5; - - if (strategy == 0) { - // STRATEGY 1: Massive coordinated sell to push into discovery - _executeDiscoveryPush(rand); - } else if (strategy == 1) { - // STRATEGY 2: Whale manipulation - _executeWhaleManipulation(rand); - } else if (strategy == 2) { - // STRATEGY 3: Volatile swings - _executeVolatileSwings(rand); - } else if (strategy == 3) { - // STRATEGY 4: Sustained pressure - _executeSustainedPressure(rand); - } else { - // STRATEGY 5: Random large trades - _executeRandomLargeTrades(rand); - } - - // More staking actions after trading if enabled - if (enableStaking) { - console.log(" === Post-trading staking round ==="); - // Try to stake more aggressively after trading to push pool over limit - for (uint256 i = 0; i < 10; i++) { // Increased from 2 to 10 - _executeStakingAction(rand + i * 2000 + 5000); - } - - // Final push to ensure we try snatching - console.log(" === Final staking push (should trigger snatching) ==="); - - // Check if we're near the limit - uint256 finalPercent = stake.getPercentageStaked(); - console.log(" Current pool:", finalPercent / 1e16, "percent"); - - // Force large stakes to exceed limit - for (uint256 i = 0; i < 10; i++) { - // Try to stake large amounts to push over limit - uint256 largeAmount = harberg.balanceOf(account) / 2; - if (largeAmount > harberg.minStake()) { - vm.prank(account); - harberg.approve(address(stake), largeAmount); - _executeStakeWithAmount(account, largeAmount, uint32(i % 30)); - } - - largeAmount = harberg.balanceOf(whale) / 2; - if (largeAmount > harberg.minStake()) { - vm.prank(whale); - harberg.approve(address(stake), largeAmount); - _executeStakeWithAmount(whale, largeAmount, uint32((i + 15) % 30)); - } - } - } // Check if we reached discovery (, int24 currentTick,,,,,) = pool.slot0(); @@ -286,193 +227,15 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager { finalBalance = weth.balanceOf(account); } - - function _executeDiscoveryPush(uint256 rand) internal virtual { - console.log(" Strategy: Discovery Push"); - - // Both accounts buy large amounts first - uint256 traderBuy = weth.balanceOf(account) * 7 / 10; // 70% of balance - uint256 whaleBuy = weth.balanceOf(whale) * 8 / 10; // 80% of balance - - _executeBuy(account, traderBuy); - _executeBuy(whale, whaleBuy); - - if (trackPositions) { - _recordPositionData("MassiveBuy"); - } - - // Now coordinated massive sell to push price down - uint256 whaleKraiken = harberg.balanceOf(whale); - _executeSell(whale, whaleKraiken); // Whale dumps all - - if (trackPositions) { - _recordPositionData("WhaleDump"); - } - - // Trader tries to profit from the movement - uint256 traderKraiken = harberg.balanceOf(account); - if (traderKraiken > 0) { - // Sell half during crash - _executeSell(account, traderKraiken / 2); - - // Recenter during low price - vm.warp(block.timestamp + 1 hours); - vm.prank(feeDestination); - try lm.recenter{gas: 50_000_000}() {} catch {} - - // Buy back at low price - uint256 remainingWeth = weth.balanceOf(account); - if (remainingWeth > 0) { - _executeBuy(account, remainingWeth / 2); - } - } - } - - function _executeWhaleManipulation(uint256 rand) internal { - console.log(" Strategy: Whale Manipulation"); - - // Whale does large trades to move price significantly - for (uint256 i = 0; i < 5; i++) { - // Apply buy bias to whale's action choice - uint256 actionRoll = (rand >> i) % 100; - uint256 action; - if (actionRoll < buyBias) { - action = 0; // Buy (biased) - } else if (actionRoll < 85) { - action = 1; // Sell - } else { - action = 2; // Recenter - } - - if (action == 0) { - // Large buy (increased with high buy bias) - uint256 buyPct = buyBias > 70 ? 70 : 50; - uint256 buyAmount = weth.balanceOf(whale) * buyPct / 100; - if (buyAmount > 0) { - _executeBuy(whale, buyAmount); - } - } else if (action == 1) { - // Large sell (reduced with high buy bias) - uint256 sellPct = buyBias > 70 ? 25 : 50; - uint256 sellAmount = harberg.balanceOf(whale) * sellPct / 100; - if (sellAmount > 0) { - _executeSell(whale, sellAmount); - } - } else { - // Trigger recenter - vm.warp(block.timestamp + 30 minutes); - vm.prank(feeDestination); - try lm.recenter{gas: 50_000_000}() {} catch {} - } - - // Trader tries to follow/counter (also biased) - if (buyBias > 70 || weth.balanceOf(account) > harberg.balanceOf(account)) { - if (weth.balanceOf(account) > 0) { - _executeBuy(account, weth.balanceOf(account) / 4); - } - } else if (harberg.balanceOf(account) > 0) { - _executeSell(account, harberg.balanceOf(account) / 4); - } - - if (trackPositions && i % 2 == 0) { - _recordPositionData("Whale"); - } - } - } - - function _executeVolatileSwings(uint256 rand) internal { - console.log(" Strategy: Volatile Swings (with buy bias)"); - - // Create large price swings (but bias towards buys if configured) - for (uint256 i = 0; i < 8; i++) { - // With high buy bias, reduce sell swings - bool shouldSell = (i % 2 == 0) && (buyBias < 70); - - if (shouldSell) { - // Swing down - coordinated sells (reduced with high buy bias) - uint256 sellPct = buyBias > 50 ? 50 : 100; - uint256 traderSell = harberg.balanceOf(account) * sellPct / 100; - uint256 whaleSell = harberg.balanceOf(whale) * sellPct / 100; - - if (traderSell > 0) _executeSell(account, traderSell); - if (whaleSell > 0) _executeSell(whale, whaleSell); - - // If we pushed price low enough, recenter - (, int24 tick,,,,,) = pool.slot0(); - (, int24 discoveryLower,) = lm.positions(ThreePositionStrategy.Stage.DISCOVERY); - - if (tick < discoveryLower + 1000) { - vm.warp(block.timestamp + 1 hours); - vm.prank(feeDestination); - try lm.recenter{gas: 50_000_000}() {} catch {} - } - } else { - // Swing up - coordinated buys (increased with high buy bias) - uint256 buyPctTrader = buyBias > 70 ? 80 : 60; - uint256 buyPctWhale = buyBias > 70 ? 85 : 70; - uint256 traderBuy = weth.balanceOf(account) * buyPctTrader / 100; - uint256 whaleBuy = weth.balanceOf(whale) * buyPctWhale / 100; - - if (traderBuy > 0) _executeBuy(account, traderBuy); - if (whaleBuy > 0) _executeBuy(whale, whaleBuy); - } - - if (trackPositions) { - _recordPositionData("Swing"); - } - } - } - - function _executeSustainedPressure(uint256 rand) internal { - console.log(" Strategy: Sustained Pressure (buy bias:", buyBias, "%)"); - - // First accumulate KRAIKEN (even more with high buy bias) - uint256 buyPct = buyBias > 70 ? 95 : 90; - _executeBuy(account, weth.balanceOf(account) * buyPct / 100); - _executeBuy(whale, weth.balanceOf(whale) * buyPct / 100); - - if (trackPositions) { - _recordPositionData("Accumulation"); - } - - // Now sustained selling pressure (reduced with high buy bias) - uint256 totalKraiken = harberg.balanceOf(account) + harberg.balanceOf(whale); - uint256 sellsPerAccount = buyBias > 70 ? 5 : 10; // Fewer sells with high buy bias - uint256 amountPerSell = totalKraiken / (sellsPerAccount * 2); - - for (uint256 i = 0; i < sellsPerAccount; i++) { - // Alternate sells between accounts - if (harberg.balanceOf(account) >= amountPerSell) { - _executeSell(account, amountPerSell); - } - if (harberg.balanceOf(whale) >= amountPerSell) { - _executeSell(whale, amountPerSell); - } - - // Check if we're approaching discovery - (, int24 currentTick,,,,,) = pool.slot0(); - (, int24 discoveryUpper,) = lm.positions(ThreePositionStrategy.Stage.DISCOVERY); - - if (currentTick < discoveryUpper + 500) { - console.log(" Approaching discovery, tick:", vm.toString(currentTick)); - - // Recenter while near discovery - vm.warp(block.timestamp + 30 minutes); - vm.prank(feeDestination); - try lm.recenter{gas: 50_000_000}() {} catch {} - - if (trackPositions) { - _recordPositionData("Near_Discovery"); - } - } - } - } - function _executeRandomLargeTrades(uint256 rand) internal { console.log(" Strategy: Random Large Trades"); console.log(" Buy bias:", buyBias, "%"); + console.log(" Trades:", tradesPerRun); + if (enableStaking) { + console.log(" Staking bias:", stakingBias, "%"); + } - for (uint256 i = 0; i < 15; i++) { + for (uint256 i = 0; i < tradesPerRun; i++) { rand = uint256(keccak256(abi.encodePacked(rand, i))); uint256 actor = rand % 2; // 0 = trader, 1 = whale @@ -511,8 +274,21 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager { try lm.recenter{gas: 50_000_000}() {} catch {} } - if (trackPositions && i % 3 == 0) { - _recordPositionData("Random"); + // Every 3rd trade, attempt staking/unstaking if enabled + if (enableStaking && i % 3 == 2) { + uint256 stakingRoll = uint256(keccak256(abi.encodePacked(rand, "staking", i))) % 100; + if (stakingRoll < stakingBias) { + // Try to stake + _executeStake(rand + i * 1000); + } else { + // Try to unstake + _executeExitPosition(rand + i * 1000); + } + } + + // Only record every 5th trade to avoid memory issues with large trade counts + if (trackPositions && i % 5 == 0) { + _recordPositionData("Trade"); } } } @@ -550,6 +326,8 @@ contract ImprovedFuzzingAnalysis is Test, CSVManager { trackPositions = vm.envOr("TRACK_POSITIONS", false); enableStaking = vm.envOr("ENABLE_STAKING", true); // Default to true buyBias = vm.envOr("BUY_BIAS", uint256(50)); // Default 50% (balanced) + tradesPerRun = vm.envOr("TRADES_PER_RUN", uint256(15)); // Default 15 trades + stakingBias = vm.envOr("STAKING_BIAS", uint256(80)); // Default 80% stake vs 20% unstake optimizerClass = vm.envOr("OPTIMIZER_CLASS", string("BullMarketOptimizer")); } diff --git a/onchain/analysis/helpers/CSVHelper.sol b/onchain/analysis/helpers/CSVHelper.sol index ce4eb1a..df36f2d 100644 --- a/onchain/analysis/helpers/CSVHelper.sol +++ b/onchain/analysis/helpers/CSVHelper.sol @@ -15,7 +15,7 @@ library CSVHelper { */ function createPositionsHeader() internal pure returns (string memory) { return - "precedingAction, currentTick, floorTickLower, floorTickUpper, floorLiquidity, anchorTickLower, anchorTickUpper, anchorLiquidity, discoveryTickLower, discoveryTickUpper, discoveryLiquidity, token0isWeth"; + "precedingAction, currentTick, floorTickLower, floorTickUpper, floorLiquidity, anchorTickLower, anchorTickUpper, anchorLiquidity, discoveryTickLower, discoveryTickUpper, discoveryLiquidity, token0isWeth, percentageStaked, avgTaxRate"; } function createTimeSeriesHeader() internal pure returns (string memory) { diff --git a/onchain/analysis/run-improved-fuzzing.sh b/onchain/analysis/run-improved-fuzzing.sh index 4b910f1..6570803 100755 --- a/onchain/analysis/run-improved-fuzzing.sh +++ b/onchain/analysis/run-improved-fuzzing.sh @@ -1,10 +1,10 @@ #!/bin/bash -# Usage: ./run-improved-fuzzing.sh [optimizer] [runs=N] [staking=on|off] [buybias=N] +# 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 +# ./run-improved-fuzzing.sh BullMarketOptimizer runs=200 staking=on buybias=100 trades=30 stakingbias=95 # Colors for output RED='\033[0;31m' @@ -19,6 +19,8 @@ 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 @@ -42,13 +44,29 @@ 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 "" @@ -76,8 +94,10 @@ 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 30000000 -vv 2>&1 | tee $OUTPUT_DIR/fuzzing.log +forge script analysis/ImprovedFuzzingAnalysis.s.sol:ImprovedFuzzingAnalysis --gas-limit 100000000 -vv 2>&1 | tee $OUTPUT_DIR/fuzzing.log # Extract key metrics echo "" diff --git a/onchain/analysis/scenario-visualizer.html b/onchain/analysis/scenario-visualizer.html index b98209d..24a3ed4 100644 --- a/onchain/analysis/scenario-visualizer.html +++ b/onchain/analysis/scenario-visualizer.html @@ -288,6 +288,10 @@ const discoveryTickUpper = parseFloat(row.discoveryTickUpper); const discoveryLiquidity = parseFloat(row.discoveryLiquidity || 0); + // Extract staking metrics if available + const percentageStaked = row.percentageStaked ? parseFloat(row.percentageStaked) : 0; + const avgTaxRate = row.avgTaxRate ? parseFloat(row.avgTaxRate) : 0; + // Calculate token amounts from liquidity const floorAmounts = getAmountsForLiquidity(floorLiquidity, floorTickLower, floorTickUpper, currentTick); const anchorAmounts = getAmountsForLiquidity(anchorLiquidity, anchorTickLower, anchorTickUpper, currentTick); @@ -383,7 +387,7 @@ simulateEnhanced(headline, currentTick, floorTickLower, floorTickUpper, floorEth, floorKraiken, floorLiquidity, anchorTickLower, anchorTickUpper, anchorEth, anchorKraiken, anchorLiquidity, - discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken, discoveryLiquidity, token0isWeth, index, precedingAction); + discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken, discoveryLiquidity, token0isWeth, index, precedingAction, percentageStaked, avgTaxRate); // Add navigation buttons below const bottomNavDiv = document.createElement('div'); @@ -569,7 +573,7 @@ function simulateEnhanced(precedingAction, currentTick, floorTickLower, floorTickUpper, floorEth, floorKraiken, floorLiquidity, anchorTickLower, anchorTickUpper, anchorEth, anchorKraiken, anchorLiquidity, - discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken, discoveryLiquidity, token0isWeth, index, originalAction) { + discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken, discoveryLiquidity, token0isWeth, index, originalAction, percentageStaked = 0, avgTaxRate = 0) { // Position data structure with liquidity calculations const positions = { @@ -635,7 +639,7 @@ scenarioContainer.appendChild(chartsContainer); // Create summary panel - const summaryPanel = createSummaryPanel(positions, currentTick, token0isWeth, originalAction || precedingAction, index); + const summaryPanel = createSummaryPanel(positions, currentTick, token0isWeth, originalAction || precedingAction, index, percentageStaked, avgTaxRate); scenarioContainer.appendChild(summaryPanel); // Add to page @@ -1097,7 +1101,7 @@ }); } - function createSummaryPanel(positions, currentTick, token0isWeth, precedingAction, index) { + function createSummaryPanel(positions, currentTick, token0isWeth, precedingAction, index, percentageStaked = 0, avgTaxRate = 0) { const panel = document.createElement('div'); panel.className = 'summary-panel'; @@ -1172,6 +1176,25 @@ 1 KRAIKEN = ${kraikenPriceInEth.toExponential(3)} ETH `; grid.appendChild(priceItem); + + // Add staking metrics if available + if (percentageStaked > 0 || avgTaxRate > 0) { + const stakingItem = document.createElement('div'); + stakingItem.className = 'summary-item'; + + // Format percentageStaked (it's in 1e18 format, so divide by 1e16 to get percentage) + const stakingPercent = (percentageStaked / 1e16).toFixed(2); + + // Format avgTaxRate (also in 1e18 format, normalized to max tax rate) + const taxRatePercent = (avgTaxRate / 1e16).toFixed(2); + + stakingItem.innerHTML = ` + Staking Metrics
+ Staked: ${stakingPercent}%
+ Avg Tax Rate: ${taxRatePercent}% + `; + grid.appendChild(stakingItem); + } panel.appendChild(grid); return panel; diff --git a/onchain/improved_profitable_3601.csv b/onchain/improved_profitable_3601.csv new file mode 100644 index 0000000..40b1ac4 --- /dev/null +++ b/onchain/improved_profitable_3601.csv @@ -0,0 +1,3 @@ +Scenario,Seed,Initial Balance,Final Balance,Profit,Profit %,Discovery Reached +BullMarketOptimizer,1,152861730151649342497,165534767451273053750,12673037299623711253,8,true +BullMarketOptimizer,2,53215106468573532381,63779335616103461539,10564229147529929158,19,true diff --git a/onchain/improved_profitable_84051.csv b/onchain/improved_profitable_84051.csv new file mode 100644 index 0000000..85db56d --- /dev/null +++ b/onchain/improved_profitable_84051.csv @@ -0,0 +1,5 @@ +Scenario,Seed,Initial Balance,Final Balance,Profit,Profit %,Discovery Reached +BullMarketOptimizer,3,86868696383720927358,91094180959940828354,4225484576219900996,4,true +BullMarketOptimizer,6,77383282103079540723,78863793676376493002,1480511573296952279,1,true +BullMarketOptimizer,9,52269169078465922293,60595359746230433174,8326190667764510881,15,false +BullMarketOptimizer,11,63309771874363779531,63524232370110625118,214460495746845587,0,true diff --git a/onchain/lib/pt-v5-twab-controller b/onchain/lib/pt-v5-twab-controller index 258ab89..2992696 160000 --- a/onchain/lib/pt-v5-twab-controller +++ b/onchain/lib/pt-v5-twab-controller @@ -1 +1 @@ -Subproject commit 258ab89ee5da09a494d5721c18d27133ad844b63 +Subproject commit 29926961b2ecfa89e0f61a6d874c71b6f8e29112 diff --git a/onchain/lib/solmate b/onchain/lib/solmate index c892309..89365b8 160000 --- a/onchain/lib/solmate +++ b/onchain/lib/solmate @@ -1 +1 @@ -Subproject commit c892309933b25c03d32b1b0d674df7ae292ba925 +Subproject commit 89365b880c4f3c786bdd453d4b8e8fe410344a69