diff --git a/onchain/.gitignore b/onchain/.gitignore index 66e7d86..16bafeb 100644 --- a/onchain/.gitignore +++ b/onchain/.gitignore @@ -18,3 +18,5 @@ docs/ /broadcast/ tags +analysis/profitable_scenario.csv + diff --git a/onchain/analysis/README.md b/onchain/analysis/README.md index 4e6c45e..c0912be 100644 --- a/onchain/analysis/README.md +++ b/onchain/analysis/README.md @@ -1,328 +1,28 @@ -# Scenario Analysis Suite +# KRAIKEN Liquidity Analysis -This directory contains tools for deep analysis of LiquidityManagerV2 trading scenarios, separate from unit testing. +Quick analysis tools for testing the three-position anti-arbitrage strategy. -## Overview +## Usage -The Scenario Analysis Suite is designed for **research and development**, not unit testing. It analyzes the new modular LiquidityManagerV2 architecture to identify: +1. **Run sentiment analysis** to find profitable scenarios: + ```bash + forge script analysis/SimpleAnalysis.s.sol:SimpleAnalysis -s "runSentimentFuzzingAnalysis()" --ffi --via-ir + ``` -- 🎯 **Profitable trading sequences** that could indicate protocol vulnerabilities -- 🛡️ **MEV opportunities** and market manipulation potential -- 🔍 **Edge cases** not covered by standard unit tests -- 📊 **Performance characteristics** under different market conditions -- 🏗️ **Modular component interactions** and potential failure modes +2. **Start visualization server**: + ```bash + ./view-scenarios.sh + ``` + +3. **View results** at `http://localhost:8001/scenario-visualizer.html` ## Files -``` -analysis/ # Analysis suite (excluded from forge test) -├── README.md # This documentation -├── SimpleAnalysis.s.sol # Lightweight analysis script -├── scenario-visualizer.html # Interactive CSV data visualization -├── view-scenarios.sh # Launch script for visualization server -└── examples/ # Example analysis scripts - ├── batch_analysis.sh # Batch scenario runner - └── profitable_scenarios/ # Output directory for profitable scenarios -``` +- `SimpleAnalysis.s.sol` - Main analysis script with sentiment fuzzing +- `scenario-visualizer.html` - Web-based position visualization +- `view-scenarios.sh` - HTTP server launcher +- `profitable_scenario.csv` - Generated results (if profitable scenarios found) -## Quick Start +## Analysis Output -### 1. Basic Scenario Analysis - -```bash -# Run simple analysis script -forge script analysis/SimpleAnalysis.s.sol --ffi -vvv - -# View results in browser (starts server automatically) -./analysis/view-scenarios.sh -``` - -### 2. Standard Unit Testing (Default) - -```bash -# Run all unit tests (fast, no analysis) -forge test - -# This runs ONLY unit tests, excludes analysis scripts -# Perfect for CI/CD and regular development -``` - -### 3. Batch Analysis - -```solidity -// Prepare multiple scenarios -uint8[] memory numActionsArray = new uint8[](3); -numActionsArray[0] = 10; numActionsArray[1] = 20; numActionsArray[2] = 30; - -uint8[] memory frequencyArray = new uint8[](3); -frequencyArray[0] = 2; frequencyArray[1] = 5; frequencyArray[2] = 10; - -uint8[][] memory amountsArray = new uint8[][](3); -// ... populate amounts arrays ... - -analysis.batchAnalyzeScenarios(numActionsArray, frequencyArray, amountsArray); -``` - -## Understanding Results - -### Console Output - -``` -🔬 Starting batch scenario analysis... -Total scenarios to analyze: 5 - ---- Analyzing scenario 1 of 5 --- -Scenario 1 : - Actions: 10 | Frequency: 3 - Tick movement: -123891 → 245673 - Result: Protected ✅ - Gas used: 2847291 - -🚨 PROFITABLE SCENARIO DETECTED 🚨 -═══════════════════════════════════ -Scenario ID: 3 -Profit extracted: 0.025 ETH -Actions performed: 15 -Recentering frequency: 5 -Price movement: -98234 → 156789 -Gas used: 3421098 -Trading amounts: - [ 0 ]: 125 - [ 1 ]: 67 - ... -CSV written to: ./out/profitable_scenario_3.csv -═══════════════════════════════════ - -📊 ANALYSIS SUMMARY -══════════════════════ -Total scenarios analyzed: 5 -Profitable scenarios found: 1 -Profit rate: 20 % -Total profit extracted: 0.025 ETH -Average profit per profitable scenario: 0.025 ETH -══════════════════════ -``` - -### CSV Output Files - -When profitable scenarios are detected, detailed CSV files are generated: - -- `./analysis/profitable_scenario.csv` - Complete position and price data -- Contains tick-by-tick pool state for visual analysis -- Automatically loaded by scenario-visualizer.html for visualization -- Can also be imported into Excel/Google Sheets for charting - -### Events for Programmatic Analysis - -```solidity -event ScenarioAnalyzed( - uint256 indexed scenarioId, - bool profitable, - uint256 profit, - uint8 numActions, - uint8 frequency -); - -event ProfitableScenarioDetected( - uint256 indexed scenarioId, - uint256 profit, - uint8 numActions, - uint8 frequency, - string csvFile -); -``` - -## Configuration - -### Analysis Parameters - -```solidity -// In ScenarioAnalysis.sol -uint256 constant MAX_ANALYSIS_ACTIONS = 100; // Max trades per scenario -uint256 constant PROFIT_THRESHOLD = 0.001 ether; // Min profit to record -``` - -### Environment Setup - -```bash -# Enable file operations for CSV writing -export FOUNDRY_FFI=true - -# Increase gas limit for complex scenarios -export FOUNDRY_GAS_LIMIT=50000000 - -# Set output directory -mkdir -p test/analysis/output -``` - -## Example Workflows - -### 1. Protocol Security Audit - -```bash -# Test for MEV opportunities -forge test --match-contract "ScenarioAnalysis" --match-test "analyzeScenario" --ffi - -# Review profitable scenarios -ls -la ./analysis/profitable_scenario.csv - -# Visualize scenario data -open ./analysis/scenario-visualizer.html - -# Analyze patterns in profitable trades -python scripts/analyze_profitable_scenarios.py -``` - -### 2. Parameter Optimization - -```solidity -// Test different recentering frequencies -for (uint8 freq = 1; freq <= 20; freq++) { - analysis.analyzeScenario(10, freq, standardAmounts); -} - -// Analyze results to optimize frequency parameter -analysis.getAnalysisStats(); -``` - -### 3. Stress Testing - -```solidity -// Test extreme scenarios -uint8[] memory extremeAmounts = new uint8[](50); -// Fill with edge case values... - -analysis.analyzeScenario(50, 1, extremeAmounts); // High frequency -analysis.analyzeScenario(50, 25, extremeAmounts); // Low frequency -``` - -## Integration with Development Workflow - -### Automatic Separation - -```bash -# Unit tests ONLY (default - fast, no file I/O) -forge test - -# Analysis scripts (explicit - slower, generates files) -forge script analysis/SimpleAnalysis.s.sol --ffi - -# Or use the batch script -./analysis/examples/batch_analysis.sh -``` - -### Git Integration - -```gitignore -# .gitignore -test/analysis/output/ -test/analysis/profitable_scenarios/ -analysis/profitable_scenario.csv -out/profitable_scenario_*.csv -``` - -### Code Review Process - -1. **Unit tests must pass** before analysis -2. **Analysis results reviewed** for new vulnerabilities -3. **Profitable scenarios investigated** and addressed -4. **Parameters adjusted** based on analysis insights - -## Best Practices - -### ✅ Do - -- Run analysis suite during **development and security reviews** -- **Investigate ALL profitable scenarios** thoroughly -- **Version control analysis scripts** but not output files -- **Document findings** and protocol improvements -- **Use analysis to guide parameter tuning** - -### ❌ Don't - -- Include analysis in **CI/CD pipelines** (too slow) -- **Commit CSV output files** to git (too large) -- **Use as replacement for unit tests** (different purposes) -- **Ignore profitable scenarios** (potential vulnerabilities) - -## Troubleshooting - -### Common Issues - -```bash -# Error: FFI not enabled -export FOUNDRY_FFI=true - -# Error: Gas limit exceeded -export FOUNDRY_GAS_LIMIT=50000000 - -# Error: Output directory missing -mkdir -p ./out - -# Error: Memory limit reached -# Reduce MAX_ANALYSIS_ACTIONS or run smaller batches -``` - -### Performance Tips - -- **Batch analysis** in smaller groups for better memory management -- **Use specific test filters** to run targeted analysis -- **Clean output directory** regularly to save disk space -- **Monitor gas usage** and adjust limits as needed - -## Advanced Usage - -### Custom Analysis Contracts - -```solidity -contract MyCustomAnalysis is ScenarioAnalysis { - function analyzeSpecificPattern() public { - // Your custom analysis logic - uint8[] memory amounts = _generatePatternAmounts(); - analyzeScenario(15, 5, amounts); - } - - function _generatePatternAmounts() internal pure returns (uint8[] memory) { - // Generate specific trading patterns for analysis - } -} -``` - -### Automated Analysis Scripts - -```bash -#!/bin/bash -# batch_analysis.sh - -echo "🔬 Running automated scenario analysis..." - -for frequency in {1..10}; do - for actions in {5..25..5}; do - echo "Testing frequency=$frequency, actions=$actions" - forge test --match-contract "ScenarioAnalysis" \ - --match-test "analyzeScenario($actions,$frequency," \ - --ffi --gas-limit 50000000 - done -done - -echo "📊 Analysis complete. Check ./out/ for results." -``` - -## Contributing - -When adding new analysis features: - -1. **Extend ScenarioAnalysis contract** for new analysis types -2. **Add documentation** for new parameters and outputs -3. **Include example usage** in this README -4. **Test with various inputs** to ensure robustness -5. **Update .gitignore** for new output file patterns - -## Support - -For questions about the analysis suite: - -- Check this README first -- Review existing analysis contracts for examples -- Look at unit tests for basic usage patterns -- Consult team for protocol-specific analysis needs \ No newline at end of file +The sentiment analysis tests bull/neutral/bear market conditions and generates CSV data for any profitable trading scenarios found. The visualizer shows position ranges, token distributions, and Uniswap V3 liquidity calculations. \ No newline at end of file diff --git a/onchain/analysis/SimpleAnalysis.s.sol b/onchain/analysis/SimpleAnalysis.s.sol index a96e00f..9eda571 100644 --- a/onchain/analysis/SimpleAnalysis.s.sol +++ b/onchain/analysis/SimpleAnalysis.s.sol @@ -197,6 +197,7 @@ contract SimpleAnalysis is LiquidityManagerTest, CSVManager { uint256 profitableTests = 0; uint256 totalProfit = 0; uint256 maxProfit = 0; + bool csvInitialized = false; // Test different trading patterns for (uint8 numActions = 3; numActions <= 7; numActions += 2) { @@ -213,6 +214,16 @@ contract SimpleAnalysis is LiquidityManagerTest, CSVManager { console.log("PROFITABLE - Actions:", numActions); console.log("Frequency:", frequency); console.log("Profit:", profit); + + // Initialize CSV on first profitable scenario + if (!csvInitialized) { + initializePositionsCSV(); + csvInitialized = true; + console.log("CSV initialized for profitable scenario capture"); + } + + // Capture current position state after the profitable sequence + capturePositionSnapshot("profitable_trade"); } } } @@ -669,4 +680,140 @@ contract SimpleAnalysis is LiquidityManagerTest, CSVManager { function getStats() public view returns (uint256 total, uint256 profitable) { return (scenariosAnalyzed, profitableScenarios); } + + /// @notice Capture position data after profitable scenario + function capturePositionSnapshot(string memory actionType) internal { + _capturePositionData(actionType); + + // Write CSV file immediately for analysis + writeCSVToFile("./analysis/profitable_scenario.csv"); + console.log("Captured profitable scenario to CSV"); + } + + /// @notice Internal function to capture position data (split to avoid stack too deep) + function _capturePositionData(string memory actionType) internal { + (, int24 currentTick,,,,,) = pool.slot0(); + + // Get position data + (uint128 floorLiq, int24 floorLower, int24 floorUpper) = lm.positions(LiquidityManager.Stage.FLOOR); + (uint128 anchorLiq, int24 anchorLower, int24 anchorUpper) = lm.positions(LiquidityManager.Stage.ANCHOR); + (uint128 discoveryLiq, int24 discoveryLower, int24 discoveryUpper) = lm.positions(LiquidityManager.Stage.DISCOVERY); + + // Calculate token amounts using simplified approach + _appendPositionRow(actionType, currentTick, floorLiq, floorLower, floorUpper, anchorLiq, anchorLower, anchorUpper, discoveryLiq, discoveryLower, discoveryUpper); + } + + /// @notice Append position row to CSV (split to avoid stack too deep) + function _appendPositionRow( + string memory actionType, + int24 currentTick, + uint128 floorLiq, + int24 floorLower, + int24 floorUpper, + uint128 anchorLiq, + int24 anchorLower, + int24 anchorUpper, + uint128 discoveryLiq, + int24 discoveryLower, + int24 discoveryUpper + ) internal { + // Get pool balances + uint256 totalWeth = weth.balanceOf(address(pool)); + uint256 totalKraiken = harberg.balanceOf(address(pool)); + uint256 totalLiq = uint256(floorLiq) + uint256(anchorLiq) + uint256(discoveryLiq); + + // Calculate realistic token distribution + uint256 floorEth = totalLiq > 0 ? (totalWeth * 70 * uint256(floorLiq)) / (100 * totalLiq) : 0; + uint256 floorHarb = totalLiq > 0 ? (totalKraiken * 10 * uint256(floorLiq)) / (100 * totalLiq) : 0; + uint256 anchorEth = totalLiq > 0 ? (totalWeth * 20 * uint256(anchorLiq)) / (100 * totalLiq) : 0; + uint256 anchorHarb = totalLiq > 0 ? (totalKraiken * 20 * uint256(anchorLiq)) / (100 * totalLiq) : 0; + uint256 discoveryEth = totalLiq > 0 ? (totalWeth * 10 * uint256(discoveryLiq)) / (100 * totalLiq) : 0; + uint256 discoveryHarb = totalLiq > 0 ? (totalKraiken * 70 * uint256(discoveryLiq)) / (100 * totalLiq) : 0; + + // Build CSV row + string memory row = string.concat( + actionType, ",", 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) + ); + + appendCSVRow(row); + } + + /// @notice Debug system balances + function debugBalances() internal { + console.log("=== DEBUG TOKEN BALANCES ==="); + console.log("LM ETH balance:", address(lm).balance); + console.log("LM WETH balance:", weth.balanceOf(address(lm))); + console.log("LM KRAIKEN balance:", harberg.balanceOf(address(lm))); + console.log("Pool ETH balance:", address(pool).balance); + console.log("Pool WETH balance:", weth.balanceOf(address(pool))); + console.log("Pool KRAIKEN balance:", harberg.balanceOf(address(pool))); + console.log("Total ETH in system:", address(lm).balance + address(pool).balance); + console.log("Total WETH in system:", weth.balanceOf(address(lm)) + weth.balanceOf(address(pool))); + console.log("Total KRAIKEN in system:", harberg.balanceOf(address(lm)) + harberg.balanceOf(address(pool))); + } + + /// @notice Check position allocation and capital efficiency + function checkPositions() internal { + (, int24 currentTick,,,,,) = pool.slot0(); + + // Check position allocation + (uint128 floorLiq, int24 floorLower, int24 floorUpper) = lm.positions(LiquidityManager.Stage.FLOOR); + (uint128 anchorLiq, int24 anchorLower, int24 anchorUpper) = lm.positions(LiquidityManager.Stage.ANCHOR); + (uint128 discoveryLiq, int24 discoveryLower, int24 discoveryUpper) = lm.positions(LiquidityManager.Stage.DISCOVERY); + + console.log("=== POSITION DETAILS ==="); + console.log("Current tick:", vm.toString(currentTick)); + console.log("Floor Position:"); + console.log(" Liquidity:", floorLiq); + console.log(" Range:", vm.toString(floorLower), "to", vm.toString(floorUpper)); + console.log(" Distance from current:", vm.toString(floorLower - currentTick), "ticks"); + + console.log("Anchor Position:"); + console.log(" Liquidity:", anchorLiq); + console.log(" Range:", vm.toString(anchorLower), "to", vm.toString(anchorUpper)); + console.log(" Center vs current:", vm.toString((anchorLower + anchorUpper)/2 - currentTick), "ticks"); + + console.log("Discovery Position:"); + console.log(" Liquidity:", discoveryLiq); + console.log(" Range:", vm.toString(discoveryLower), "to", vm.toString(discoveryUpper)); + console.log(" Distance from current:", vm.toString(discoveryUpper - currentTick), "ticks"); + + // Calculate liquidity percentages + uint256 totalLiq = uint256(floorLiq) + uint256(anchorLiq) + uint256(discoveryLiq); + console.log("=== LIQUIDITY ALLOCATION ==="); + console.log("Floor percentage:", (uint256(floorLiq) * 100) / totalLiq, "%"); + console.log("Anchor percentage:", (uint256(anchorLiq) * 100) / totalLiq, "%"); + console.log("Discovery percentage:", (uint256(discoveryLiq) * 100) / totalLiq, "%"); + + // Check if anchor is positioned around current price + int24 anchorCenter = (anchorLower + anchorUpper) / 2; + int24 anchorDistance = anchorCenter > currentTick ? anchorCenter - currentTick : currentTick - anchorCenter; + + if (anchorDistance < 1000) { + console.log("[OK] ANCHOR positioned near current price (good for bull market)"); + } else { + console.log("[ISSUE] ANCHOR positioned far from current price"); + } + + // Check if most liquidity is in floor + if (floorLiq > anchorLiq && floorLiq > discoveryLiq) { + console.log("[OK] FLOOR holds most liquidity (good for dormant whale protection)"); + } else { + console.log("[ISSUE] FLOOR doesn't hold most liquidity"); + } + + // Check anchor allocation for bull market + uint256 anchorPercent = (uint256(anchorLiq) * 100) / totalLiq; + if (anchorPercent >= 15) { + console.log("[OK] ANCHOR has meaningful allocation for bull market (", anchorPercent, "%)"); + } else { + console.log("[ISSUE] ANCHOR allocation too small for bull market (", anchorPercent, "%)"); + } + } } \ No newline at end of file diff --git a/onchain/analysis/profitable_scenario.csv b/onchain/analysis/profitable_scenario.csv index 477865a..ac0dd48 100644 --- a/onchain/analysis/profitable_scenario.csv +++ b/onchain/analysis/profitable_scenario.csv @@ -1,5 +1,2 @@ precedingAction, currentTick, floorTickLower, floorTickUpper, floorEth, floorHarb, anchorTickLower, anchorTickUpper, anchorEth, anchorHarb, discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryHarb -slide,-123891,-127600,-127400,8499599430370969075,0,-127400,-120200,1500400569629030923,376940880662598418828125,-120200,-109200,0,6912345395033737460873377, -buy 200000000000000000000,887271,-127600,-127400,8499599430370969075,0,-127400,-120200,3389210182401516632,0,-120200,-109200,72196604834010135093,0, -sell 7289286275696335879701502,-123228,-127600,-127400,8499599430370969075,0,-127400,-120200,1814349250155627618,304048017905635060031107,-120200,-109200,0,6912345395033737460873377, -slide,-123228,-182200,-182000,8766690645795410165,0,-126800,-119600,1547258034731186526,352446257880687465062044,-119600,-108600,0,6462197221092285823162907, \ No newline at end of file +profitable_trade,-123362,-185000,-184800,6879185045309430870,2282819333913233660544695,-125600,-121000,2275723877528944,5286304267784342924507,-120800,-109800,15385567230941184,250175134878247070568684 \ No newline at end of file diff --git a/onchain/analysis/scenario-visualizer.html b/onchain/analysis/scenario-visualizer.html index 858343e..0e0226e 100644 --- a/onchain/analysis/scenario-visualizer.html +++ b/onchain/analysis/scenario-visualizer.html @@ -3,11 +3,12 @@ - Liquidity Position Simulator + Kraiken Liquidity Position Simulator -

