harb/onchain/analysis/KRAIKEN_RESEARCH_REPORT.md
openhands b7260b2eaf chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
  AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00

19 KiB
Raw Blame History

KRAIKEN Floor & Optimizer Research Report

Period: 2026-02-04 to 2026-02-12 Branch: fix/floor-ratchet (primary), feat/optimizer-v2-validation Authors: Johann (design, direction) + Clawy (implementation, analysis)


Table of Contents

  1. Executive Summary
  2. Critical Bugs Found & Fixed
  3. Floor Drain Vulnerability
  4. VWAP Mirror Defense
  5. Parameter Space Safety Map
  6. Fee Revenue Analysis
  7. LP Competition Analysis
  8. Optimizer Evolution (V1 → V2 → V3)
  9. Staking Dynamics & Triangle Cycle
  10. Remaining Work
  11. Key Commits
  12. Appendix: Fuzzing Infrastructure

1. Executive Summary

What we discovered

The KRAIKEN LiquidityManager had two critical math bugs and a fundamental floor placement vulnerability that allowed attackers to extract 100+ ETH per attack cycle. We fixed the bugs, designed a VWAP mirror defense, mapped the entire parameter safety space, and designed a new optimizer (V3) that uses Harberger staking signals to switch between safe and aggressive configurations.

Key outcomes

  • Two critical math bugs fixed (sqrt inflation + missing supply accounting)
  • Floor drain vulnerability understood and mitigated via VWAP mirror + parameter-space defense
  • Complete 2D safety frontier mapped: only extreme configs (AS≤35%/AW=100 or AS≥50%/AW=20) are safe without HWM
  • Fee revenue fully characterized: CI has zero effect; only AS and AW matter
  • Realistic LP competition modeled: LM retains 55-65% of WETH fees with 200 ETH competing LP
  • OptimizerV3 designed: three-zone piecewise function from Harberger staking data → binary step between safe bear/bull configs
  • Bear config optimized: AS=30% AW=100 earns 48% more WETH fees than AS=10% while remaining safe

Design philosophy (Johann)

  • Transaction fees are the product — locked ETH has no value
  • No magic numbers — CI should be the risk lever
  • Fix root causes, not symptoms
  • Parameter space provides safety; no position ratchets needed

2. Critical Bugs Found & Fixed

Bug 1: sqrt inflation in _setFloorPosition (ThreePositionStrategy.sol)

Impact: Made EthScarcity permanently true, forcing floor to always use scarcity path regardless of actual ETH balance.

Root cause: The scarcity calculation used FullMath.mulDiv(sqrtVwapX96, sqrtVwapX96, FixedPoint96.Q96) which squares sqrtVwapX96, inflating requiredEthForBuyback by ~445×.

Fix: Use vwapX96 directly (already the squared value): requiredEthForBuyback = FullMath.mulDiv(outstandingSupply, vwapX96, FixedPoint96.Q96)

Bug 2: outstandingSupply() missing pool balance

Impact: outstandingSupply() only subtracted LM's own balance from total supply, but not KRK held by feeDestination and stakingPool. This inflated the supply figure, making scarcity trigger even more easily.

Fix: Subtract feeDestination and stakingPool KRK balances from outstanding supply.

Combined commit: 0e2104b. 130 tests pass after fix.

Effect: After fixing both bugs, CI works correctly as a solvency lever:

  • CI=0% → safest (floor furthest from current)
  • CI=100% → riskiest (floor closest)
  • Previously, CI had no effect because scarcity was permanently true.

3. Floor Drain Vulnerability

Attack pattern

  1. Attacker buys ~950 ETH of KRK (building position)
  2. Executes ~2000 trades with 90% sells (buybias=10)
  3. Each sell triggers a recenter that rebuilds the floor position
  4. Floor walks progressively closer to current price via ~140 recenters
  5. Final dump sweeps all floor + anchor positions → net profit +130-170 ETH

Root cause: floor = f(current_tick)

The floor position's absolute tick is always computed from the current tick:

