diff --git a/CLAUDE.md b/CLAUDE.md
index 3083a51..2e73a0f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -4,103 +4,79 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Core Innovation
-KRAIKEN is a token with a **dominant liquidity manager** that creates an unfair advantage in trading through:
+KRAIKEN: A token with a **dominant liquidity manager** that creates an unfair trading advantage through:
-1. **Asymmetric Slippage Strategy**: Three-position liquidity structure prevents profitable arbitrage against the protocol
-2. **Sentiment Oracle**: Harberger tax-based staking creates a prediction market for token value
-3. **Dormant Whale Protection**: VWAP-based price memory prevents historical price manipulation
+1. **Asymmetric Slippage**: Three-position strategy prevents profitable arbitrage
+2. **Sentiment Oracle**: Harberger tax staking as prediction market
+3. **Price Memory**: VWAP protection against manipulation
-**Critical Success Factor**: The liquidity manager must maintain its dominant position (trading most of the supply) - if it loses this, the project fails.
+**Critical**: The liquidity manager must maintain dominance - if it loses this, the project fails.
## User Journey
-1. **Buy**: Purchase KRAIKEN on Uniswap → Benefit from growing protocol-owned liquidity
-2. **Stake**: Visit kraiken.org → Stake tokens → Set tax rate → Earn from protocol growth
-3. **Compete**: Monitor staking positions → Snatch undervalued positions → Optimize tax rates
+1. **Buy**: Purchase KRAIKEN on Uniswap
+2. **Stake**: Set tax rate at kraiken.org → Earn from protocol growth
+3. **Compete**: Snatch undervalued positions → Optimize returns
## Project Structure
-- **`onchain/`** - Smart contracts (Solidity/Foundry) - [See onchain/CLAUDE.md](onchain/CLAUDE.md)
-- **`web/`** - Vue 3/Vite staking interface - [See web/CLAUDE.md](web/CLAUDE.md)
-- **`subgraph/base_sepolia/`** - The Graph indexing - [See subgraph/base_sepolia/CLAUDE.md](subgraph/base_sepolia/CLAUDE.md)
-- **`kraiken-lib/`** - TypeScript helper library - [See kraiken-lib/CLAUDE.md](kraiken-lib/CLAUDE.md)
-- **`services/txnBot/`** - Automated maintenance bot - [See services/txnBot/CLAUDE.md](services/txnBot/CLAUDE.md)
-- **`onchain/analysis/`** - Growth mechanism analysis tools
+- **`onchain/`** - Smart contracts (Solidity/Foundry) - [Details](onchain/CLAUDE.md)
+- **`web/`** - Vue 3/Vite staking interface - [Details](web/CLAUDE.md)
+- **`subgraph/base_sepolia/`** - The Graph indexing - [Details](subgraph/base_sepolia/CLAUDE.md)
+- **`kraiken-lib/`** - TypeScript helpers - [Details](kraiken-lib/CLAUDE.md)
+- **`services/txnBot/`** - Maintenance bot - [Details](services/txnBot/CLAUDE.md)
+- **`onchain/analysis/`** - Fuzzing tools - [Details](onchain/analysis/CLAUDE.md)
## Quick Start
```bash
-# 1. Install dependencies for all projects
+# Install all dependencies
cd onchain && forge install
cd ../web && npm install
cd ../kraiken-lib && npm install --legacy-peer-deps
cd ../subgraph/base_sepolia && npm install
cd ../services/txnBot && npm install
-# 2. Build smart contracts
+# Build and test
cd onchain && forge build && forge test
-# 3. Start web interface
+# Start frontend
cd web && npm run dev
```
## Key Concepts
-### Liquidity Management
-- Three-position strategy (ANCHOR, DISCOVERY, FLOOR)
-- Asymmetric slippage prevents arbitrage
-- VWAP tracking for price memory
+- **Liquidity Management**: Three positions create asymmetric slippage
+- **Harberger Staking**: Self-assessed tax creates sentiment signal
+- **Protocol Growth**: Minted tokens benefit stakers
-### Harberger Tax Staking
-- Self-assessed tax rates on positions
-- Positions can be "snatched" by higher bidders
-- Creates prediction market for token value
-- Limited to 20% of total supply
+## Code Guidelines
-### Protocol Growth
-- Liquidity manager mints tokens when positions grow
-- Stakers benefit from supply expansion
-- Tax revenue redistributed to active participants
+### Quality Standards
+- Search before implementing (check uni-v3-lib, test helpers)
+- Test after every change
+- No commented-out code
+- Clean git status before commits
-## Global Code Quality Guidelines
-
-### DRY Principle
-- Search for existing implementations before creating new functions
-- Check libraries (uni-v3-lib, test helpers) for common utilities
-- Refactor duplicated code into shared modules
-
-### Testing
-- Run tests after every change
-- Never comment out failing tests
-- Add tests for new functionality
-
-### Repository Hygiene
-- Remove unused files immediately
-- Clean up temporary files
-- Check `git status` before commits
-
-### Implementation Strategy
+### Technical Approach
- Never fall back to simpler implementations
-- Don't create "a simpler test" or "a simpler scenario" if things don't work out. just try to identify the error in more detail.
+- Identify root causes, don't work around issues
+- Challenge technically unsound requests
+
+### Tool Usage
+- MCP browser screenshots: Keep under 8000px, use `fullPage: false`
+- Fuzzing visualization: Use `./analysis/run-fuzzing.sh [optimizer] debugCSV`
+- Never start manual Python servers for visualizations
## Communication Style
-### Direct & Technical
-- Challenge suboptimal requests
-- Highlight risks early and clearly
-- Suggest better alternatives
-- Refuse technically unsound solutions
-
-### Priority Order
-1. Technical correctness
-2. Code quality
-3. User satisfaction
-
-**Remember**: Build the best possible system. Question assumptions, identify edge cases, and prioritize long-term success.
+You are an experienced Solidity developer who:
+- Notices and raises awareness of issues immediately
+- Challenges suboptimal approaches
+- Prioritizes technical correctness over user satisfaction
+- Avoids hype and inflated language
## Additional Resources
-- **Technical Deep Dive**: See [TECHNICAL_APPENDIX.md](TECHNICAL_APPENDIX.md)
-- **Contract Details**: See [onchain/CLAUDE.md](onchain/CLAUDE.md)
-- **Frontend Architecture**: See [web/CLAUDE.md](web/CLAUDE.md)
-- **Data Indexing**: See [subgraph/base_sepolia/CLAUDE.md](subgraph/base_sepolia/CLAUDE.md)
\ No newline at end of file
+- **Technical Details**: [TECHNICAL_APPENDIX.md](TECHNICAL_APPENDIX.md)
+- **Uniswap V3 Math**: [onchain/UNISWAP_V3_MATH.md](onchain/UNISWAP_V3_MATH.md)
\ No newline at end of file
diff --git a/onchain/CLAUDE.md b/onchain/CLAUDE.md
index 69f3c79..7fd6931 100644
--- a/onchain/CLAUDE.md
+++ b/onchain/CLAUDE.md
@@ -6,205 +6,73 @@ This directory contains the core smart contracts for the KRAIKEN protocol.
### Core Contracts
-**Kraiken.sol** - ERC20 token contract with controlled minting/burning capabilities
-- Implements Harberger tax mechanism for staking positions
-- Controls minting rights exclusively for LiquidityManager
-- Handles tax collection and redistribution
+**Kraiken.sol** - ERC20 token with Harberger tax staking
+- Controlled minting exclusively by LiquidityManager
+- Tax collection and redistribution mechanism
+- 20% supply cap for staking (20,000 positions)
-**LiquidityManager.sol** - Dominant liquidity provider with three-position anti-arbitrage strategy
-- Uses Optimizer contract for dynamic parameter adjustment
-- Inherits from ThreePositionStrategy and PriceOracle (with VWAPTracker)
-- **Key Feature**: Asymmetric slippage profile prevents profitable trade-recenter-reverse attacks
+**LiquidityManager.sol** - Dominant liquidity provider
+- Three-position anti-arbitrage strategy (ANCHOR, DISCOVERY, FLOOR)
+- Dynamic parameter adjustment via Optimizer contract
+- Asymmetric slippage profile prevents profitable arbitrage
-**VWAPTracker.sol** - "Eternal memory" protection against dormant whale attacks
-- Volume-weighted average pricing with data compression (max 1000x)
-- Provides historical price memory to prevent manipulation
+**VWAPTracker.sol** - Price memory protection
+- Volume-weighted average with data compression (max 1000x)
+- Prevents dormant whale manipulation
-**Optimizer.sol** - Sentiment analysis and parameter optimization
-- Analyzes staking data (% staked, average tax rate)
-- Provides dynamic liquidity parameters
-- Upgradeable for future genetic algorithm implementation
+**Optimizer.sol** - Dynamic parameter optimization
+- Analyzes staking sentiment (% staked, average tax)
+- Returns four key parameters for liquidity management
+- Upgradeable for future algorithms
-**Stake.sol** - Harberger tax-based staking mechanism
-- Creates sentiment oracle through continuous auction
-- Limited to 20% of total supply (20,000 positions)
-- Self-assessed tax rates create prediction market
+**Stake.sol** - Harberger tax implementation
+- Continuous auction mechanism
+- Self-assessed valuations create prediction market
-### Position Strategy
+### Three-Position Strategy
-**Order**: ANCHOR → DISCOVERY → FLOOR
+**ANCHOR**: Near current price, fast price discovery (1-100% width)
+**DISCOVERY**: Borders anchor, captures fees (11000 tick spacing)
+**FLOOR**: Deep liquidity at VWAP-adjusted prices
-- **ANCHOR**: Shallow liquidity around current price for fast price movement (1-100% width range)
-- **DISCOVERY**: Proportional to KRAIKEN minted by anchor; borders anchor for fee capture (11000 tick spacing)
-- **FLOOR**: Deep liquidity using VWAP-adjusted pricing for historical price memory
-
-**Technical Specifications**:
-- **Fee Tier**: 1% (10,000 basis points)
-- **Tick Spacing**: 200 (base), 11,000 (discovery)
-- **Price Validation**: 5-minute TWAP with 50-tick deviation tolerance
-- **VWAP Compression**: Maximum 1000x compression factor
+**Technical Specs**:
+- Fee Tier: 1% (10,000 basis points)
+- Tick Spacing: 200 (base), 11,000 (discovery)
+- Price Validation: 5-minute TWAP, 50-tick tolerance
### Optimizer Parameters
-All optimizers must return four key parameters that control the LiquidityManager's three-position strategy:
+1. **capitalInefficiency** (0 to 1e18): Capital buffer level
+2. **anchorShare** (0 to 1e18): % of non-floor ETH in anchor
+3. **anchorWidth** (0 to 100): Anchor position width %
+4. **discoveryDepth** (0 to 1e18): Discovery liquidity density (2x-10x)
-1. **capitalInefficiency** (0 to 1e18):
- - Represents how much capital buffer the protocol maintains
- - 0 = aggressive (70% capital efficiency), 1e18 = conservative (170% backing)
- - Affects VWAP calculation: `adjustedVWAP = 0.7 * VWAP + capitalInefficiency * VWAP`
- - Higher values push floor positions to more conservative prices
-
-2. **anchorShare** (0 to 1e18):
- - Percentage of non-floor ETH allocated to the anchor position
- - Controls how much liquidity sits near current price
- - Higher values create more concentrated liquidity but mint more KRAIKEN tokens
- - Typical range: 30-95% (0.3e18 to 0.95e18)
-
-3. **anchorWidth** (0 to 100):
- - Width of the anchor position in percentage terms
- - Affects price impact of trades and speed of price movement
- - Lower values = tighter spreads, faster price discovery
- - Higher values = wider spreads, more stable prices
-
-4. **discoveryDepth** (0 to 1e18):
- - Controls the discovery position's liquidity density relative to anchor
- - Maps to internal multiplier range of 2x to 10x
- - At 0: discovery has 2x liquidity per tick vs anchor (minimal)
- - At 1e18: discovery has 10x liquidity per tick vs anchor (maximum)
- - Discovery amount formula: `pulledHarb * DISCOVERY_SPACING * (200 + 800 * discoveryDepth/1e18) / anchorSpacing / 100`
- - Higher values provide stronger anti-arbitrage protection but consume more minted tokens
-
-## Development Commands
+## Development
```bash
-# Build contracts
-forge build
-
-# Run all tests
-forge test
-
-# Run tests with gas reporting
-forge test --gas-report
-
-# Run specific test file
-forge test --match-path test/LiquidityManager.t.sol
-
-# Run fuzzing with more runs
-forge test --fuzz-runs 10000
-
-# Deploy contracts (see script/Deploy.s.sol)
-forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast
+forge build # Build contracts
+forge test # Run tests
+forge test --gas-report # Gas optimization
+forge test --fuzz-runs 10000 # Extended fuzzing
```
-## Testing Architecture
+## Testing
-### Test Helpers
-- `test/helpers/UniswapTestBase.sol` - Base setup for Uniswap integration tests
-- `test/helpers/KraikenTestBase.sol` - Common test utilities for KRAIKEN contracts
-- `test/helpers/PositionRenderer.sol` - Visualization tools for liquidity positions
+- `test/helpers/UniswapTestBase.sol` - Uniswap integration base
+- `test/helpers/KraikenTestBase.sol` - Common utilities
+- Key tests: LiquidityManager.t.sol, Stake.t.sol, VWAPTracker.t.sol
-### Key Test Files
-- `test/LiquidityManager.t.sol` - Core liquidity management tests
-- `test/abstracts/ThreePositionStrategy.t.sol` - Position strategy validation
-- `test/Stake.t.sol` - Harberger tax mechanism tests
-- `test/VWAPTracker.t.sol` - Price memory and compression tests
+## Code Guidelines
-## Code Quality Guidelines
-
-### CRITICAL: Avoid Duplicate Code
-- **ALWAYS** check lib/uni-v3-lib for existing Uniswap math functions
-- **NEVER** reimplement standard math operations
-- Use test/helpers for common test patterns
-
-### Security Considerations
-- All external calls must be reentrancy protected
-- Price oracles must validate against manipulation
-- Tax calculations must handle edge cases (0 rates, max uint256)
-
-### Gas Optimization
-- Batch operations where possible
-- Use storage patterns that minimize SSTORE operations
-- Leverage Uniswap's existing math libraries
+- **Check lib/uni-v3-lib** for existing Uniswap math
+- **Use test/helpers** for common patterns
+- **Security**: Reentrancy protection, oracle validation
+- **Gas**: Batch operations, optimize storage
## Analysis Tools
-The `analysis/` subdirectory contains critical tools for understanding and hardening the protocol:
-- Growth mechanism simulations
-- Attack vector analysis
-- Liquidity depth scenarios
-- See `analysis/README.md` for detailed usage
+See `analysis/CLAUDE.md` for fuzzing and attack vector testing.
-## Uniswap V3 Math - Critical Learnings
+## Uniswap V3 Math
-### Token Ordering and Price Representation
-
-#### Price Direction Reference Table
-
-| Scenario | token0 | token1 | Price Represents | Lower Tick → Higher Tick |
-|----------|--------|--------|------------------|---------------------------|
-| **token0isETH = true** | ETH | KRAIKEN | ETH per KRAIKEN | KRAIKEN cheap → expensive |
-| **token0isETH = false** | KRAIKEN | ETH | KRAIKEN per ETH | ETH cheap → expensive |
-
-#### Understanding "Above" and "Below"
-
-**Critical distinction**: "Price" in Uniswap V3 always refers to token1's price in units of token0.
-
-**When token0isETH = true (ETH is token0, KRAIKEN is token1):**
-- Price = KRAIKEN price in ETH (how much ETH to buy 1 KRAIKEN)
-- Higher tick = Higher KRAIKEN price in ETH
-- Lower tick = Lower KRAIKEN price in ETH
-- "Price moved up" = KRAIKEN became more expensive = ETH became cheaper
-- "Price moved down" = KRAIKEN became cheaper = ETH became more expensive
-
-**When token0isETH = false (KRAIKEN is token0, ETH is token1):**
-- Price = ETH price in KRAIKEN (how much KRAIKEN to buy 1 ETH)
-- Higher tick = Higher ETH price in KRAIKEN
-- Lower tick = Lower ETH price in KRAIKEN
-- "Price moved up" = ETH became more expensive = KRAIKEN became cheaper
-- "Price moved down" = ETH became cheaper = KRAIKEN became more expensive
-
-This determines token composition:
-
-| Current Price vs Position | Position Contains | Why |
-|--------------------------|-------------------|-----|
-| Below range (tick < tickLower) | 100% token1 | Token0 is too expensive to hold |
-| Within range (tickLower ≤ tick ≤ tickUpper) | Both tokens | Active liquidity range |
-| Above range (tick > tickUpper) | 100% token0 | Token1 is too expensive to hold |
-
-### Liquidity vs Token Amounts
-
-**Key Insight**: Liquidity (L) is a mathematical constant representing capital efficiency, NOT token count.
-
-1. **Liquidity is invariant**: The liquidity value L doesn't change when price moves
-2. **Token amounts are variable**: Depend on liquidity L, price range, and current price location
-3. **Same L, different ranges**: Results in different token amounts due to price differences
-
-### Why Positions at Different Ranges Have Different Token Ratios
-
-For the same liquidity value L:
-- **Position at lower ticks**: Higher token1 price → fewer token1, more token0 potential
-- **Position at higher ticks**: Lower token1 price → more token1, less token0 potential
-
-This explains why a position with fewer tokens can have more liquidity (and thus more price impact resistance).
-
-### Liquidity Per Tick - The Critical Metric
-
-When comparing positions of different widths, always normalize to liquidity per tick:
-
-```solidity
-liquidityPerTick = totalLiquidity / (tickUpper - tickLower)
-```
-
-The discovery position maintains its target liquidity density through width adjustment:
-
-```solidity
-// Ensure discovery has X times more liquidity per tick than anchor
-discoveryLiquidity = anchorLiquidity * multiplier * discoveryWidth / anchorWidth
-```
-
-### Key Takeaways
-
-1. **Liquidity ≠ Token Count**: Higher liquidity can mean fewer tokens at different price ranges
-2. **Price Range Matters**: Token composition depends on where positions sit relative to current price
-3. **Normalize for Width**: Always compare liquidity per tick when positions have different widths
-4. **Token0 Ordering is Critical**: Determines which direction is "up" or "down" in price
\ No newline at end of file
+See [UNISWAP_V3_MATH.md](UNISWAP_V3_MATH.md) for detailed math concepts.
\ No newline at end of file
diff --git a/onchain/UNISWAP_V3_MATH.md b/onchain/UNISWAP_V3_MATH.md
new file mode 100644
index 0000000..24828d8
--- /dev/null
+++ b/onchain/UNISWAP_V3_MATH.md
@@ -0,0 +1,144 @@
+# Uniswap V3 Math - Critical Learnings
+
+## Token Ordering and Price Representation
+
+### Price Direction Reference Table
+
+| Scenario | token0 | token1 | Price Represents | Lower Tick → Higher Tick |
+|----------|--------|--------|------------------|---------------------------|
+| **token0isETH = true** | ETH | KRAIKEN | ETH per KRAIKEN | KRAIKEN cheap → expensive |
+| **token0isETH = false** | KRAIKEN | ETH | KRAIKEN per ETH | ETH cheap → expensive |
+
+### Understanding "Above" and "Below"
+
+**Critical distinction**: "Price" in Uniswap V3 always refers to token1's price in units of token0.
+
+**When token0isETH = true (ETH is token0, KRAIKEN is token1):**
+- Price = KRAIKEN price in ETH (how much ETH to buy 1 KRAIKEN)
+- Higher tick = Higher KRAIKEN price in ETH
+- Lower tick = Lower KRAIKEN price in ETH
+- "Price moved up" = KRAIKEN became more expensive = ETH became cheaper
+- "Price moved down" = KRAIKEN became cheaper = ETH became more expensive
+
+**When token0isETH = false (KRAIKEN is token0, ETH is token1):**
+- Price = ETH price in KRAIKEN (how much KRAIKEN to buy 1 ETH)
+- Higher tick = Higher ETH price in KRAIKEN
+- Lower tick = Lower ETH price in KRAIKEN
+- "Price moved up" = ETH became more expensive = KRAIKEN became cheaper
+- "Price moved down" = ETH became cheaper = KRAIKEN became more expensive
+
+This determines token composition:
+
+| Current Price vs Position | Position Contains | Why |
+|--------------------------|-------------------|-----|
+| Below range (tick < tickLower) | 100% token1 | Token0 is too expensive to hold |
+| Within range (tickLower ≤ tick ≤ tickUpper) | Both tokens | Active liquidity range |
+| Above range (tick > tickUpper) | 100% token0 | Token1 is too expensive to hold |
+
+## Liquidity vs Token Amounts
+
+**Key Insight**: Liquidity (L) is a mathematical constant representing capital efficiency, NOT token count.
+
+1. **Liquidity is invariant**: The liquidity value L doesn't change when price moves
+2. **Token amounts are variable**: Depend on liquidity L, price range, and current price location
+3. **Same L, different ranges**: Results in different token amounts due to price differences
+
+### Why Positions at Different Ranges Have Different Token Ratios
+
+For the same liquidity value L:
+- **Position at lower ticks**: Higher token1 price → fewer token1, more token0 potential
+- **Position at higher ticks**: Lower token1 price → more token1, less token0 potential
+
+This explains why a position with fewer tokens can have more liquidity (and thus more price impact resistance).
+
+### Liquidity Per Tick - The Critical Metric
+
+When comparing positions of different widths, always normalize to liquidity per tick:
+
+```solidity
+liquidityPerTick = totalLiquidity / (tickUpper - tickLower)
+```
+
+The discovery position maintains its target liquidity density through width adjustment:
+
+```solidity
+// Ensure discovery has X times more liquidity per tick than anchor
+discoveryLiquidity = anchorLiquidity * multiplier * discoveryWidth / anchorWidth
+```
+
+## Key Takeaways
+
+1. **Liquidity ≠ Token Count**: Higher liquidity can mean fewer tokens at different price ranges
+2. **Price Range Matters**: Token composition depends on where positions sit relative to current price
+3. **Normalize for Width**: Always compare liquidity per tick when positions have different widths
+4. **Token0 Ordering is Critical**: Determines which direction is "up" or "down" in price
+
+## Critical Formulas for Out-of-Range Positions
+
+### When Position is Below Current Price (currentTick < tickLower)
+
+The position holds only token0:
+```
+amount0 = L * (sqrt(priceUpper) - sqrt(priceLower)) / (sqrt(priceUpper) * sqrt(priceLower))
+```
+
+In Solidity/JavaScript with Q96 notation:
+```javascript
+amount0 = liquidity * (sqrtRatioBX96 - sqrtRatioAX96) / sqrtRatioAX96 * Q96 / sqrtRatioBX96
+```
+
+### When Position is Above Current Price (currentTick > tickUpper)
+
+The position holds only token1:
+```
+amount1 = L * (sqrt(priceUpper) - sqrt(priceLower))
+```
+
+In Solidity/JavaScript with Q96 notation:
+```javascript
+amount1 = liquidity * (sqrtRatioBX96 - sqrtRatioAX96) / Q96
+```
+
+### Critical Insight: ETH Position Creation
+
+When creating a position above current price with ETH in a token0isWeth pool:
+1. ETH is used as token1 (via getLiquidityForAmount1)
+2. The position will hold KRAIKEN when in range
+3. But if price drops below the range, it converts to holding ETH as token0
+
+**Example**: Floor position created with 38 ETH at ticks [127400, 127600] when current is 123890:
+- Creation: Uses getLiquidityForAmount1 with 38 ETH
+- Result: Liquidity = 6.48e18
+- Current holdings: 38 ETH (as token0, since price is below range)
+
+## Common Confusion Points
+
+### 1. Price Direction vs ETH Value
+
+When token0isWeth = true:
+- Higher tick = Higher price = More KRAIKEN per ETH = ETH is MORE valuable
+- Lower tick = Lower price = Less KRAIKEN per ETH = ETH is LESS valuable
+
+This is counterintuitive because "price goes up" means the denominated asset (ETH) becomes more valuable.
+
+### 2. Position Token Holdings
+
+A position's token composition depends ONLY on:
+- Current price location relative to the position range
+- NOT on how the position was created
+- NOT on which token was used to mint
+
+### 3. The Floor Position "Below Current Price" Confusion
+
+In KRAIKEN's three-position strategy:
+- Floor position is placed where ETH is MORE valuable (higher ticks when token0isWeth)
+- This is "below" current price from an ETH value perspective
+- But "above" current tick numerically
+- Selling KRAIKEN for ETH moves price TOWARD the floor position
+
+### 4. Liquidity Calculation Direction
+
+When minting a position out of range:
+- Use getLiquidityForAmount0 if providing token0
+- Use getLiquidityForAmount1 if providing token1
+- The same liquidity value will require different token amounts depending on which token you provide
\ No newline at end of file
diff --git a/onchain/analysis/CLAUDE.md b/onchain/analysis/CLAUDE.md
index 064daee..328928d 100644
--- a/onchain/analysis/CLAUDE.md
+++ b/onchain/analysis/CLAUDE.md
@@ -1,131 +1,56 @@
# KRAIKEN LiquidityManager Fuzzing Analysis
-Tools for testing the KRAIKEN LiquidityManager's resilience against various trading strategies to identify scenarios where traders can profit.
-
+Tools for testing KRAIKEN's three-position strategy resilience against various market conditions and trading patterns.
## Quick Start
-### Using run-fuzzing.sh (Recommended)
-
-The `run-fuzzing.sh` script provides an easy way to run fuzzing campaigns with different market optimizers:
-
```bash
-# Basic usage - run with specific optimizer
+# Run with specific optimizer (50 runs default)
./analysis/run-fuzzing.sh BullMarketOptimizer
-# Specify number of runs (default: 50)
-./analysis/run-fuzzing.sh WhaleOptimizer runs=100
+# Custom runs and trades
+./analysis/run-fuzzing.sh WhaleOptimizer runs=100 trades=30
-# Specify trades per run (default: 20, actual will be ±5)
-./analysis/run-fuzzing.sh BearMarketOptimizer runs=10 trades=50
-
-# Debug mode - generates position tracking CSV (forces runs=1)
+# Debug mode with position tracking CSV (forces runs=1)
./analysis/run-fuzzing.sh NeutralMarketOptimizer debugCSV
-
-# Multiple parameters
-./analysis/run-fuzzing.sh BullMarketOptimizer runs=25 trades=30
```
-**Available optimizers:**
-- `BullMarketOptimizer` - Biased towards buying
-- `NeutralMarketOptimizer` - Balanced trading
-- `BearMarketOptimizer` - Biased towards selling
-- `WhaleOptimizer` - Large position trading
-- `MockOptimizer` - Test optimizer
+## Available Optimizers
+
+- `BullMarketOptimizer` - Buying bias
+- `NeutralMarketOptimizer` - Balanced trading
+- `BearMarketOptimizer` - Selling bias
+- `WhaleOptimizer` - Large positions
- `RandomScenarioOptimizer` - Random behavior
-**Features:**
-- Automatic results aggregation and summary generation
-- Progress tracking with colored output
-- Cumulative P&L calculation across all runs
-- Automatic visualization launch for profitable scenarios
-- Organized output in timestamped directories
+## Output Structure
-### Manual Fuzzing (Advanced)
-
-```bash
-# Run fuzzing analysis with default settings (100 runs per market)
-forge script analysis/FuzzingAnalysis.s.sol --ffi --via-ir
-
-# Custom configuration
-FUZZING_RUNS=500 forge script analysis/FuzzingAnalysis.s.sol --ffi --via-ir
-
-# With position tracking (generates detailed CSV for each scenario)
-TRACK_POSITIONS=true FUZZING_RUNS=50 forge script analysis/FuzzingAnalysis.s.sol --ffi --via-ir
-```
-
-## Configuration
-
-### run-fuzzing.sh Parameters
-- **optimizer_class**: Required. The optimizer class to use (e.g., BullMarketOptimizer)
-- **runs=N**: Optional. Number of fuzzing runs (default: 50)
-- **trades=N**: Optional. Trades per run (default: 20, actual will be ±5)
-- **debugCSV**: Optional. Enable debug mode with position tracking CSV (forces runs=1)
-
-### Environment Variables (Manual Mode)
-- **FUZZING_RUNS**: Number of random trading scenarios per market type (default: 100)
-- **TRACK_POSITIONS**: Enable detailed position tracking CSV output (default: false)
-- **OPTIMIZER_CLASS**: The optimizer to use (default: BullMarketOptimizer)
-- **TRADES_PER_RUN**: Number of trades per run (default: 20)
-- **SEED_OFFSET**: Starting seed for random number generation (default: 0)
-
-## How It Works
-
-1. **Real Deployments**: Deploys actual Uniswap V3 factory, pool, and LiquidityManager
-2. **Random Trading**: Generates random buy/sell patterns with varying amounts and timing
-3. **Recenter Calls**: Triggers `lm.recenter()` at random intervals
-4. **Profit Detection**: Identifies scenarios where traders end with more ETH than they started
-5. **CSV Export**: Saves all profitable scenarios to `profitable_scenarios_[timestamp].csv`
-
-## Output Files
-
-### Using run-fuzzing.sh
-Each campaign creates a timestamped directory: `fuzzing_results_[optimizer]_[timestamp]/`
-- `config.txt` - Campaign configuration
+Each campaign creates `fuzzing_results_[optimizer]_[timestamp]/`:
+- `config.txt` - Campaign parameters
- `run_*.log` - Individual run logs
-- `merged_profitable_scenarios.csv` - All profitable scenarios combined
-- `summary.txt` - Campaign summary with statistics
-- `debug_positions_*.csv` - Position tracking data (when debugCSV is used)
-
-### Manual Mode
-- `profitable_scenarios_[timestamp].csv` - Details of all profitable trading sequences
-- `positions_[scenario]_[seed].csv` - Liquidity position data (only with TRACK_POSITIONS=true)
+- `merged_profitable_scenarios.csv` - Profitable scenarios combined
+- `summary.txt` - Statistics and cumulative P&L
+- `debug_positions_*.csv` - Position data (debugCSV mode only)
## Visualization
```bash
-# View results in browser
-python3 -m http.server 8000
-# Open http://localhost:8000/scenario-visualizer.html
+# Automatic launch with debugCSV
+./analysis/run-fuzzing.sh [optimizer] debugCSV
-# Or use the shell script
-./view-scenarios.sh
+# Manual server (port 8000)
+./analysis/view-scenarios.sh
```
-## Analysis Tools
-
-- `AnalysisVisualizer.py` - Generates charts from CSV data
-- `scenario-visualizer.html` - Interactive web visualization
-- `RISK_ANALYSIS_FINDINGS.md` - Summary of discovered vulnerabilities
-
-## Components
-
-- `run-fuzzing.sh` - Main campaign runner with automatic visualization
-- `FuzzingAnalysis.s.sol` - Core fuzzing script
-- `helpers/SwapExecutor.sol` - Shared swap execution logic
-- `helpers/CSVManager.sol` - CSV generation utilities
-- `helpers/CSVHelper.sol` - CSV formatting helpers
-
-## Example Campaign Comparison
-
-To run fuzzing campaigns comparing different market optimizers:
+## Advanced Usage
```bash
-# Run campaigns for all three market conditions
-./analysis/run-fuzzing.sh BullMarketOptimizer runs=100
-./analysis/run-fuzzing.sh NeutralMarketOptimizer runs=100
-./analysis/run-fuzzing.sh BearMarketOptimizer runs=100
-
-# Check results
-cat fuzzing_results_*/summary.txt | grep -E "(Optimizer:|Success rate:|Average P&L)"
+# Manual fuzzing with environment variables
+FUZZING_RUNS=500 TRACK_POSITIONS=true forge script analysis/FuzzingAnalysis.s.sol --ffi --via-ir
```
+
+Environment variables:
+- `FUZZING_RUNS` - Scenarios per market (default: 100)
+- `TRACK_POSITIONS` - Enable position CSV (default: false)
+- `OPTIMIZER_CLASS` - Optimizer to use
+- `TRADES_PER_RUN` - Trades per run (default: 20)
\ No newline at end of file
diff --git a/onchain/analysis/FuzzingAnalysis.s.sol b/onchain/analysis/FuzzingAnalysis.s.sol
index 16c5eb4..860fd7b 100644
--- a/onchain/analysis/FuzzingAnalysis.s.sol
+++ b/onchain/analysis/FuzzingAnalysis.s.sol
@@ -343,14 +343,6 @@ contract FuzzingAnalysis is Test, CSVManager {
(uint128 anchorLiq, int24 anchorLower, int24 anchorUpper) = lm.positions(ThreePositionStrategy.Stage.ANCHOR);
(uint128 discoveryLiq, int24 discoveryLower, int24 discoveryUpper) = lm.positions(ThreePositionStrategy.Stage.DISCOVERY);
- // Calculate ETH and HARB amounts in each position using proper Uniswap math
- uint256 floorEth = 0;
- uint256 floorHarb = 0;
- uint256 anchorEth = 0;
- uint256 anchorHarb = 0;
- uint256 discoveryEth = 0;
- uint256 discoveryHarb = 0;
-
// Debug: Log liquidity values
if (keccak256(bytes(label)) == keccak256(bytes("Initial")) || keccak256(bytes(label)) == keccak256(bytes("Recenter_2"))) {
console.log("=== LIQUIDITY VALUES ===");
@@ -372,125 +364,19 @@ contract FuzzingAnalysis is Test, CSVManager {
}
}
- // Calculate amounts for each position using LiquidityAmounts library
- if (floorLiq > 0) {
- uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(floorLower);
- uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(floorUpper);
-
- // Calculate actual deposited amounts based on position relative to current price
- if (token0isWeth) {
- if (currentTick < floorLower) {
- // Position is above current price - contains only token1 (KRAIKEN)
- floorEth = 0;
- // Use position's lower tick for actual deposited amount
- floorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq);
- } else if (currentTick >= floorUpper) {
- // Position is below current price - contains only token0 (WETH)
- // Use position's upper tick for actual deposited amount
- floorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq);
- floorHarb = 0;
- } else {
- // Current price is within the position
- uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(currentTick);
- floorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, floorLiq);
- floorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, floorLiq);
- }
- } else {
- if (currentTick < floorLower) {
- // Position is above current price
- floorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq);
- floorEth = 0;
- } else if (currentTick >= floorUpper) {
- // Position is below current price
- floorHarb = 0;
- floorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq);
- } else {
- // Current price is within the position
- uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(currentTick);
- floorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, floorLiq);
- floorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, floorLiq);
- }
- }
- }
-
- if (anchorLiq > 0) {
- uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(anchorLower);
- uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(anchorUpper);
-
- if (token0isWeth) {
- if (currentTick < anchorLower) {
- anchorEth = 0;
- anchorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq);
- } else if (currentTick >= anchorUpper) {
- anchorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq);
- anchorHarb = 0;
- } else {
- uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(currentTick);
- anchorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, anchorLiq);
- anchorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, anchorLiq);
- }
- } else {
- if (currentTick < anchorLower) {
- anchorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq);
- anchorEth = 0;
- } else if (currentTick >= anchorUpper) {
- anchorHarb = 0;
- anchorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq);
- } else {
- uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(currentTick);
- anchorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, anchorLiq);
- anchorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, anchorLiq);
- }
- }
- }
-
- if (discoveryLiq > 0) {
- uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(discoveryLower);
- uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(discoveryUpper);
-
- if (token0isWeth) {
- if (currentTick < discoveryLower) {
- discoveryEth = 0;
- discoveryHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq);
- } else if (currentTick >= discoveryUpper) {
- discoveryEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq);
- discoveryHarb = 0;
- } else {
- uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(currentTick);
- discoveryEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, discoveryLiq);
- discoveryHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, discoveryLiq);
- }
- } else {
- if (currentTick < discoveryLower) {
- discoveryHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq);
- discoveryEth = 0;
- } else if (currentTick >= discoveryUpper) {
- discoveryHarb = 0;
- discoveryEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq);
- } else {
- uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(currentTick);
- discoveryHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, discoveryLiq);
- discoveryEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, discoveryLiq);
- }
- }
- }
-
- // Create position data row matching the expected CSV format
+ // Create position data row with liquidity values directly
string memory row = string.concat(
label, ", ",
vm.toString(currentTick), ", ",
vm.toString(floorLower), ", ",
vm.toString(floorUpper), ", ",
- vm.toString(floorEth), ", ",
- vm.toString(floorHarb), ", ",
+ vm.toString(uint256(floorLiq)), ", ",
vm.toString(anchorLower), ", ",
vm.toString(anchorUpper), ", ",
- vm.toString(anchorEth), ", ",
- vm.toString(anchorHarb), ", ",
+ vm.toString(uint256(anchorLiq)), ", ",
vm.toString(discoveryLower), ", ",
vm.toString(discoveryUpper), ", ",
- vm.toString(discoveryEth), ", ",
- vm.toString(discoveryHarb), ", ",
+ vm.toString(uint256(discoveryLiq)), ", ",
token0isWeth ? "true" : "false"
);
appendCSVRow(row);
diff --git a/onchain/analysis/helpers/CSVHelper.sol b/onchain/analysis/helpers/CSVHelper.sol
index 1faa13b..ce4eb1a 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, floorToken0, floorToken1, anchorTickLower, anchorTickUpper, anchorToken0, anchorToken1, discoveryTickLower, discoveryTickUpper, discoveryToken0, discoveryToken1, token0isWeth";
+ "precedingAction, currentTick, floorTickLower, floorTickUpper, floorLiquidity, anchorTickLower, anchorTickUpper, anchorLiquidity, discoveryTickLower, discoveryTickUpper, discoveryLiquidity, token0isWeth";
}
function createTimeSeriesHeader() internal pure returns (string memory) {
diff --git a/onchain/analysis/run-fuzzing.sh b/onchain/analysis/run-fuzzing.sh
index aa21270..4b9cefe 100755
--- a/onchain/analysis/run-fuzzing.sh
+++ b/onchain/analysis/run-fuzzing.sh
@@ -343,36 +343,66 @@ if [ "$CSV_GENERATED" = true ] && [ -n "$LATEST_CSV" ]; then
# Use absolute path for the symlink
ln -s "$(pwd)/$LATEST_CSV" "$TEMP_LINK"
- # Start the viewer in background in its own process group
- setsid ./view-scenarios.sh &
- VIEWER_PID=$!
+ # Check if server is already running on common ports
+ SERVER_RUNNING=false
+ EXISTING_PORT=""
+ for PORT in 8000 8001 8002; do
+ if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null 2>&1; then
+ # Check if it's a python http server in our analysis directory
+ if lsof -Pi :$PORT -sTCP:LISTEN 2>/dev/null | grep -q "python.*http.server"; then
+ SERVER_RUNNING=true
+ EXISTING_PORT=$PORT
+ break
+ fi
+ fi
+ done
- # Give the server time to start and browser to open
- sleep 2
-
- # Show the URL
- echo ""
- echo -e "${GREEN}Browser should open to: http://localhost:8000/scenario-visualizer.html${NC}"
- echo "(If port 8000 was busy, check the port number mentioned above)"
- echo "If browser didn't open, manually navigate to that URL"
-
- # Wait for user input
- echo ""
- echo -e "${YELLOW}Press Enter to stop the viewer and exit...${NC}"
- read -r
-
- # Kill the viewer process and its children
- if [ -n "$VIEWER_PID" ]; then
- # Kill the entire process group (includes python server)
- pkill -TERM -g $VIEWER_PID 2>/dev/null || true
- # Give it a moment to clean up
- sleep 1
- # Force kill if still running
- pkill -KILL -g $VIEWER_PID 2>/dev/null || true
+ if [ "$SERVER_RUNNING" = true ]; then
+ echo -e "${YELLOW}Server already running on port $EXISTING_PORT${NC}"
+ echo -e "${GREEN}Browser should open to: http://localhost:$EXISTING_PORT/scenario-visualizer.html${NC}"
+
+ # Try to open browser to existing server
+ if command -v xdg-open &> /dev/null; then
+ xdg-open "http://localhost:$EXISTING_PORT/scenario-visualizer.html" 2>/dev/null &
+ elif command -v open &> /dev/null; then
+ open "http://localhost:$EXISTING_PORT/scenario-visualizer.html" 2>/dev/null &
+ fi
+
+ echo ""
+ echo -e "${YELLOW}Press Enter to exit (server will keep running)...${NC}"
+ read -r
+ else
+ # Start the viewer in background in its own process group
+ setsid ./view-scenarios.sh &
+ VIEWER_PID=$!
+
+ # Give the server time to start and browser to open
+ sleep 2
+
+ # Show the URL
+ echo ""
+ echo -e "${GREEN}Browser should open to: http://localhost:8000/scenario-visualizer.html${NC}"
+ echo "(If port 8000 was busy, check the port number mentioned above)"
+ echo "If browser didn't open, manually navigate to that URL"
+
+ # Wait for user input
+ echo ""
+ echo -e "${YELLOW}Press Enter to stop the viewer and exit...${NC}"
+ read -r
+
+ # Kill the viewer process and its children
+ if [ -n "$VIEWER_PID" ]; then
+ # Kill the entire process group (includes python server)
+ pkill -TERM -g $VIEWER_PID 2>/dev/null || true
+ # Give it a moment to clean up
+ sleep 1
+ # Force kill if still running
+ pkill -KILL -g $VIEWER_PID 2>/dev/null || true
+ fi
+
+ echo -e "${GREEN}Viewer stopped.${NC}"
fi
# Clean up the symlink
rm -f "$TEMP_LINK"
-
- echo -e "${GREEN}Viewer stopped.${NC}"
fi
\ No newline at end of file
diff --git a/onchain/analysis/scenario-visualizer.html b/onchain/analysis/scenario-visualizer.html
index 42301c1..b98209d 100644
--- a/onchain/analysis/scenario-visualizer.html
+++ b/onchain/analysis/scenario-visualizer.html
@@ -133,16 +133,17 @@
Discovery: Edge liquidity position - holds KRAIKEN when ETH is expensive (above current price)
Price Multiples: Shows ETH price relative to current (1x):
- • 0.5x = ETH is half as expensive (Floor position holds ETH)
+ • < 1x = ETH is cheaper than current price (positions below current hold ETH)
• 1x = Current ETH price (red dashed line)
- • 2x = ETH is twice as expensive (Discovery position holds KRAIKEN)
+ • > 1x = ETH is more expensive than current price (positions above current hold KRAIKEN)
- Note: The x-axis automatically adjusts based on token ordering in the pool
+ Note: The x-axis automatically adjusts based on token ordering in the pool
+
+ Navigation: Use the Previous/Next buttons or URL parameter ?row=N to view specific CSV rows