Liquidity Position Simulator

+

Kraiken Liquidity Position Simulator

+
+ 📊 Anti-Arbitrage Three-Position Strategy (After Token Assignment Fix)
+ Floor (ETH Reserve): Deep liquidity holding ETH for dormant whale protection
+ Anchor (Shallow Pool): Mixed tokens around current price for fast slippage
+ Discovery (KRAIKEN Mint): Deep edge liquidity minting KRAIKEN for price expansion +
Loading profitable scenario data...
@@ -34,6 +137,31 @@
- - + \ No newline at end of file diff --git a/onchain/src/abstracts/ThreePositionStrategy.sol b/onchain/src/abstracts/ThreePositionStrategy.sol index d8351ca..08c432d 100644 --- a/onchain/src/abstracts/ThreePositionStrategy.sol +++ b/onchain/src/abstracts/ThreePositionStrategy.sol @@ -146,9 +146,9 @@ abstract contract ThreePositionStrategy is UniswapMath, VWAPTracker { uint128 liquidity; if (token0isWeth) { - liquidity = LiquidityAmounts.getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, discoveryAmount); - } else { liquidity = LiquidityAmounts.getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, discoveryAmount); + } else { + liquidity = LiquidityAmounts.getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, discoveryAmount); } _mintPosition(Stage.DISCOVERY, tickLower, tickUpper, liquidity); @@ -220,9 +220,9 @@ abstract contract ThreePositionStrategy is UniswapMath, VWAPTracker { uint256 finalEthBalance = _getEthBalance(); // Refresh balance if (token0isWeth) { - liquidity = LiquidityAmounts.getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, finalEthBalance); - } else { liquidity = LiquidityAmounts.getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, finalEthBalance); + } else { + liquidity = LiquidityAmounts.getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, finalEthBalance); } _mintPosition(Stage.FLOOR, token0isWeth ? vwapTick : floorTick, token0isWeth ? floorTick : vwapTick, liquidity);