floorTick = currentTick + distance(VWAP, CI, ...)

During sell-heavy trading, currentTick drops through recenters. Even if the VWAP distance grows, the absolute floor position still walks down because current drops faster than distance grows.

What we tried (in order)

Approach Result Why it failed/worked
Directional VWAP Reduced profits 20× Prevents VWAP dilution but doesn't prevent floor walking
VWAP bootstrap No improvement 8/10 still profitable
Anti-overlap clamp removal Regression Clamp is a correctness constraint (floor must hold WETH)
Floor ratchet on isUp Works but rejected "Bandage, not elegant" — Johann
VWAP mirror Partial Floor walks less but still walks
Mirror + wide floor No improvement Width irrelevant when attacker sweeps everything
Mirror + peak VWAP distance CI=0% safe, CI>0% leaks Distance is relative, not absolute
Mirror + floor high-water mark 135/135 safe Absolute position ratchet
Parameter space defense Works without HWM Safe configs prevent floor walking by geometry

Why HWM was removed

Johann's argument: HWM creates a one-way valve. If the optimizer changes CI during operations, HWM prevents the floor from moving back. This defeats the purpose of having CI as a risk lever. Safety should come from the parameter space, not from a position ratchet.


4. VWAP Mirror Defense

Current floor formula (no HWM, no Scarcity/Abundance branching)

floorTick = max(scarcityTick, mirrorTick, clampTick) toward KRK-cheap side

Three signals:

  • scarcityTick: from vwapX96 and ETH/supply ratio. Correct when ETH is scarce.
  • mirrorTick: currentTick + |adjustedVwapTick - currentTick| on KRK-cheap side. Reflects VWAP distance symmetrically. Uses getAdjustedVWAP(CI).
  • clampTick: minimum distance from anchor edge. anchorSpacing = 200 + (34 × 20 × AW / 100) ticks.

Key properties:

  • CI controls mirror distance through getAdjustedVWAP(CI) — no magic numbers
  • Selling naturally grows the mirror distance (current moves away from VWAP)
  • AW=100 → clamp = 7000 ticks minimum distance (provides safety floor)
  • Unified formula — no EthScarcity/EthAbundance branching

VWAP recording (directional)

  • LiquidityManager._scrapePositions(bool recordVWAP) — only records on ETH inflow
  • shouldRecordVWAP flag: compares lastRecenterTick to current tick to detect direction
  • Records anchor midpoint price weighted by WETH fees
  • Bootstrap: always records when cumulativeVolume == 0
  • Commit c97714c (directional) + ba018c4 (bootstrap)

5. Parameter Space Safety Map

2D Safe Frontier (AS × AW)

Tested 29 (AS, AW) combinations adversarially (buybias=10, 2000 trades, CI=0%). Full results in analysis/2D_FRONTIER_LOG.md and analysis/2d-frontier-results.csv.

AW=100: AS ≤ 35% safe ✅       (clamp = 7000 ticks)
AW= 90: AS ≤ 30% safe ✅       (clamp = 6320 ticks)
AW= 80: AS ≤ 30% safe ✅       (clamp = 5640 ticks)
AW= 60: ALL AS broken ❌       (clamp = 4280 ticks — too close)
AW= 40: ALL AS broken ❌       (clamp = 2920 ticks)
AW= 30: AS ≥ 80% safe ✅       (floor not under pressure with thin anchor)
AW= 20: AS ≥ 50% safe ✅       (clamp = 1560 ticks but anchor is thin)

The kill zone is AW 40-80 at most AS levels. Only extreme configurations survive adversarial attack.

Why only extremes work

Config Why safe
AS low + AW high (bear) Wide clamp (7000 ticks) prevents floor from reaching current. Thin anchor means less ETH available for attacker to trade against.
AS high + AW low (bull) Thin, concentrated anchor near current price. Floor far away with minimal ETH. Attacker can't drain deep anchor efficiently.
AS mid + AW mid Moderate anchor depth AND moderate clamp distance. Attacker can trade against enough ETH through the anchor while floor is close enough to drain.

Other parameter effects

  • CI (capitalInefficiency): Zero effect on fee revenue. Pure risk lever for floor placement. CI=0% safest.
  • DD (discoveryDepth): Zero effect on floor safety. Pure fee lever for discovery position liquidity. Tested 20/20 safe across DD 0 to 1e18 at AS=10% AW=100.
  • Staking level: r≈0 correlation with attack profitability.

6. Fee Revenue Analysis

Core finding: CI has ZERO effect on fees

Tested across CI=0%, 25%, 50%, 75%, 100% with identical results. CI only affects floor placement, which doesn't generate fees.

AS × AW fee matrix (without background LP)

Config WETH fees KRK fees Notes
AS=10% AW=100 48 W 1.3M K Best WETH per ETH
AS=30% AW=100 72 W 1.7M K Optimal bear
AS=35% AW=100 72 W 1.7M K Edge of safe zone
AS=100% AW=20 19 W 9.2M K Best KRK fees

Two opposing forces:

  • WETH fees ↑ with wider AW (more trades complete through range)
  • KRK fees ↑ with higher AS + narrower AW (concentrated liquidity captures more per-tick)

Volatility effect

High volatility → 5-8× more fees (more trading activity). Fee revenue is primarily driven by volume, not parameters.


7. LP Competition Analysis

Background LP model

BackgroundLP.sol: 5 stacked Gaussian positions at ±10/20/40/80/160 tick spacings centered on current tick. 200 ETH total (40 ETH/layer). Buys KRK from pool realistically. Rebalances every 10th recenter. Commit e008b42 + 381b1cc.

Fee retention with competition

Config WETH (no BG LP) WETH (200 ETH BG LP) Retained
AS=30% AW=100 72 W 43 W 60%
AS=35% AW=100 72 W 38 W 52%
AS=10% AW=100 48 W 28 W 58%
AS=50% AW=150 75 W 37 W 49%
AS=50% AW=200 68 W 31 W 41%
AS=100% AW=20 19 W 13 W 66%

Wider AW = more fee leakage. The LM's liquidity is spread thinner → concentrated competitor captures disproportionate share.

Real LP distribution data (Uniswap V3 mainnet, Feb 2026)

Scanned 4 small-cap pools on mainnet:

Pool #Ticks ±10sp ±50sp Avg dist Character
AZTEC/WETH 1% 9 50% 100% 15 sp Very concentrated
wTAO/USDC 1% 72 54% 85% 21 sp Moderate, long tail
wTAO/WETH 0.3% 109 5% 50% 80 sp Very spread
LQTY/WETH 0.3% 41 0% 24% 234 sp Extremely spread

Key insight: 1% fee pools (same as KRAIKEN) have more concentrated LPs (avg ~18 spacings). Our Gaussian model at avg ~62 spacings is less concentrated than typical real competition for 1% fee pools. This means our fee estimates are slightly optimistic — real competing LPs would capture somewhat more fees.

Caveat: KRAIKEN is unique. The LM owns the entire initial liquidity and rebalances every recenter. Competing LPs face a protocol-owned position that actively tracks price, which is very different from normal pools.


8. Optimizer Evolution (V1 → V2 → V3)

V1 (Original)

  • Sentiment-based: bear → high AS, bull → low AS
  • CI, DD driven by sentiment
  • Inverted: high AS in bear = deep anchor = more ETH for attacker

V2 (src/OptimizerV2.sol, commit c13d4ca)

  • CI = 0 always (no fee impact, pure safety)
  • AS: 100% (bull) → 10% (bear) — corrected inversion
  • AW: 20 (bull) → 100 (bear)
  • DD: proportional to sentiment
  • UUPS upgradeable
  • 131 tests pass

V3 (src/OptimizerV3.sol, commit 44b8510 + 94446e7)

Uses on-chain Harberger staking data to determine market phase:

Inputs: percentageStaked (0-100%), averageTaxRate (maps to index 0-29)

Tax rate array: [1, 3, 5, 8, 12, 18, 24, 30, 40, 50, 60, 80, 100, 130, 180, 250, 320, 420, 540, 700, 920, 1200, 1600, 2000, 2600, 3400, 4400, 5700, 7500, 9700]

Three zones → score 0-200:

Zone Condition Formula Meaning
A staked ≤ 39% 100 - stakedPct² × effIdx / 3600 Early filling, score ~100
B 40-91% staked max(0, 120 - 8 × effIdx) Main operating range
C >91% staked max(0, 200 - deltaS³ × effIdx / 20) Euphoria zone, cubic snap

Where effIdx = min(29, taxIdx + (taxIdx >= 14 ? 1 : 0)), deltaS = 100 - stakedPct

Score → parameters (step function):

  • Score ≤ 140 → BEAR: AS=30%, AW=100, CI=0
  • Score ≥ 160 → BULL: AS=100%, AW=20, CI=0
  • 140-160: narrow linear ramp

Parameter space distribution: 94.3% bear, 0.5% transition, 5.2% bull.

Why step function: Linear gradient through the score range would pass through vulnerable middle AW values (40-80). Step function snaps between proven-safe extremes.

Pending: Direct 2D mapping (remove score intermediate)

Johann directed removing the score variable. Score collapses useful 2D (staking%, avgTax) information into lossy 1D.

Direct rule: staked ≤ 91% → BEAR always. staked > 91% → BULL if deltaS³ × effIdx / 20 < 50, else BEAR.

At specific thresholds:

  • 97%+ staked: any tax → bull
  • 95% staked: tax ≤ 30% (idx ≤ 7) → bull
  • 92% staked: tax ≤ 3% (idx ≤ 1) → bull
  • <92%: always bear

9. Staking Dynamics & Triangle Cycle

Harberger tax mechanics

  • Tax rate = self-assessed defense price (not conviction)
  • Snatching a position requires strictly higher tax rate
  • MAX_STAKE = 20% of KRK supply
  • TAX_FLOOR_DURATION = 3 days
  • High tax erodes position exponentially — cost of defense

Triangle cycle model

The staking system naturally traces a triangle in (staking%, avgTax) space:

                    100% staked
                   /            \
                  /   BULL       \
     fill up    /   (euphoria)    \  collapse
    (bottom)   /                   \ (hypotenuse)
              /        BEAR         \
             /________________________\
           0% staked               0% staked
           low tax                 high tax

Phase 1 — Bottom edge (fill up): Staking grows 0→100%, tax starts low. Optimizer stays bear. Transitions to bull at ~95% staked.

Phase 2 — Right edge (snatching wars): 100% staked, snatching wars push average tax rate up. deltaS = 0 → score = 200 (always bull). Euphoria overwhelms tax cost.

Phase 3 — Hypotenuse (collapse): Nervous exits. High tax + declining staking → cubic term in Zone C snaps score to 0 (bear) within 4-6% staking drop. Fast transition because deltaS³ is cubic.

Game theory validates this trajectory — no agent simulation needed (Johann's direction). Incentive structures force participants through this cycle.


10. Remaining Work

Immediate

  • Refactor OptimizerV3: Remove score intermediate. Direct 2D (staking%, avgTax) → binary config.
  • Fix run-v3-step-test.sh: Parameter passing bug causes false positives (script bug, not V3 bug).
  • Complete bear AS sweep: Test AS=40-100% at AW=100 to confirm frontier. Fix PnL parsing.
  • Re-validate after V3 refactor: Run adversarial suite against refactored V3.

Deferred

  • Update PR: https://codeberg.org/johba/harb/compare/master...fix/floor-ratchet
  • Bull→bear transition testing: What happens when optimizer switches mid-cycle?
  • Test V3 with real staking scenarios end-to-end
  • Consider if bear AS can ramp with staking confidence (AS=30% base → higher as staking grows)

Won't do

  • Agent-based staking simulation — game theory argument sufficient
  • HWM / position ratchet — removed by design decision
  • New fuzzing scripts — extend existing infrastructure only

11. Key Commits

Commit Description Branch
0e2104b sqrt + outstandingSupply bugfix fix/floor-ratchet
c97714c Directional VWAP recording fix/floor-ratchet
ba018c4 VWAP bootstrap fix fix/floor-ratchet
59b30a6 Initial VWAP mirror fix/floor-ratchet
49d15f0 Revert to Version A (CI controls mirror) fix/floor-ratchet
bf92977 Floor HWM (later removed) fix/floor-ratchet
c7ea6d0 Cleanup (diagnostics, stale CSVs) fix/floor-ratchet
e008b42 Gaussian background LP feat/optimizer-v2-validation
381b1cc Realistic BG LP funding feat/optimizer-v2-validation
c13d4ca OptimizerV2 + HWM removal feat/optimizer-v2-validation
7b83dd4 BG LP rebalance fix (every 10th) feat/optimizer-v2-validation
44b8510 OptimizerV3: three-zone piecewise feat/optimizer-v2-validation
94446e7 OptimizerV3: step function feat/optimizer-v2-validation

Appendix: Fuzzing Infrastructure

Scripts

Script Purpose
analysis/run-fuzzing.sh Single-optimizer fuzzing, CSV per run
analysis/run-adversarial.sh Attack specific configs with varied strategies
analysis/run-v3-adversarial.sh Attack V3 with staking scenarios
analysis/run-v3-step-test.sh Test step function across parameter space (HAS BUG)
analysis/run-deep-search.sh Deep search across 4D parameter space
analysis/run-bglp-fee-test.sh Fee revenue with background LP competition
analysis/scan-final.py On-chain LP distribution scanner
analysis/clean-csvs.sh Clean generated CSV files

Solidity

Contract Purpose
StreamlinedFuzzing.s.sol Main fuzzing script. ConfigurableOptimizer, staking, BG LP, uncapped swaps.
ParameterSweepFuzzing.s.sol Multi-combo sweep in single execution
BullBearSweep.s.sol Deterministic bull→bear scenario
helpers/FuzzingBase.sol Shared infrastructure
helpers/BackgroundLP.sol Gaussian competing LP (5 layers, rebalances on recenters)
helpers/ConfigurableOptimizer.sol Test optimizer with env-var-driven params

Environment variables

Var Default Description
CI_VALUE 0 Capital inefficiency (0-1e18)
AS_VALUE 1e17 Anchor share (0-1e18)
AW_VALUE 20 Anchor width (0-200+)
DD_VALUE 5e17 Discovery depth (0-1e18)
BUY_BIAS 50 % of trades that are buys (0-100)
TRADES_PER_RUN 15 Trades per run
FUZZING_RUNS 1 Runs per invocation
BATCH_SEED 0 Random seed
OPTIMIZER_CLASS BullMarketOptimizer Which optimizer to use
UNCAPPED_SWAPS false Use uncapped swap amounts
BG_LP_ETH_PER_LAYER 0 ETH per BG LP layer (0 = disabled)
STAKING_LEVEL 0 Staking % (0-100)
STAKING_TAX_RATE 3 Tax rate index (0-29)

Constraints

  • 1 run per forge invocation: EVM MemoryOOG after ~2 runs of 2000 trades. Loop in shell.
  • VPS: 8GB RAM, no swap: Cargo tests OOM. Use CARGO_BUILD_JOBS=1.
  • Disk: ~50% used. Run clean-csvs.sh periodically.
  • Forge PATH: ~/.foundry/bin/forge (not in default PATH).

Data files

File Description
analysis/2D_FRONTIER_LOG.md 29-combo (AS, AW) safety frontier
analysis/2d-frontier-results.csv Machine-readable frontier data
analysis/V3_FUZZING_LOG.md V3 adversarial test results
analysis/V3_STEP_LOG.md Step function test results
analysis/FUZZING_LOG.md General fuzzing log
analysis/AS_SWEEP_LOG.md AS sweep results
analysis/PARAMETER_SEARCH_RESULTS.md 4D parameter search