diff --git a/onchain/analysis/PARAMETER_SEARCH_RESULTS.md b/onchain/analysis/PARAMETER_SEARCH_RESULTS.md
new file mode 100644
index 0000000..404f1ab
--- /dev/null
+++ b/onchain/analysis/PARAMETER_SEARCH_RESULTS.md
@@ -0,0 +1,361 @@
+# KRAIKEN Parameter Search Results
+
+## Objective
+Find optimizer parameters where the LiquidityManager NEVER loses ETH regardless of trade sequence.
+
+## Methodology
+- **Mode**: boundary
+- **Runs per parameter combination**: 5
+- **Trades per run**: 30
+- **Uncapped swaps**: true (trades push through position boundaries)
+- **Trade size range**: 20-80 ETH (vs 100 ETH LM balance)
+- **VWAP accumulation**: Environment reused across runs per combo
+- **Buy biases tested**: 80%
+- **Total combinations tested**: 252
+- **Elapsed time**: 64s
+
+### Parameters Searched
+| Parameter | Values | Description |
+|-----------|--------|-------------|
+| capitalInefficiency | 0%, 30%, 50%, 80% | Capital buffer (0=aggressive, 1e18=conservative) |
+| anchorShare | 10.0%, 20.0%, 30.0%, 40.0%, 50.0%, 70.0%, 100.0% | ETH allocation to anchor vs floor |
+| anchorWidth | 30,50,80 | Anchor position width (1-100) |
+| discoveryDepth | 20%, 50%, 100% | Discovery liquidity density |
+| buyBias | 80% | Adversarial trade mix (80=buy-heavy, 100=buy-only) |
+
+### Key Metrics
+- **Trader PnL < 0**: LM gained ETH (SAFE). Trader lost money.
+- **Trader PnL > 0**: LM lost ETH (UNSAFE). Trader extracted ETH.
+
+## Results Summary
+- **Safe combinations**: 1 / 252
+- **Unsafe combinations**: 251 / 252
+
+## UNSAFE Parameters (Trader Profited = LM Lost ETH)
+
+| CI | AnchorShare | AnchorWidth | DiscoveryDepth | BuyBias | Worst Trader PnL (ETH) |
+|-----|-------------|-------------|----------------|---------|------------------------|
+| 0% | 10.0% | 30 | 20% | 80 | +44.4865 |
+| 0% | 10.0% | 30 | 50% | 80 | +167.0544 |
+| 0% | 10.0% | 30 | 100% | 80 | +173.8168 |
+| 0% | 10.0% | 50 | 20% | 80 | +195.4837 |
+| 0% | 10.0% | 50 | 50% | 80 | +151.0647 |
+| 0% | 10.0% | 50 | 100% | 80 | +32.3425 |
+| 0% | 10.0% | 80 | 50% | 80 | +194.9101 |
+| 0% | 10.0% | 80 | 100% | 80 | +142.8975 |
+| 0% | 20.0% | 30 | 20% | 80 | +155.1874 |
+| 0% | 20.0% | 30 | 50% | 80 | +163.5719 |
+| 0% | 20.0% | 30 | 100% | 80 | +165.1913 |
+| 0% | 20.0% | 50 | 20% | 80 | +160.7820 |
+| 0% | 20.0% | 50 | 50% | 80 | +45.7948 |
+| 0% | 20.0% | 50 | 100% | 80 | +158.7578 |
+| 0% | 20.0% | 80 | 20% | 80 | +194.8064 |
+| 0% | 20.0% | 80 | 50% | 80 | +195.2834 |
+| 0% | 20.0% | 80 | 100% | 80 | +111.9274 |
+| 0% | 30.0% | 30 | 20% | 80 | +151.7137 |
+| 0% | 30.0% | 30 | 50% | 80 | +159.1207 |
+| 0% | 30.0% | 30 | 100% | 80 | +171.0853 |
+| 0% | 30.0% | 50 | 20% | 80 | +129.2839 |
+| 0% | 30.0% | 50 | 50% | 80 | +141.0922 |
+| 0% | 30.0% | 50 | 100% | 80 | +153.9969 |
+| 0% | 30.0% | 80 | 20% | 80 | +194.9104 |
+| 0% | 30.0% | 80 | 50% | 80 | +167.4619 |
+| 0% | 30.0% | 80 | 100% | 80 | +98.0605 |
+| 0% | 40.0% | 30 | 20% | 80 | +150.5747 |
+| 0% | 40.0% | 30 | 50% | 80 | +156.1247 |
+| 0% | 40.0% | 30 | 100% | 80 | +164.0883 |
+| 0% | 40.0% | 50 | 20% | 80 | +101.9849 |
+| 0% | 40.0% | 50 | 50% | 80 | +93.0508 |
+| 0% | 40.0% | 50 | 100% | 80 | +146.2112 |
+| 0% | 40.0% | 80 | 20% | 80 | +195.2850 |
+| 0% | 40.0% | 80 | 50% | 80 | +126.8223 |
+| 0% | 40.0% | 80 | 100% | 80 | +103.2776 |
+| 0% | 50.0% | 30 | 20% | 80 | +160.1651 |
+| 0% | 50.0% | 30 | 50% | 80 | +165.6169 |
+| 0% | 50.0% | 30 | 100% | 80 | +167.6367 |
+| 0% | 50.0% | 50 | 20% | 80 | +137.2574 |
+| 0% | 50.0% | 50 | 50% | 80 | +150.7772 |
+| 0% | 50.0% | 50 | 100% | 80 | +154.5785 |
+| 0% | 50.0% | 80 | 20% | 80 | +195.4837 |
+| 0% | 50.0% | 80 | 50% | 80 | +181.7083 |
+| 0% | 50.0% | 80 | 100% | 80 | +147.8093 |
+| 0% | 70.0% | 30 | 20% | 80 | +172.0906 |
+| 0% | 70.0% | 30 | 50% | 80 | +170.8340 |
+| 0% | 70.0% | 30 | 100% | 80 | +167.3951 |
+| 0% | 70.0% | 50 | 20% | 80 | +156.1362 |
+| 0% | 70.0% | 50 | 50% | 80 | +163.3642 |
+| 0% | 70.0% | 50 | 100% | 80 | +169.0484 |
+| 0% | 70.0% | 80 | 20% | 80 | +120.1484 |
+| 0% | 70.0% | 80 | 50% | 80 | +127.5211 |
+| 0% | 70.0% | 80 | 100% | 80 | +142.2562 |
+| 0% | 100.0% | 30 | 20% | 80 | +159.4093 |
+| 0% | 100.0% | 30 | 50% | 80 | +162.4528 |
+| 0% | 100.0% | 30 | 100% | 80 | +159.8911 |
+| 0% | 100.0% | 50 | 20% | 80 | +164.0498 |
+| 0% | 100.0% | 50 | 50% | 80 | +166.4621 |
+| 0% | 100.0% | 50 | 100% | 80 | +163.1331 |
+| 0% | 100.0% | 80 | 20% | 80 | +139.6734 |
+| 0% | 100.0% | 80 | 50% | 80 | +142.3217 |
+| 0% | 100.0% | 80 | 100% | 80 | +147.6998 |
+| 30% | 10.0% | 30 | 20% | 80 | +90.1073 |
+| 30% | 10.0% | 30 | 50% | 80 | +115.8428 |
+| 30% | 10.0% | 30 | 100% | 80 | +119.9304 |
+| 30% | 10.0% | 50 | 20% | 80 | +126.4138 |
+| 30% | 10.0% | 50 | 50% | 80 | +121.1845 |
+| 30% | 10.0% | 50 | 100% | 80 | +103.7924 |
+| 30% | 10.0% | 80 | 20% | 80 | +71.6892 |
+| 30% | 10.0% | 80 | 50% | 80 | +113.3565 |
+| 30% | 10.0% | 80 | 100% | 80 | +110.1272 |
+| 30% | 20.0% | 30 | 20% | 80 | +99.5726 |
+| 30% | 20.0% | 30 | 50% | 80 | +109.5590 |
+| 30% | 20.0% | 30 | 100% | 80 | +102.5265 |
+| 30% | 20.0% | 50 | 20% | 80 | +120.0764 |
+| 30% | 20.0% | 50 | 50% | 80 | +88.3542 |
+| 30% | 20.0% | 50 | 100% | 80 | +105.7466 |
+| 30% | 20.0% | 80 | 20% | 80 | +115.8770 |
+| 30% | 20.0% | 80 | 50% | 80 | +112.3954 |
+| 30% | 20.0% | 80 | 100% | 80 | +102.0245 |
+| 30% | 30.0% | 30 | 20% | 80 | +88.9205 |
+| 30% | 30.0% | 30 | 50% | 80 | +97.1584 |
+| 30% | 30.0% | 30 | 100% | 80 | +102.9767 |
+| 30% | 30.0% | 50 | 20% | 80 | +113.3466 |
+| 30% | 30.0% | 50 | 50% | 80 | +81.5380 |
+| 30% | 30.0% | 50 | 100% | 80 | +91.2719 |
+| 30% | 30.0% | 80 | 20% | 80 | +113.7442 |
+| 30% | 30.0% | 80 | 50% | 80 | +105.2492 |
+| 30% | 30.0% | 80 | 100% | 80 | +98.0605 |
+| 30% | 40.0% | 30 | 20% | 80 | +80.5371 |
+| 30% | 40.0% | 30 | 50% | 80 | +87.1861 |
+| 30% | 40.0% | 30 | 100% | 80 | +89.2654 |
+| 30% | 40.0% | 50 | 20% | 80 | +101.9849 |
+| 30% | 40.0% | 50 | 50% | 80 | +93.0508 |
+| 30% | 40.0% | 50 | 100% | 80 | +82.1692 |
+| 30% | 40.0% | 80 | 20% | 80 | +112.1467 |
+| 30% | 40.0% | 80 | 50% | 80 | +98.4444 |
+| 30% | 40.0% | 80 | 100% | 80 | +81.6585 |
+| 30% | 50.0% | 30 | 20% | 80 | +81.1150 |
+| 30% | 50.0% | 30 | 50% | 80 | +87.9297 |
+| 30% | 50.0% | 30 | 100% | 80 | +85.4227 |
+| 30% | 50.0% | 50 | 20% | 80 | +64.9790 |
+| 30% | 50.0% | 50 | 50% | 80 | +82.5178 |
+| 30% | 50.0% | 50 | 100% | 80 | +85.9601 |
+| 30% | 50.0% | 80 | 20% | 80 | +106.5547 |
+| 30% | 50.0% | 80 | 50% | 80 | +104.7799 |
+| 30% | 50.0% | 80 | 100% | 80 | +99.1856 |
+| 30% | 70.0% | 30 | 20% | 80 | +81.5207 |
+| 30% | 70.0% | 30 | 50% | 80 | +79.0134 |
+| 30% | 70.0% | 30 | 100% | 80 | +72.5387 |
+| 30% | 70.0% | 50 | 20% | 80 | +69.8455 |
+| 30% | 70.0% | 50 | 50% | 80 | +80.6623 |
+| 30% | 70.0% | 50 | 100% | 80 | +86.1583 |
+| 30% | 70.0% | 80 | 20% | 80 | +65.6840 |
+| 30% | 70.0% | 80 | 50% | 80 | +58.3039 |
+| 30% | 70.0% | 80 | 100% | 80 | +65.6792 |
+| 30% | 100.0% | 30 | 20% | 80 | +48.0308 |
+| 30% | 100.0% | 30 | 50% | 80 | +46.0619 |
+| 30% | 100.0% | 30 | 100% | 80 | +45.0256 |
+| 30% | 100.0% | 50 | 20% | 80 | +61.2679 |
+| 30% | 100.0% | 50 | 50% | 80 | +64.0892 |
+| 30% | 100.0% | 50 | 100% | 80 | +54.6580 |
+| 30% | 100.0% | 80 | 20% | 80 | +59.1616 |
+| 30% | 100.0% | 80 | 50% | 80 | +54.4745 |
+| 30% | 100.0% | 80 | 100% | 80 | +58.5477 |
+| 50% | 10.0% | 30 | 20% | 80 | +44.4865 |
+| 50% | 10.0% | 30 | 50% | 80 | +36.2061 |
+| 50% | 10.0% | 30 | 100% | 80 | +39.7368 |
+| 50% | 10.0% | 50 | 20% | 80 | +78.7116 |
+| 50% | 10.0% | 50 | 50% | 80 | +74.2340 |
+| 50% | 10.0% | 50 | 100% | 80 | +32.3425 |
+| 50% | 10.0% | 80 | 20% | 80 | +72.2638 |
+| 50% | 10.0% | 80 | 50% | 80 | +72.8687 |
+| 50% | 10.0% | 80 | 100% | 80 | +63.3909 |
+| 50% | 20.0% | 30 | 20% | 80 | +31.0651 |
+| 50% | 20.0% | 30 | 50% | 80 | +30.5473 |
+| 50% | 20.0% | 30 | 100% | 80 | +29.6514 |
+| 50% | 20.0% | 50 | 20% | 80 | +75.2892 |
+| 50% | 20.0% | 50 | 50% | 80 | +45.7948 |
+| 50% | 20.0% | 50 | 100% | 80 | +27.4948 |
+| 50% | 20.0% | 80 | 20% | 80 | +72.8613 |
+| 50% | 20.0% | 80 | 50% | 80 | +67.6330 |
+| 50% | 20.0% | 80 | 100% | 80 | +61.9827 |
+| 50% | 30.0% | 30 | 20% | 80 | +34.5388 |
+| 50% | 30.0% | 30 | 50% | 80 | +27.1038 |
+| 50% | 30.0% | 30 | 100% | 80 | +35.0315 |
+| 50% | 30.0% | 50 | 20% | 80 | +70.7938 |
+| 50% | 30.0% | 50 | 50% | 80 | +45.1601 |
+| 50% | 30.0% | 50 | 100% | 80 | +32.2557 |
+| 50% | 30.0% | 80 | 20% | 80 | +70.9767 |
+| 50% | 30.0% | 80 | 50% | 80 | +62.9839 |
+| 50% | 30.0% | 80 | 100% | 80 | +60.1060 |
+| 50% | 40.0% | 30 | 20% | 80 | +35.6779 |
+| 50% | 40.0% | 30 | 50% | 80 | +30.1036 |
+| 50% | 40.0% | 30 | 100% | 80 | +22.1643 |
+| 50% | 40.0% | 50 | 20% | 80 | +66.2748 |
+| 50% | 40.0% | 50 | 50% | 80 | +62.6375 |
+| 50% | 40.0% | 50 | 100% | 80 | +40.0414 |
+| 50% | 40.0% | 80 | 20% | 80 | +67.5835 |
+| 50% | 40.0% | 80 | 50% | 80 | +61.6885 |
+| 50% | 40.0% | 80 | 100% | 80 | +54.1124 |
+| 50% | 50.0% | 30 | 20% | 80 | +26.0875 |
+| 50% | 50.0% | 30 | 50% | 80 | +20.6095 |
+| 50% | 50.0% | 30 | 100% | 80 | +18.6159 |
+| 50% | 50.0% | 50 | 20% | 80 | +48.9952 |
+| 50% | 50.0% | 50 | 50% | 80 | +35.4577 |
+| 50% | 50.0% | 50 | 100% | 80 | +31.6740 |
+| 50% | 50.0% | 80 | 20% | 80 | +70.3513 |
+| 50% | 50.0% | 80 | 50% | 80 | +68.3633 |
+| 50% | 50.0% | 80 | 100% | 80 | +62.8821 |
+| 50% | 70.0% | 30 | 20% | 80 | +14.6729 |
+| 50% | 70.0% | 30 | 50% | 80 | +15.8832 |
+| 50% | 70.0% | 30 | 100% | 80 | +19.7497 |
+| 50% | 70.0% | 50 | 20% | 80 | +30.1163 |
+| 50% | 70.0% | 50 | 50% | 80 | +22.8615 |
+| 50% | 70.0% | 50 | 100% | 80 | +17.2041 |
+| 50% | 70.0% | 80 | 20% | 80 | +56.9112 |
+| 50% | 70.0% | 80 | 50% | 80 | +55.4916 |
+| 50% | 70.0% | 80 | 100% | 80 | +43.9963 |
+| 50% | 100.0% | 30 | 20% | 80 | +14.4888 |
+| 50% | 100.0% | 30 | 50% | 80 | +17.3528 |
+| 50% | 100.0% | 30 | 100% | 80 | +20.0627 |
+| 50% | 100.0% | 50 | 20% | 80 | +22.2027 |
+| 50% | 100.0% | 50 | 50% | 80 | +19.7685 |
+| 50% | 100.0% | 50 | 100% | 80 | +23.5007 |
+| 50% | 100.0% | 80 | 20% | 80 | +44.1949 |
+| 50% | 100.0% | 80 | 50% | 80 | +41.6010 |
+| 50% | 100.0% | 80 | 100% | 80 | +38.5527 |
+| 80% | 10.0% | 30 | 20% | 80 | +36.9053 |
+| 80% | 10.0% | 30 | 50% | 80 | +19.1955 |
+| 80% | 10.0% | 30 | 100% | 80 | +13.3382 |
+| 80% | 10.0% | 50 | 20% | 80 | +38.0580 |
+| 80% | 10.0% | 50 | 50% | 80 | +36.8523 |
+| 80% | 10.0% | 50 | 100% | 80 | +32.3425 |
+| 80% | 10.0% | 80 | 20% | 80 | +22.1459 |
+| 80% | 10.0% | 80 | 50% | 80 | +22.4193 |
+| 80% | 10.0% | 80 | 100% | 80 | +17.4677 |
+| 80% | 20.0% | 30 | 20% | 80 | +31.0651 |
+| 80% | 20.0% | 30 | 50% | 80 | +22.6756 |
+| 80% | 20.0% | 30 | 100% | 80 | +21.0613 |
+| 80% | 20.0% | 50 | 20% | 80 | +32.2943 |
+| 80% | 20.0% | 50 | 50% | 80 | +31.7863 |
+| 80% | 20.0% | 50 | 100% | 80 | +27.4948 |
+| 80% | 20.0% | 80 | 20% | 80 | +23.7564 |
+| 80% | 20.0% | 80 | 50% | 80 | +22.6200 |
+| 80% | 20.0% | 80 | 100% | 80 | +18.4964 |
+| 80% | 30.0% | 30 | 20% | 80 | +27.9013 |
+| 80% | 30.0% | 30 | 50% | 80 | +27.1038 |
+| 80% | 30.0% | 30 | 100% | 80 | +15.1672 |
+| 80% | 30.0% | 50 | 20% | 80 | +31.9832 |
+| 80% | 30.0% | 50 | 50% | 80 | +28.1646 |
+| 80% | 30.0% | 50 | 100% | 80 | +25.4829 |
+| 80% | 30.0% | 80 | 20% | 80 | +23.0357 |
+| 80% | 30.0% | 80 | 50% | 80 | +29.0780 |
+| 80% | 30.0% | 80 | 100% | 80 | +18.5361 |
+| 80% | 40.0% | 30 | 20% | 80 | +26.2602 |
+| 80% | 40.0% | 30 | 50% | 80 | +23.8902 |
+| 80% | 40.0% | 30 | 100% | 80 | +22.1643 |
+| 80% | 40.0% | 50 | 20% | 80 | +28.8204 |
+| 80% | 40.0% | 50 | 50% | 80 | +24.2234 |
+| 80% | 40.0% | 50 | 100% | 80 | +23.4347 |
+| 80% | 40.0% | 80 | 20% | 80 | +31.4300 |
+| 80% | 40.0% | 80 | 50% | 80 | +28.4225 |
+| 80% | 40.0% | 80 | 100% | 80 | +26.1570 |
+| 80% | 50.0% | 30 | 20% | 80 | +20.1297 |
+| 80% | 50.0% | 30 | 50% | 80 | +17.7192 |
+| 80% | 50.0% | 30 | 100% | 80 | +18.6159 |
+| 80% | 50.0% | 50 | 20% | 80 | +21.8346 |
+| 80% | 50.0% | 50 | 50% | 80 | +20.5705 |
+| 80% | 50.0% | 50 | 100% | 80 | +19.6272 |
+| 80% | 50.0% | 80 | 20% | 80 | +30.2614 |
+| 80% | 50.0% | 80 | 50% | 80 | +25.7402 |
+| 80% | 50.0% | 80 | 100% | 80 | +24.5946 |
+| 80% | 70.0% | 30 | 20% | 80 | +9.4713 |
+| 80% | 70.0% | 30 | 50% | 80 | +10.6575 |
+| 80% | 70.0% | 30 | 100% | 80 | +19.7497 |
+| 80% | 70.0% | 50 | 20% | 80 | +14.8283 |
+| 80% | 70.0% | 50 | 50% | 80 | +12.9254 |
+| 80% | 70.0% | 50 | 100% | 80 | +12.3710 |
+| 80% | 70.0% | 80 | 20% | 80 | +23.0548 |
+| 80% | 70.0% | 80 | 50% | 80 | +21.2336 |
+| 80% | 70.0% | 80 | 100% | 80 | +18.9539 |
+| 80% | 100.0% | 30 | 20% | 80 | +12.7994 |
+| 80% | 100.0% | 30 | 50% | 80 | +13.8975 |
+| 80% | 100.0% | 30 | 100% | 80 | +16.5736 |
+| 80% | 100.0% | 50 | 20% | 80 | +7.8091 |
+| 80% | 100.0% | 50 | 50% | 80 | +7.6161 |
+| 80% | 100.0% | 50 | 100% | 80 | +18.5219 |
+| 80% | 100.0% | 80 | 20% | 80 | +18.8946 |
+| 80% | 100.0% | 80 | 50% | 80 | +18.7205 |
+| 80% | 100.0% | 80 | 100% | 80 | +16.0340 |
+
+## SAFE Parameters
+
+All tested parameter combinations where the LM never lost ETH:
+
+### Safe Ranges by Buy Bias
+
+- **BuyBias=80%**: 1/252 safe
+
+### Top 20 Safest Combinations (most negative trader PnL = hardest to exploit)
+
+| CI | AnchorShare | AnchorWidth | DiscoveryDepth | BuyBias | Worst Trader PnL (ETH) |
+|-----|-------------|-------------|----------------|---------|------------------------|
+| 0% | 10.0% | 80 | 20% | 80 | -114.4822 |
+
+## Exploitation Mechanism
+
+### Where Trader Profit ETH Comes From
+The trader's profit WETH is extracted from the Uniswap pool's liquidity, which is backed by
+the LM's positions. Since the LM is the sole liquidity provider:
+1. Trader buys KRAIKEN: sends WETH to pool, receives KRAIKEN from LM's positions
+2. Recenter fires: LM scrapes positions, repositions at new price, mints fresh KRAIKEN
+3. Trader sells KRAIKEN: receives WETH from pool (from LM's repositioned liquidity)
+4. Net: trader extracts WETH from LM's position value
+
+This is **impermanent loss (IL)** from dynamic liquidity management. Each recenter
+repositions liquidity at the current price, "absorbing" the price impact. The trader
+exploits this by pushing price, triggering recenter, then reversing.
+
+### VWAP is NOT the Attack Vector
+VWAP tracks historical anchor prices weighted by ETH fee volume. `getAdjustedVWAP(CI)`
+returns `(70% * VWAP) + (CI * VWAP)`, which places the floor BELOW average prices
+when CI is low (bull) and ABOVE when CI is high (bear). VWAP **anchors the floor to
+history** — it is a safety mechanism that prevents the floor from chasing price up,
+not an exploitation surface.
+
+### Measurement Notes
+- **Trader PnL** is the reliable safety metric: WETH balance before vs after trading+liquidation
+- **lm_eth_delta** in the CSV uses `lm_balance + pool_WETH` as a rough proxy for total LM ETH.
+ This metric is noisy because pool WETH mixes LM position ETH with trader buy WETH in transit.
+ It is informational only — trader PnL is the authoritative signal.
+
+### Confirmed: Capped Swaps Prevent Exploitation
+With LiquidityBoundaryHelper caps enabled (production behavior): trader ALWAYS loses money.
+Capped swaps prevent the trader from pushing through position boundaries, eliminating the
+IL-based extraction. The question is whether caps restrict legitimate large trades.
+
+## Recommendations
+
+**251 of 252 tested parameter combinations are UNSAFE with uncapped swaps.**
+
+The exploitation stems from the LM acting as a repositioning market maker: each recenter
+resets position geometry around the current price, allowing a trader to repeatedly extract
+IL by moving the price and triggering repositioning.
+
+### capitalInefficiency Effect
+| CI | Unsafe Rate | Avg Trader Profit |
+|----|-------------|-------------------|
+| 0% (bull) | 98% | ~100+ ETH |
+| 30% | 100% | ~85 ETH |
+| 50% | 100% | ~40 ETH |
+| 80% (bear) | 100% | ~22 ETH |
+
+CI reduces exploitation magnitude but does not eliminate it.
+
+### Mitigation Directions (Require Code Changes)
+1. **Keep swap caps**: LiquidityBoundaryHelper prevents exploitation entirely
+2. **Recenter cooldown**: Prevent rapid buy→recenter→sell→recenter cycles
+3. **Price impact detection**: Detect when recenter is triggered by a single actor's trades
+4. **Position geometry hardening**: Widen positions to increase slippage cost of round-trips
+
+---
+*Generated: 2026-02-07*
diff --git a/onchain/analysis/ParameterSweepFuzzing.s.sol b/onchain/analysis/ParameterSweepFuzzing.s.sol
new file mode 100644
index 0000000..f0d1b4a
--- /dev/null
+++ b/onchain/analysis/ParameterSweepFuzzing.s.sol
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.19;
+
+import { Kraiken } from "../src/Kraiken.sol";
+
+import { LiquidityManager } from "../src/LiquidityManager.sol";
+import { Stake } from "../src/Stake.sol";
+import { ThreePositionStrategy } from "../src/abstracts/ThreePositionStrategy.sol";
+import { UniswapHelpers } from "../src/helpers/UniswapHelpers.sol";
+import { IWETH9 } from "../src/interfaces/IWETH9.sol";
+import { TestEnvironment } from "../test/helpers/TestBase.sol";
+
+import { ConfigurableOptimizer } from "../test/mocks/ConfigurableOptimizer.sol";
+import { SwapExecutor } from "./helpers/SwapExecutor.sol";
+import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
+import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
+import "forge-std/Script.sol";
+import "forge-std/console2.sol";
+
+/// @title ParameterSweepFuzzing
+/// @notice Runs multiple parameter combinations in a single forge execution.
+/// @dev Key design: environment is deployed ONCE per combo and reused across runs
+/// so that VWAP accumulates naturally across recenters.
+/// Swaps are uncapped by default (no LiquidityBoundaryHelper limits).
+/// LM ETH is tracked as direct balance + pool WETH (since LM is sole LP,
+/// pool WETH represents LM's deployed position ETH).
+contract ParameterSweepFuzzing is Script {
+ TestEnvironment testEnv;
+ IUniswapV3Factory factory;
+ IUniswapV3Pool pool;
+ IWETH9 weth;
+ Kraiken kraiken;
+ Stake stake;
+ LiquidityManager lm;
+ SwapExecutor swapExecutor;
+ ConfigurableOptimizer optimizer;
+ bool token0isWeth;
+
+ address trader = makeAddr("trader");
+ address fees = makeAddr("fees");
+
+ string summaryFile;
+
+ uint256 cfgBuyBias;
+ uint256 cfgTradesPerRun;
+ uint256 cfgRunsPerCombo;
+ uint256 cfgMinBuy;
+ uint256 cfgMaxBuy;
+ bool cfgUncapped;
+
+ struct RunResult {
+ uint256 lmEthInit;
+ uint256 lmEthFinal;
+ uint256 traderInitEth;
+ uint256 traderFinalEth;
+ uint256 numRecenters;
+ uint256 numBuysFailed;
+ }
+
+ function run() public {
+ cfgTradesPerRun = vm.envOr("TRADES_PER_RUN", uint256(30));
+ cfgRunsPerCombo = vm.envOr("RUNS_PER_COMBO", uint256(5));
+ cfgUncapped = vm.envOr("UNCAPPED_SWAPS", true);
+ cfgMinBuy = vm.envOr("MIN_BUY_ETH", uint256(20));
+ cfgMaxBuy = vm.envOr("MAX_BUY_ETH", uint256(80));
+ string memory tag = vm.envOr("SWEEP_TAG", string("SWEEP"));
+
+ // Parse parameter arrays from comma-separated env vars
+ uint256[] memory ciValues = _parseUintArray(vm.envOr("CI_VALUES", string("0,500000000000000000,1000000000000000000")));
+ uint256[] memory asValues = _parseUintArray(vm.envOr("AS_VALUES", string("100000000000000000,500000000000000000,1000000000000000000")));
+ uint256[] memory awValues = _parseUintArray(vm.envOr("AW_VALUES", string("30,50,80")));
+ uint256[] memory ddValues = _parseUintArray(vm.envOr("DD_VALUES", string("200000000000000000,1000000000000000000")));
+ uint256[] memory bbValues = _parseUintArray(vm.envOr("BB_VALUES", string("60,80,100")));
+
+ uint256 totalCombos = ciValues.length * asValues.length * awValues.length * ddValues.length * bbValues.length;
+ console2.log("=== Parameter Sweep ===");
+ console2.log("Combinations:", totalCombos);
+ console2.log("Runs/combo:", cfgRunsPerCombo);
+ console2.log("Trades/run:", cfgTradesPerRun);
+ console2.log("Uncapped:", cfgUncapped);
+ console2.log("Trade range (ETH):", cfgMinBuy, cfgMaxBuy);
+
+ testEnv = new TestEnvironment(fees);
+ factory = UniswapHelpers.deployUniswapFactory();
+
+ summaryFile = string(abi.encodePacked("analysis/sweep-", tag, "-summary.csv"));
+ vm.writeFile(summaryFile, "ci,anchor_share,anchor_width,discovery_depth,buy_bias,max_trader_pnl,min_trader_pnl,any_lm_loss,lm_eth_delta\n");
+
+ uint256 comboIndex = 0;
+ for (uint256 ci_i = 0; ci_i < ciValues.length; ci_i++) {
+ for (uint256 as_i = 0; as_i < asValues.length; as_i++) {
+ for (uint256 aw_i = 0; aw_i < awValues.length; aw_i++) {
+ for (uint256 dd_i = 0; dd_i < ddValues.length; dd_i++) {
+ for (uint256 bb_i = 0; bb_i < bbValues.length; bb_i++) {
+ comboIndex++;
+ _runCombo(
+ ciValues[ci_i], asValues[as_i], uint24(awValues[aw_i] > 100 ? 100 : awValues[aw_i]), ddValues[dd_i], bbValues[bb_i], comboIndex
+ );
+ }
+ }
+ }
+ }
+ }
+
+ console2.log("=== Sweep Complete ===");
+ console2.log("Results:", summaryFile);
+ }
+
+ function _runCombo(uint256 ci, uint256 as_, uint24 aw, uint256 dd, uint256 bb, uint256 comboIdx) internal {
+ // Deploy optimizer and environment ONCE per combo
+ optimizer = new ConfigurableOptimizer(ci, as_, aw, dd);
+ cfgBuyBias = bb;
+
+ // Setup environment once — VWAP accumulates across all runs
+ _setupEnvironment(comboIdx % 2 == 0);
+
+ int256 maxPnl = type(int256).min;
+ int256 minPnl = type(int256).max;
+ bool anyLoss = false;
+
+ // Track total LM ETH = direct balance + pool WETH (LM's deployed positions)
+ // address(lm).balance + weth.balanceOf(lm) is near-zero after recenter since ETH is in pool
+ uint256 lmSystemStart = _getLmSystemEth();
+
+ for (uint256 runIdx = 0; runIdx < cfgRunsPerCombo; runIdx++) {
+ RunResult memory result = _executeRun(runIdx);
+
+ int256 pnl = int256(result.traderFinalEth) - int256(result.traderInitEth);
+
+ if (pnl > maxPnl) maxPnl = pnl;
+ if (pnl < minPnl) minPnl = pnl;
+ if (pnl > 0) anyLoss = true;
+ }
+
+ uint256 lmSystemEnd = _getLmSystemEth();
+ int256 lmDelta = int256(lmSystemEnd) - int256(lmSystemStart);
+
+ // Write summary
+ string memory row = string(abi.encodePacked(vm.toString(ci), ",", vm.toString(as_), ",", vm.toString(uint256(aw)), ","));
+ row = string(abi.encodePacked(row, vm.toString(dd), ",", vm.toString(bb), ",", vm.toString(maxPnl), ","));
+ row = string(abi.encodePacked(row, vm.toString(minPnl), ",", anyLoss ? "true" : "false", ",", vm.toString(lmDelta)));
+ vm.writeLine(summaryFile, row);
+
+ // Log progress
+ if (anyLoss) {
+ console2.log("UNSAFE combo", comboIdx);
+ console2.log(" maxPnl:", maxPnl);
+ console2.log(" lmDelta:", lmDelta);
+ } else if (comboIdx % 5 == 0) {
+ console2.log("Progress:", comboIdx);
+ }
+ }
+
+ /// @notice Approximate total ETH attributable to the LM (direct balance + pool WETH)
+ /// @dev Pool WETH includes both LM position ETH and trader buy ETH in transit.
+ /// This is a rough proxy — trader PnL is the reliable safety metric.
+ function _getLmSystemEth() internal view returns (uint256) {
+ return address(lm).balance + weth.balanceOf(address(lm)) + weth.balanceOf(address(pool));
+ }
+
+ function _executeRun(uint256 runIndex) internal returns (RunResult memory result) {
+ // DON'T re-setup environment — reuse existing so VWAP accumulates
+ result.lmEthInit = _getLmSystemEth();
+
+ // Fund trader fresh each run
+ vm.deal(trader, 400 ether);
+ vm.prank(trader);
+ weth.deposit{ value: 200 ether }();
+ result.traderInitEth = weth.balanceOf(trader);
+
+ for (uint256 i = 0; i < cfgTradesPerRun; i++) {
+ if (uint256(keccak256(abi.encodePacked(runIndex, i, "recenter"))) % 3 == 0) {
+ if (_tryRecenter()) result.numRecenters++;
+ }
+
+ uint256 rand = uint256(keccak256(abi.encodePacked(runIndex, i))) % 100;
+ if (rand < cfgBuyBias) {
+ if (!_executeBuy(runIndex, i)) result.numBuysFailed++;
+ } else {
+ _executeSell(runIndex, i);
+ }
+ }
+
+ _tryRecenter();
+ _liquidateTraderHoldings();
+
+ result.lmEthFinal = _getLmSystemEth();
+ result.traderFinalEth = weth.balanceOf(trader);
+ }
+
+ function _setupEnvironment(bool wethIsToken0) internal {
+ (factory, pool, weth, kraiken, stake, lm,, token0isWeth) = testEnv.setupEnvironmentWithExistingFactory(factory, wethIsToken0, fees, address(optimizer));
+
+ swapExecutor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm, cfgUncapped);
+
+ vm.deal(address(lm), 200 ether);
+ vm.prank(address(lm));
+ weth.deposit{ value: 100 ether }();
+
+ vm.prank(fees);
+ try lm.recenter() { } catch { }
+ }
+
+ function _executeBuy(uint256 runIndex, uint256 tradeIndex) internal returns (bool) {
+ uint256 range = cfgMaxBuy - cfgMinBuy;
+ uint256 amount = (cfgMinBuy * 1 ether) + (uint256(keccak256(abi.encodePacked(runIndex, tradeIndex, "buy"))) % (range * 1 ether));
+ if (weth.balanceOf(trader) < amount) return false;
+
+ vm.startPrank(trader);
+ weth.transfer(address(swapExecutor), amount);
+ try swapExecutor.executeBuy(amount, trader) returns (uint256 actualAmount) {
+ vm.stopPrank();
+ return actualAmount > 0;
+ } catch {
+ vm.stopPrank();
+ return false;
+ }
+ }
+
+ function _executeSell(uint256 runIndex, uint256 tradeIndex) internal returns (bool) {
+ uint256 kraikenBal = kraiken.balanceOf(trader);
+ if (kraikenBal == 0) return false;
+
+ // Sell 20-80% of holdings
+ uint256 pct = 20 + (uint256(keccak256(abi.encodePacked(runIndex, tradeIndex, "sell"))) % 60);
+ uint256 amount = kraikenBal * pct / 100;
+ if (amount == 0) return false;
+
+ vm.startPrank(trader);
+ kraiken.transfer(address(swapExecutor), amount);
+ try swapExecutor.executeSell(amount, trader) returns (uint256 actualAmount) {
+ vm.stopPrank();
+ return actualAmount > 0;
+ } catch {
+ vm.stopPrank();
+ return false;
+ }
+ }
+
+ function _tryRecenter() internal returns (bool) {
+ vm.warp(block.timestamp + 1 hours);
+ vm.roll(block.number + 1);
+ vm.prank(fees);
+ try lm.recenter{ gas: 50_000_000 }() {
+ return true;
+ } catch {
+ return false;
+ }
+ }
+
+ function _liquidateTraderHoldings() internal {
+ uint256 remaining = kraiken.balanceOf(trader);
+ uint256 attempts;
+ while (remaining > 0 && attempts < 20) {
+ uint256 prev = remaining;
+ vm.startPrank(trader);
+ kraiken.transfer(address(swapExecutor), remaining);
+ try swapExecutor.executeSell(remaining, trader) returns (uint256 a) {
+ vm.stopPrank();
+ if (a == 0) break;
+ } catch {
+ vm.stopPrank();
+ break;
+ }
+
+ // Recenter between attempts to unlock more sell liquidity
+ if (attempts % 3 == 2) {
+ _tryRecenter();
+ }
+
+ remaining = kraiken.balanceOf(trader);
+ if (remaining >= prev) break;
+ unchecked {
+ attempts++;
+ }
+ }
+ }
+
+ /// @notice Parse comma-separated uint string into array
+ function _parseUintArray(string memory csv) internal pure returns (uint256[] memory) {
+ bytes memory b = bytes(csv);
+ uint256 count = 1;
+ for (uint256 i = 0; i < b.length; i++) {
+ if (b[i] == ",") count++;
+ }
+
+ uint256[] memory result = new uint256[](count);
+ uint256 idx = 0;
+ uint256 start = 0;
+
+ for (uint256 i = 0; i <= b.length; i++) {
+ if (i == b.length || b[i] == ",") {
+ uint256 num = 0;
+ for (uint256 j = start; j < i; j++) {
+ require(b[j] >= "0" && b[j] <= "9", "Invalid number");
+ num = num * 10 + (uint256(uint8(b[j])) - 48);
+ }
+ result[idx] = num;
+ idx++;
+ start = i + 1;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/onchain/analysis/StreamlinedFuzzing.s.sol b/onchain/analysis/StreamlinedFuzzing.s.sol
index 86b4c6b..2688814 100644
--- a/onchain/analysis/StreamlinedFuzzing.s.sol
+++ b/onchain/analysis/StreamlinedFuzzing.s.sol
@@ -1,25 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
+import { Kraiken } from "../src/Kraiken.sol";
+
+import { LiquidityManager } from "../src/LiquidityManager.sol";
+
+import { Optimizer } from "../src/Optimizer.sol";
+import { Stake } from "../src/Stake.sol";
+import { ThreePositionStrategy } from "../src/abstracts/ThreePositionStrategy.sol";
+import { UniswapHelpers } from "../src/helpers/UniswapHelpers.sol";
+import { IWETH9 } from "../src/interfaces/IWETH9.sol";
+import { TestEnvironment } from "../test/helpers/TestBase.sol";
+
+import { BearMarketOptimizer } from "../test/mocks/BearMarketOptimizer.sol";
+import { BullMarketOptimizer } from "../test/mocks/BullMarketOptimizer.sol";
+
+import { ExtremeOptimizer } from "../test/mocks/ExtremeOptimizer.sol";
+import { MaliciousOptimizer } from "../test/mocks/MaliciousOptimizer.sol";
+import { NeutralMarketOptimizer } from "../test/mocks/NeutralMarketOptimizer.sol";
+import { WhaleOptimizer } from "../test/mocks/WhaleOptimizer.sol";
+import { SwapExecutor } from "./helpers/SwapExecutor.sol";
+import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
+import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "forge-std/Script.sol";
import "forge-std/console2.sol";
-import {TestEnvironment} from "../test/helpers/TestBase.sol";
-import {IUniswapV3Pool} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
-import {IUniswapV3Factory} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
-import {UniswapHelpers} from "../src/helpers/UniswapHelpers.sol";
-import {IWETH9} from "../src/interfaces/IWETH9.sol";
-import {Kraiken} from "../src/Kraiken.sol";
-import {Stake} from "../src/Stake.sol";
-import {LiquidityManager} from "../src/LiquidityManager.sol";
-import {ThreePositionStrategy} from "../src/abstracts/ThreePositionStrategy.sol";
-import {SwapExecutor} from "./helpers/SwapExecutor.sol";
-import {Optimizer} from "../src/Optimizer.sol";
-import {BullMarketOptimizer} from "../test/mocks/BullMarketOptimizer.sol";
-import {BearMarketOptimizer} from "../test/mocks/BearMarketOptimizer.sol";
-import {NeutralMarketOptimizer} from "../test/mocks/NeutralMarketOptimizer.sol";
-import {WhaleOptimizer} from "../test/mocks/WhaleOptimizer.sol";
-import {ExtremeOptimizer} from "../test/mocks/ExtremeOptimizer.sol";
-import {MaliciousOptimizer} from "../test/mocks/MaliciousOptimizer.sol";
contract StreamlinedFuzzing is Script {
// Test environment
@@ -32,77 +36,101 @@ contract StreamlinedFuzzing is Script {
LiquidityManager lm;
SwapExecutor swapExecutor;
bool token0isWeth;
-
+
// Actors
address trader = makeAddr("trader");
+ address staker = makeAddr("staker");
address fees = makeAddr("fees");
-
+
// Staking tracking
- mapping(address => uint256[]) public activePositions;
- uint256[] public allPositionIds;
+ uint256[] public activePositionIds;
uint256 totalStakesAttempted;
uint256 totalStakesSucceeded;
- uint256 totalSnatchesAttempted;
- uint256 totalSnatchesSucceeded;
-
+
// CSV filename for current run
string csvFilename;
-
+
// Track cumulative fees
uint256 totalFees0;
uint256 totalFees1;
-
+
// Track recentering
uint256 lastRecenterBlock;
-
+
+ // Config
+ uint256 cfgBuyBias;
+ uint256 cfgMinBuy;
+ uint256 cfgMaxBuy;
+ bool cfgUncapped;
+
function run() public {
// Get configuration from environment
uint256 numRuns = vm.envOr("FUZZING_RUNS", uint256(20));
uint256 tradesPerRun = vm.envOr("TRADES_PER_RUN", uint256(15));
bool enableStaking = vm.envOr("ENABLE_STAKING", true);
- uint256 buyBias = vm.envOr("BUY_BIAS", uint256(50));
+ cfgBuyBias = vm.envOr("BUY_BIAS", uint256(50));
uint256 stakingBias = vm.envOr("STAKING_BIAS", uint256(80));
string memory optimizerClass = vm.envOr("OPTIMIZER_CLASS", string("BullMarketOptimizer"));
-
+ cfgUncapped = vm.envOr("UNCAPPED_SWAPS", true);
+ cfgMinBuy = vm.envOr("MIN_BUY_ETH", uint256(20));
+ cfgMaxBuy = vm.envOr("MAX_BUY_ETH", uint256(80));
+
console2.log("=== Streamlined Fuzzing Analysis ===");
console2.log("Optimizer:", optimizerClass);
-
- // Deploy factory once for all runs (gas optimization)
+ console2.log("Uncapped swaps:", cfgUncapped);
+ console2.log("Trade range (ETH):", cfgMinBuy, cfgMaxBuy);
+
+ // Deploy factory once
testEnv = new TestEnvironment(fees);
factory = UniswapHelpers.deployUniswapFactory();
-
+
// Generate unique 4-character scenario ID
string memory scenarioCode = _generateScenarioId();
-
- // Run fuzzing scenarios
+
+ // Setup environment ONCE — all runs share it so VWAP accumulates
+ _setupEnvironment(optimizerClass, true);
+
+ // Track LM ETH across the entire session
+ uint256 lmEthStart = address(lm).balance + weth.balanceOf(address(lm)) + weth.balanceOf(address(pool));
+ console2.log("LM starting ETH:", lmEthStart / 1e18, "ETH");
+
+ // Run fuzzing scenarios — same environment, VWAP carries over
for (uint256 runIndex = 0; runIndex < numRuns; runIndex++) {
string memory runId = string(abi.encodePacked(scenarioCode, "-", _padNumber(runIndex, 3)));
console2.log("\nRun:", runId);
-
+
// Initialize CSV file for this run
- // Always write to analysis directory relative to project root
csvFilename = string(abi.encodePacked("analysis/fuzz-", runId, ".csv"));
- string memory header = "action,amount,tick,floor_lower,floor_upper,floor_liq,anchor_lower,anchor_upper,anchor_liq,discovery_lower,discovery_upper,discovery_liq,eth_balance,kraiken_balance,vwap,fees_eth,fees_kraiken,recenter\n";
+ string memory header =
+ "action,amount,tick,floor_lower,floor_upper,floor_liq,anchor_lower,anchor_upper,anchor_liq,discovery_lower,discovery_upper,discovery_liq,eth_balance,kraiken_balance,vwap,fees_eth,fees_kraiken,recenter\n";
vm.writeFile(csvFilename, header);
-
- // Setup fresh environment for each run
- _setupEnvironment(optimizerClass, runIndex % 2 == 0);
-
- // Reset tracking variables
+
+ // Reset tracking for CSV
totalFees0 = 0;
totalFees1 = 0;
lastRecenterBlock = block.number;
-
- // Fund trader based on run seed - increased for longer campaigns
- uint256 traderFund = 500 ether + (uint256(keccak256(abi.encodePacked(runIndex, "trader"))) % 500 ether);
- vm.deal(trader, traderFund * 2);
+ // Reset trader — burn any leftover WETH/ETH from previous run
+ uint256 leftoverWeth = weth.balanceOf(trader);
+ if (leftoverWeth > 0) {
+ vm.prank(trader);
+ weth.transfer(address(0xdead), leftoverWeth);
+ }
+ uint256 leftoverKraiken = kraiken.balanceOf(trader);
+ if (leftoverKraiken > 0) {
+ vm.prank(trader);
+ kraiken.transfer(address(0xdead), leftoverKraiken);
+ }
+
+ // Fund trader fresh for this run
+ uint256 traderFund = 200 ether;
+ vm.deal(trader, traderFund);
vm.prank(trader);
- weth.deposit{value: traderFund}();
-
+ weth.deposit{ value: traderFund }();
+
// Initial state
_recordState("INIT", 0);
-
+
// Execute trades
for (uint256 i = 0; i < tradesPerRun; i++) {
// Check for recenter opportunity on average every 3 trades
@@ -110,51 +138,67 @@ contract StreamlinedFuzzing is Script {
if (recenterRand == 0) {
_tryRecenter();
}
-
+
// Determine trade based on bias
uint256 rand = uint256(keccak256(abi.encodePacked(runIndex, i))) % 100;
-
- if (rand < buyBias) {
+
+ if (rand < cfgBuyBias) {
_executeBuy(runIndex, i);
} else {
_executeSell(runIndex, i);
}
-
+
// Staking operations if enabled
- if (enableStaking && i % 3 == 0) {
+ if (enableStaking && i % 5 == 0) {
_executeStakingOperation(runIndex, i, stakingBias);
}
}
- // Final state
+ // Final recenter + liquidate
+ _tryRecenter();
_liquidateTraderHoldings();
_recordState("FINAL", 0);
+
+ // Report per-run PnL
+ uint256 traderEthNow = weth.balanceOf(trader);
+ uint256 lmEthNow = address(lm).balance + weth.balanceOf(address(lm)) + weth.balanceOf(address(pool));
+ if (traderEthNow > traderFund) {
+ console2.log(" TRADER PROFIT:", (traderEthNow - traderFund) / 1e15, "finney");
+ }
+ console2.log(" LM ETH (wei):", lmEthNow, _signedDelta(lmEthNow, lmEthStart));
}
+ uint256 lmEthEnd = address(lm).balance + weth.balanceOf(address(lm)) + weth.balanceOf(address(pool));
console2.log("\n=== Analysis Complete ===");
+ console2.log("LM ETH start:", lmEthStart / 1e18, "final (ETH):", lmEthEnd / 1e18);
+ if (lmEthEnd < lmEthStart) {
+ console2.log("LM LOST ETH:", (lmEthStart - lmEthEnd) / 1e15, "finney");
+ }
console2.log("Generated", numRuns, "CSV files with prefix:", scenarioCode);
}
-
+
+ function _signedDelta(uint256 current, uint256 start) internal pure returns (string memory) {
+ if (current >= start) {
+ return string(abi.encodePacked("+", vm.toString((current - start) / 1e15), " finney"));
+ } else {
+ return string(abi.encodePacked("-", vm.toString((start - current) / 1e15), " finney"));
+ }
+ }
+
function _setupEnvironment(string memory optimizerClass, bool wethIsToken0) internal {
- // Get optimizer address
address optimizer = _deployOptimizer(optimizerClass);
-
- // Setup new environment
- (factory, pool, weth, kraiken, stake, lm,, token0isWeth) =
- testEnv.setupEnvironmentWithExistingFactory(factory, wethIsToken0, fees, optimizer);
-
- // Deploy swap executor with liquidity boundary checks
- swapExecutor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm);
-
+
+ (factory, pool, weth, kraiken, stake, lm,, token0isWeth) = testEnv.setupEnvironmentWithExistingFactory(factory, wethIsToken0, fees, optimizer);
+
+ // Deploy swap executor — uncapped by default for exploit testing
+ swapExecutor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm, cfgUncapped);
+
// Fund liquidity manager
vm.deal(address(lm), 200 ether);
-
- // Initialize liquidity positions
- // First need to give LM some WETH
vm.prank(address(lm));
- weth.deposit{value: 100 ether}();
-
- // Now try recenter from fee destination
+ weth.deposit{ value: 100 ether }();
+
+ // Initial recenter to set positions
vm.prank(fees);
try lm.recenter() returns (bool isUp) {
console2.log("Initial recenter successful, isUp:", isUp);
@@ -163,15 +207,8 @@ contract StreamlinedFuzzing is Script {
} catch {
console2.log("Initial recenter failed with unknown error");
}
-
- // Clear staking state
- delete allPositionIds;
- totalStakesAttempted = 0;
- totalStakesSucceeded = 0;
- totalSnatchesAttempted = 0;
- totalSnatchesSucceeded = 0;
}
-
+
function _deployOptimizer(string memory optimizerClass) internal returns (address) {
if (keccak256(bytes(optimizerClass)) == keccak256(bytes("BullMarketOptimizer"))) {
return address(new BullMarketOptimizer());
@@ -186,33 +223,37 @@ contract StreamlinedFuzzing is Script {
} else if (keccak256(bytes(optimizerClass)) == keccak256(bytes("MaliciousOptimizer"))) {
return address(new MaliciousOptimizer());
} else {
- // Default to bull market
return address(new BullMarketOptimizer());
}
}
-
+
function _executeBuy(uint256 runIndex, uint256 tradeIndex) internal {
- uint256 amount = _getTradeAmount(runIndex, tradeIndex, true);
+ uint256 range = cfgMaxBuy - cfgMinBuy;
+ uint256 amount = (cfgMinBuy * 1 ether) + (uint256(keccak256(abi.encodePacked(runIndex, tradeIndex, "buy"))) % (range * 1 ether));
if (amount == 0 || weth.balanceOf(trader) < amount) return;
-
+
vm.startPrank(trader);
weth.transfer(address(swapExecutor), amount);
try swapExecutor.executeBuy(amount, trader) returns (uint256 actualAmount) {
if (actualAmount == 0) {
- console2.log("Buy returned 0, requested:", amount);
+ console2.log("Buy returned 0, requested:", amount / 1e18);
}
_recordState("BUY", actualAmount);
- } catch Error(string memory reason) {
- console2.log("Buy failed:", reason);
+ } catch {
_recordState("BUY_FAIL", amount);
}
vm.stopPrank();
}
-
+
function _executeSell(uint256 runIndex, uint256 tradeIndex) internal {
- uint256 amount = _getTradeAmount(runIndex, tradeIndex, false);
- if (amount == 0 || kraiken.balanceOf(trader) < amount) return;
-
+ uint256 kraikenBal = kraiken.balanceOf(trader);
+ if (kraikenBal == 0) return;
+
+ // Sell 20-80% of holdings
+ uint256 pct = 20 + (uint256(keccak256(abi.encodePacked(runIndex, tradeIndex, "sell"))) % 60);
+ uint256 amount = kraikenBal * pct / 100;
+ if (amount == 0) return;
+
vm.startPrank(trader);
kraiken.transfer(address(swapExecutor), amount);
try swapExecutor.executeSell(amount, trader) returns (uint256 actualAmount) {
@@ -222,33 +263,79 @@ contract StreamlinedFuzzing is Script {
}
vm.stopPrank();
}
-
- function _executeStakingOperation(uint256, uint256, uint256) internal {
- // Staking operations disabled for now - interface needs updating
- // TODO: Update to use correct Stake contract interface
+
+ function _executeStakingOperation(uint256 runIndex, uint256 tradeIndex, uint256 stakingBias) internal {
+ // Need KRAIKEN to stake — use the staker address, not the trader
+ uint256 stakerKraiken = kraiken.balanceOf(staker);
+
+ // If staker has no KRAIKEN and trader has some, transfer a small amount
+ if (stakerKraiken == 0) {
+ uint256 traderBal = kraiken.balanceOf(trader);
+ if (traderBal == 0) return;
+ uint256 toTransfer = traderBal / 10; // 10% of trader holdings
+ if (toTransfer == 0) return;
+ vm.prank(trader);
+ kraiken.transfer(staker, toTransfer);
+ stakerKraiken = toTransfer;
+ }
+
+ uint256 rand = uint256(keccak256(abi.encodePacked(runIndex, tradeIndex, "staking"))) % 100;
+
+ if (rand < stakingBias && activePositionIds.length == 0) {
+ // Stake: pick a tax rate (0-15 range, modest)
+ uint32 taxRate = uint32(uint256(keccak256(abi.encodePacked(runIndex, tradeIndex, "taxrate"))) % 16);
+ uint256 stakeAmount = stakerKraiken / 2;
+
+ // Check minStake
+ try kraiken.minStake() returns (uint256 minStake) {
+ if (stakeAmount < minStake) {
+ if (stakerKraiken >= minStake) {
+ stakeAmount = minStake;
+ } else {
+ return;
+ }
+ }
+ } catch {
+ return;
+ }
+
+ totalStakesAttempted++;
+ vm.startPrank(staker);
+ kraiken.approve(address(stake), stakeAmount);
+ uint256[] memory empty = new uint256[](0);
+ try stake.snatch(stakeAmount, staker, taxRate, empty) returns (uint256 positionId) {
+ activePositionIds.push(positionId);
+ totalStakesSucceeded++;
+ } catch { }
+ vm.stopPrank();
+ } else if (activePositionIds.length > 0) {
+ // Exit a random position
+ uint256 idx = uint256(keccak256(abi.encodePacked(runIndex, tradeIndex, "exit"))) % activePositionIds.length;
+ uint256 posId = activePositionIds[idx];
+ vm.prank(staker);
+ try stake.exitPosition(posId) {
+ // Remove from tracking
+ activePositionIds[idx] = activePositionIds[activePositionIds.length - 1];
+ activePositionIds.pop();
+ } catch { }
+ }
}
-
+
function _tryRecenter() internal {
vm.warp(block.timestamp + 1 hours);
- vm.roll(block.number + 1); // Advance block
+ vm.roll(block.number + 1);
vm.prank(fees);
- try lm.recenter{gas: 50_000_000}() {
+ try lm.recenter{ gas: 50_000_000 }() {
lastRecenterBlock = block.number;
_recordState("RECENTER", 0);
- } catch {}
- }
-
- function _getTradeAmount(uint256 runIndex, uint256 tradeIndex, bool isBuy) internal pure returns (uint256) {
- uint256 baseAmount = 10 ether + (uint256(keccak256(abi.encodePacked(runIndex, tradeIndex))) % 90 ether);
- return isBuy ? baseAmount : baseAmount * 1000;
+ } catch { }
}
function _liquidateTraderHoldings() internal {
uint256 remaining = kraiken.balanceOf(trader);
uint256 attempts;
- // Repeatedly sell down inventory, respecting liquidity limits in SwapExecutor
- while (remaining > 0 && attempts < 10) {
+ while (remaining > 0 && attempts < 20) {
uint256 prevRemaining = remaining;
vm.startPrank(trader);
@@ -256,127 +343,128 @@ contract StreamlinedFuzzing is Script {
try swapExecutor.executeSell(remaining, trader) returns (uint256 actualAmount) {
if (actualAmount == 0) {
vm.stopPrank();
- console2.log("Liquidity liquidation halted: sell returned 0");
break;
}
- } catch Error(string memory reason) {
- vm.stopPrank();
- console2.log("Liquidity liquidation failed:", reason);
- break;
} catch {
vm.stopPrank();
- console2.log("Liquidity liquidation failed with unknown error");
break;
}
vm.stopPrank();
- remaining = kraiken.balanceOf(trader);
- if (remaining >= prevRemaining) {
- console2.log("Liquidity liquidation made no progress; remaining KRAIKEN:", remaining);
- break;
+ // Recenter between liquidation attempts to unlock more liquidity
+ if (attempts % 3 == 2) {
+ _tryRecenter();
}
+ remaining = kraiken.balanceOf(trader);
+ if (remaining >= prevRemaining) break;
+
unchecked {
attempts++;
}
}
-
- if (kraiken.balanceOf(trader) > 0) {
- console2.log("Warning: trader still holds KRAIKEN after liquidation:", kraiken.balanceOf(trader));
- }
}
function _recordState(string memory action, uint256 amount) internal {
- // Build CSV row in parts to avoid stack too deep
string memory row = _buildRowPart1(action, amount);
row = string(abi.encodePacked(row, _buildRowPart2()));
row = string(abi.encodePacked(row, _buildRowPart3()));
-
+
vm.writeLine(csvFilename, row);
}
-
+
function _buildRowPart1(string memory action, uint256 amount) internal view returns (string memory) {
(, int24 tick,,,,,) = pool.slot0();
-
- // Get floor position
+
(uint128 floorLiq, int24 floorLower, int24 floorUpper) = lm.positions(ThreePositionStrategy.Stage.FLOOR);
-
- return string(abi.encodePacked(
- action, ",",
- vm.toString(amount), ",",
- vm.toString(tick), ",",
- vm.toString(floorLower), ",",
- vm.toString(floorUpper), ",",
- vm.toString(uint256(floorLiq)), ","
- ));
+
+ return string(
+ abi.encodePacked(
+ action,
+ ",",
+ vm.toString(amount),
+ ",",
+ vm.toString(tick),
+ ",",
+ vm.toString(floorLower),
+ ",",
+ vm.toString(floorUpper),
+ ",",
+ vm.toString(uint256(floorLiq)),
+ ","
+ )
+ );
}
-
+
function _buildRowPart2() internal view returns (string memory) {
- // Get anchor and discovery positions
(uint128 anchorLiq, int24 anchorLower, int24 anchorUpper) = lm.positions(ThreePositionStrategy.Stage.ANCHOR);
(uint128 discoveryLiq, int24 discoveryLower, int24 discoveryUpper) = lm.positions(ThreePositionStrategy.Stage.DISCOVERY);
-
- return string(abi.encodePacked(
- vm.toString(anchorLower), ",",
- vm.toString(anchorUpper), ",",
- vm.toString(uint256(anchorLiq)), ",",
- vm.toString(discoveryLower), ",",
- vm.toString(discoveryUpper), ",",
- vm.toString(uint256(discoveryLiq)), ","
- ));
+
+ return string(
+ abi.encodePacked(
+ vm.toString(anchorLower),
+ ",",
+ vm.toString(anchorUpper),
+ ",",
+ vm.toString(uint256(anchorLiq)),
+ ",",
+ vm.toString(discoveryLower),
+ ",",
+ vm.toString(discoveryUpper),
+ ",",
+ vm.toString(uint256(discoveryLiq)),
+ ","
+ )
+ );
}
-
+
function _buildRowPart3() internal view returns (string memory) {
- // Get balances and fees
uint256 ethBalance = weth.balanceOf(trader);
uint256 kraikenBalance = kraiken.balanceOf(trader);
-
+
(uint128 fees0, uint128 fees1) = pool.protocolFees();
uint256 deltaFees0 = fees0 > totalFees0 ? fees0 - totalFees0 : 0;
uint256 deltaFees1 = fees1 > totalFees1 ? fees1 - totalFees1 : 0;
-
- return string(abi.encodePacked(
- vm.toString(ethBalance), ",",
- vm.toString(kraikenBalance), ",",
- "0,", // vwap placeholder
- vm.toString(deltaFees0), ",",
- vm.toString(deltaFees1), ",",
- "0" // recenter flag placeholder - no newline here
- ));
+
+ return string(
+ abi.encodePacked(
+ vm.toString(ethBalance), ",", vm.toString(kraikenBalance), ",", "0,", vm.toString(deltaFees0), ",", vm.toString(deltaFees1), ",", "0"
+ )
+ );
}
-
+
function _generateScenarioId() internal view returns (string memory) {
uint256 rand = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao)));
bytes memory chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
bytes memory result = new bytes(4);
-
+
for (uint256 i = 0; i < 4; i++) {
result[i] = chars[rand % chars.length];
rand = rand / chars.length;
}
-
+
return string(result);
}
-
+
function _padNumber(uint256 num, uint256 digits) internal pure returns (string memory) {
string memory numStr = vm.toString(num);
bytes memory numBytes = bytes(numStr);
-
+
if (numBytes.length >= digits) {
return numStr;
}
-
+
bytes memory result = new bytes(digits);
uint256 padding = digits - numBytes.length;
-
+
for (uint256 i = 0; i < padding; i++) {
- result[i] = '0';
+ result[i] = "0";
}
-
+
for (uint256 i = 0; i < numBytes.length; i++) {
result[padding + i] = numBytes[i];
}
-
+
return string(result);
}
}
diff --git a/onchain/analysis/helpers/SwapExecutor.sol b/onchain/analysis/helpers/SwapExecutor.sol
index 1a8dd51..f3f87ea 100644
--- a/onchain/analysis/helpers/SwapExecutor.sol
+++ b/onchain/analysis/helpers/SwapExecutor.sol
@@ -1,17 +1,21 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;
-import {IUniswapV3Pool} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
-import {IWETH9} from "../../src/interfaces/IWETH9.sol";
-import {Kraiken} from "../../src/Kraiken.sol";
-import {TickMath} from "@aperture/uni-v3-lib/TickMath.sol";
-import {LiquidityBoundaryHelper} from "../../test/helpers/LiquidityBoundaryHelper.sol";
-import {ThreePositionStrategy} from "../../src/abstracts/ThreePositionStrategy.sol";
+import { Kraiken } from "../../src/Kraiken.sol";
+
+import { ThreePositionStrategy } from "../../src/abstracts/ThreePositionStrategy.sol";
+import { IWETH9 } from "../../src/interfaces/IWETH9.sol";
+import { LiquidityBoundaryHelper } from "../../test/helpers/LiquidityBoundaryHelper.sol";
+import { TickMath } from "@aperture/uni-v3-lib/TickMath.sol";
+import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
/**
* @title SwapExecutor
- * @notice Helper contract to execute swaps on Uniswap V3 pools for analysis scripts
- * @dev Extracted from analysis scripts to avoid code duplication
+ * @notice Helper contract to execute swaps on Uniswap V3 pools for analysis scripts.
+ * @dev Supports two modes:
+ * - Capped (default): trade sizes limited by LiquidityBoundaryHelper
+ * - Uncapped: trades go directly to pool with no size caps, matching production behavior
+ * Set uncapped=true via constructor to allow trades through position boundaries.
*/
contract SwapExecutor {
IUniswapV3Pool public pool;
@@ -19,93 +23,55 @@ contract SwapExecutor {
Kraiken public harberg;
bool public token0isWeth;
ThreePositionStrategy public liquidityManager;
-
- constructor(IUniswapV3Pool _pool, IWETH9 _weth, Kraiken _harberg, bool _token0isWeth, ThreePositionStrategy _liquidityManager) {
+ bool public uncapped;
+
+ constructor(IUniswapV3Pool _pool, IWETH9 _weth, Kraiken _harberg, bool _token0isWeth, ThreePositionStrategy _liquidityManager, bool _uncapped) {
pool = _pool;
weth = _weth;
harberg = _harberg;
token0isWeth = _token0isWeth;
liquidityManager = _liquidityManager;
+ uncapped = _uncapped;
}
-
+
function executeBuy(uint256 amount, address recipient) external returns (uint256) {
- // Calculate maximum safe buy amount based on liquidity
- uint256 maxBuyAmount = LiquidityBoundaryHelper.calculateBuyLimit(pool, liquidityManager, token0isWeth);
-
- // Cap the amount to the safe limit
- uint256 safeAmount = amount > maxBuyAmount ? maxBuyAmount : amount;
-
- // Skip if amount is zero
+ uint256 safeAmount = amount;
+
+ if (!uncapped) {
+ uint256 maxBuyAmount = LiquidityBoundaryHelper.calculateBuyLimit(pool, liquidityManager, token0isWeth);
+ safeAmount = amount > maxBuyAmount ? maxBuyAmount : amount;
+ }
+
if (safeAmount == 0) return 0;
-
- // For buying HARB with WETH, we're swapping in the direction that increases HARB price
- // zeroForOne = true if WETH is token0, false if WETH is token1
+
bool zeroForOne = token0isWeth;
-
- // Set appropriate price limit based on swap direction
- uint160 sqrtPriceLimitX96;
- if (zeroForOne) {
- // Price goes down (in terms of token0/token1 ratio)
- sqrtPriceLimitX96 = TickMath.MIN_SQRT_RATIO + 1;
- } else {
- // Price goes up
- sqrtPriceLimitX96 = TickMath.MAX_SQRT_RATIO - 1;
- }
-
- pool.swap(
- recipient,
- zeroForOne,
- int256(safeAmount),
- sqrtPriceLimitX96,
- ""
- );
-
+ uint160 sqrtPriceLimitX96 = zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1;
+
+ pool.swap(recipient, zeroForOne, int256(safeAmount), sqrtPriceLimitX96, "");
return safeAmount;
}
-
+
function executeSell(uint256 amount, address recipient) external returns (uint256) {
- // Calculate maximum safe sell amount based on liquidity
- uint256 maxSellAmount = LiquidityBoundaryHelper.calculateSellLimit(pool, liquidityManager, token0isWeth);
-
- // Cap the amount to the safe limit
- uint256 safeAmount = amount > maxSellAmount ? maxSellAmount : amount;
-
- // Skip if amount is zero
- if (safeAmount == 0) return 0;
-
- // For selling HARB for WETH, we're swapping in the direction that decreases HARB price
- // zeroForOne = false if WETH is token0, true if WETH is token1
- bool zeroForOne = !token0isWeth;
-
- // Set appropriate price limit based on swap direction
- uint160 sqrtPriceLimitX96;
- if (zeroForOne) {
- // Price goes down (in terms of token0/token1 ratio)
- sqrtPriceLimitX96 = TickMath.MIN_SQRT_RATIO + 1;
- } else {
- // Price goes up
- sqrtPriceLimitX96 = TickMath.MAX_SQRT_RATIO - 1;
+ uint256 safeAmount = amount;
+
+ if (!uncapped) {
+ uint256 maxSellAmount = LiquidityBoundaryHelper.calculateSellLimit(pool, liquidityManager, token0isWeth);
+ safeAmount = amount > maxSellAmount ? maxSellAmount : amount;
}
-
- pool.swap(
- recipient,
- zeroForOne,
- int256(safeAmount),
- sqrtPriceLimitX96,
- ""
- );
-
+
+ if (safeAmount == 0) return 0;
+
+ bool zeroForOne = !token0isWeth;
+ uint160 sqrtPriceLimitX96 = zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1;
+
+ pool.swap(recipient, zeroForOne, int256(safeAmount), sqrtPriceLimitX96, "");
return safeAmount;
}
-
+
// Callback required for Uniswap V3 swaps
- function uniswapV3SwapCallback(
- int256 amount0Delta,
- int256 amount1Delta,
- bytes calldata
- ) external {
+ function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata) external {
require(msg.sender == address(pool), "Unauthorized callback");
-
+
if (amount0Delta > 0) {
IWETH9(pool.token0()).transfer(address(pool), uint256(amount0Delta));
}
@@ -113,4 +79,4 @@ contract SwapExecutor {
IWETH9(pool.token1()).transfer(address(pool), uint256(amount1Delta));
}
}
-}
\ No newline at end of file
+}
diff --git a/onchain/analysis/run-fuzzing.sh b/onchain/analysis/run-fuzzing.sh
index f13ece8..825cf5d 100755
--- a/onchain/analysis/run-fuzzing.sh
+++ b/onchain/analysis/run-fuzzing.sh
@@ -1,10 +1,11 @@
#!/bin/bash
-# Usage: ./run-fuzzing.sh [optimizer] [runs=N] [staking=on|off] [buybias=N] [trades=N] [stakingbias=N] [debugCSV]
+# Usage: ./run-fuzzing.sh [optimizer] [key=value ...] [debugCSV]
# Examples:
# ./run-fuzzing.sh BullMarketOptimizer runs=50
# ./run-fuzzing.sh WhaleOptimizer runs=20 staking=off
-# ./run-fuzzing.sh BullMarketOptimizer runs=200 staking=on buybias=100 trades=30 stakingbias=95
+# ./run-fuzzing.sh BullMarketOptimizer runs=10 trades=30 buybias=80 uncapped=true
+# ./run-fuzzing.sh BullMarketOptimizer runs=10 trades=30 minbuy=30 maxbuy=70
# ./run-fuzzing.sh BullMarketOptimizer debugCSV # Opens HTML visualizer after generating CSVs
# Colors for output
@@ -15,61 +16,38 @@ BLUE='\033[0;34m'
NC='\033[0m' # No Color
BOLD='\033[1m'
-# Configuration
+# Configuration defaults
OPTIMIZER=${1:-BullMarketOptimizer}
-
-# Check if second parameter is debugCSV
-DEBUG_CSV=false
-if [[ "$2" == "debugCSV" ]]; then
- DEBUG_CSV=true
- RUNS="runs=3"
- STAKING="staking=on"
- BUYBIAS="buybias=50"
- TRADES="trades=5"
- STAKINGBIAS="stakingbias=80"
-else
- RUNS=${2:-runs=20}
- STAKING=${3:-staking=on}
- BUYBIAS=${4:-buybias=50}
- TRADES=${5:-trades=15}
- STAKINGBIAS=${6:-stakingbias=80}
-fi
-
-# Parse runs parameter
-if [[ $RUNS == runs=* ]]; then
- RUNS_VALUE=${RUNS#runs=}
-else
- RUNS_VALUE=$RUNS
-fi
-
-# Parse staking parameter
+RUNS_VALUE=20
STAKING_ENABLED="true"
-if [[ $STAKING == staking=* ]]; then
- STAKING_VALUE=${STAKING#staking=}
- if [[ $STAKING_VALUE == "off" ]] || [[ $STAKING_VALUE == "false" ]] || [[ $STAKING_VALUE == "0" ]]; then
- STAKING_ENABLED="false"
- fi
-fi
-
-# Parse buy bias parameter
BUYBIAS_VALUE="50"
-if [[ $BUYBIAS == buybias=* ]]; then
- BUYBIAS_VALUE=${BUYBIAS#buybias=}
-fi
-
-# Parse trades parameter
TRADES_VALUE="15"
-if [[ $TRADES == trades=* ]]; then
- TRADES_VALUE=${TRADES#trades=}
-fi
-
-# Parse staking bias parameter
STAKINGBIAS_VALUE="80"
-if [[ $STAKINGBIAS == stakingbias=* ]]; then
- STAKINGBIAS_VALUE=${STAKINGBIAS#stakingbias=}
-fi
+UNCAPPED_VALUE="true"
+MINBUY_VALUE="20"
+MAXBUY_VALUE="80"
+DEBUG_CSV=false
-# Ensure we're in the onchain directory (script should be run from there)
+# Parse arguments (skip first which is optimizer)
+shift
+for arg in "$@"; do
+ case "$arg" in
+ debugCSV)
+ DEBUG_CSV=true
+ RUNS_VALUE=3
+ TRADES_VALUE=5
+ ;;
+ runs=*) RUNS_VALUE=${arg#runs=} ;;
+ staking=off|staking=false|staking=0) STAKING_ENABLED="false" ;;
+ staking=*) STAKING_ENABLED="true" ;;
+ buybias=*) BUYBIAS_VALUE=${arg#buybias=} ;;
+ trades=*) TRADES_VALUE=${arg#trades=} ;;
+ stakingbias=*) STAKINGBIAS_VALUE=${arg#stakingbias=} ;;
+ uncapped=*) UNCAPPED_VALUE=${arg#uncapped=} ;;
+ minbuy=*) MINBUY_VALUE=${arg#minbuy=} ;;
+ maxbuy=*) MAXBUY_VALUE=${arg#maxbuy=} ;;
+ esac
+done
echo -e "${GREEN}=== Fuzzing Analysis ===${NC}"
echo "Optimizer: $OPTIMIZER"
@@ -80,6 +58,8 @@ if [ "$STAKING_ENABLED" = "true" ]; then
echo "Staking bias: $STAKINGBIAS_VALUE%"
fi
echo "Buy bias: $BUYBIAS_VALUE%"
+echo "Uncapped swaps: $UNCAPPED_VALUE"
+echo "Buy range: ${MINBUY_VALUE}-${MAXBUY_VALUE} ETH"
echo ""
# Validate optimizer
@@ -107,6 +87,9 @@ ENABLE_STAKING=$STAKING_ENABLED \
BUY_BIAS=$BUYBIAS_VALUE \
TRADES_PER_RUN=$TRADES_VALUE \
STAKING_BIAS=$STAKINGBIAS_VALUE \
+UNCAPPED_SWAPS=$UNCAPPED_VALUE \
+MIN_BUY_ETH=$MINBUY_VALUE \
+MAX_BUY_ETH=$MAXBUY_VALUE \
forge script analysis/StreamlinedFuzzing.s.sol:StreamlinedFuzzing --skip-simulation --gas-estimate-multiplier 300 -vv 2>&1
# Analysis complete
@@ -117,7 +100,7 @@ echo -e "${GREEN}=== ANALYSIS COMPLETE ===${NC}"
NEW_CSVS=$(ls -1 analysis/fuzz-????-???.csv 2>/dev/null | sort)
# Get the scenario code from the first new file
if [ "$EXISTING_CSVS" != "$NEW_CSVS" ]; then
- SCENARIO_CODE=$(echo "$NEW_CSVS" | grep -v -F "$EXISTING_CSVS" | head -1 | sed 's/fuzz-\(....\).*/\1/')
+ SCENARIO_CODE=$(echo "$NEW_CSVS" | grep -v -F "$EXISTING_CSVS" | head -1 | sed 's/.*fuzz-\(....\).*/\1/')
else
SCENARIO_CODE="UNKN"
fi
@@ -135,9 +118,9 @@ for csv in analysis/fuzz-${SCENARIO_CODE}-*.csv; do
# Get INIT and FINAL rows
INIT_ETH=$(grep "^INIT," "$csv" | cut -d',' -f13)
FINAL_ETH=$(grep "^FINAL," "$csv" | cut -d',' -f13)
-
+
if [ ! -z "$INIT_ETH" ] && [ ! -z "$FINAL_ETH" ]; then
- if [ "$FINAL_ETH" -gt "$INIT_ETH" ]; then
+ if [ "$FINAL_ETH" -gt "$INIT_ETH" ] 2>/dev/null; then
PROFIT_PCT=$(echo "scale=1; ($FINAL_ETH - $INIT_ETH) * 100 / $INIT_ETH" | bc -l 2>/dev/null || echo "0")
echo -e "${GREEN} $csv: PROFITABLE (+${PROFIT_PCT}%)${NC}"
((PROFITABLE_COUNT++))
@@ -159,7 +142,7 @@ echo -e "${GREEN}CSV files generated with scenario ID: ${SCENARIO_CODE}${NC}"
if [ "$DEBUG_CSV" = true ]; then
echo ""
echo -e "${YELLOW}Launching HTML visualizer...${NC}"
-
+
# Check if Python3 is available
if command -v python3 &> /dev/null; then
echo "Starting local server from analysis folder at http://localhost:8000"
@@ -168,20 +151,17 @@ if [ "$DEBUG_CSV" = true ]; then
cd analysis
python3 -m http.server 8000 --bind 127.0.0.1 &
SERVER_PID=$!
-
+
# Try to open browser (cross-platform)
sleep 1
if command -v open &> /dev/null; then
- # macOS
open "http://localhost:8000/run-visualizer.html"
elif command -v xdg-open &> /dev/null; then
- # Linux
xdg-open "http://localhost:8000/run-visualizer.html"
elif command -v wslview &> /dev/null; then
- # WSL
wslview "http://localhost:8000/run-visualizer.html"
fi
-
+
echo ""
echo "Press Ctrl+C to stop the server"
wait $SERVER_PID
@@ -190,4 +170,4 @@ if [ "$DEBUG_CSV" = true ]; then
echo " cd analysis && python3 -m http.server 8000"
echo " Then open http://localhost:8000/run-visualizer.html in your browser"
fi
-fi
\ No newline at end of file
+fi
diff --git a/onchain/analysis/run-parameter-sweep.sh b/onchain/analysis/run-parameter-sweep.sh
new file mode 100755
index 0000000..2461841
--- /dev/null
+++ b/onchain/analysis/run-parameter-sweep.sh
@@ -0,0 +1,264 @@
+#!/bin/bash
+# Parameter sweep for finding safe/unsafe optimizer parameter boundaries
+#
+# Usage: ./analysis/run-parameter-sweep.sh [mode]
+# Modes:
+# quick - Small focused grid (~5 min)
+# standard - Medium grid (~30 min)
+# boundary - Focused on exploitation boundary (~20 min)
+#
+# Run from onchain/ directory
+
+set -euo pipefail
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m'
+
+MODE=${1:-standard}
+
+# Common: uncapped swaps for realistic exploitation testing
+UNCAPPED="true"
+MINBUY="20"
+MAXBUY="80"
+
+case $MODE in
+ quick)
+ CI="0,500000000000000000,1000000000000000000"
+ AS="100000000000000000,500000000000000000,1000000000000000000"
+ AW="30,50,80"
+ DD="200000000000000000,1000000000000000000"
+ BB="80,100"
+ RUNS=3
+ TRADES=20
+ ;;
+ standard)
+ CI="0,200000000000000000,500000000000000000,800000000000000000,1000000000000000000"
+ AS="50000000000000000,100000000000000000,200000000000000000,500000000000000000,700000000000000000,1000000000000000000"
+ AW="20,50,80"
+ DD="200000000000000000,500000000000000000,1000000000000000000"
+ BB="80,100"
+ RUNS=5
+ TRADES=30
+ ;;
+ boundary)
+ # Focused sweep around known exploitation boundary:
+ # Bull (exploitable): CI=0, AS=1e18, AW=50, DD=1e18
+ # Bear (mostly safe): CI=0.8e18, AS=0.2e18, AW=80+, DD=0.2e18
+ # Key: anchorShare transition between 0.2 and 0.7
+ CI="0,300000000000000000,500000000000000000,800000000000000000"
+ AS="100000000000000000,200000000000000000,300000000000000000,400000000000000000,500000000000000000,700000000000000000,1000000000000000000"
+ AW="30,50,80"
+ DD="200000000000000000,500000000000000000,1000000000000000000"
+ BB="80"
+ RUNS=5
+ TRADES=30
+ ;;
+ *)
+ echo "Unknown mode: $MODE (use: quick, standard, boundary)"
+ exit 1
+ ;;
+esac
+
+echo -e "${GREEN}=== KRAIKEN Parameter Sweep ($MODE mode) ===${NC}"
+echo "Runs per combo: $RUNS | Trades per run: $TRADES"
+echo "Uncapped: $UNCAPPED | Trade range: ${MINBUY}-${MAXBUY} ETH"
+
+# Master results
+SUMMARY_FILE="analysis/sweep-FULL-summary.csv"
+echo "ci,anchor_share,anchor_width,discovery_depth,buy_bias,max_trader_pnl,min_trader_pnl,any_lm_loss,lm_eth_delta" > "$SUMMARY_FILE"
+
+# Split into small batches: one forge call per (CI, AS, AW) triple
+# Each call handles DD*BB combos to stay within gas limits
+batch=0
+total_combos=0
+start_time=$(date +%s)
+
+for ci_val in $(echo "$CI" | tr ',' ' '); do
+ for as_val in $(echo "$AS" | tr ',' ' '); do
+ for aw_val in $(echo "$AW" | tr ',' ' '); do
+ batch=$((batch + 1))
+ ci_pct=$(python3 -c "print(f'{int(\"$ci_val\")/1e18:.0%}')" 2>/dev/null || echo "$ci_val")
+ as_pct=$(python3 -c "print(f'{int(\"$as_val\")/1e18:.1%}')" 2>/dev/null || echo "$as_val")
+
+ echo -ne "\r${BLUE}[$batch] CI=$ci_pct AS=$as_pct AW=$aw_val${NC} "
+
+ CI_VALUES="$ci_val" \
+ AS_VALUES="$as_val" \
+ AW_VALUES="$aw_val" \
+ DD_VALUES="$DD" \
+ BB_VALUES="$BB" \
+ RUNS_PER_COMBO="$RUNS" \
+ TRADES_PER_RUN="$TRADES" \
+ UNCAPPED_SWAPS="$UNCAPPED" \
+ MIN_BUY_ETH="$MINBUY" \
+ MAX_BUY_ETH="$MAXBUY" \
+ SWEEP_TAG="B${batch}" \
+ forge script analysis/ParameterSweepFuzzing.s.sol:ParameterSweepFuzzing \
+ --skip-simulation --gas-estimate-multiplier 300 -vv 2>&1 | grep "UNSAFE" || true
+
+ batch_csv="analysis/sweep-B${batch}-summary.csv"
+ if [ -f "$batch_csv" ]; then
+ new_lines=$(tail -n +2 "$batch_csv" | wc -l)
+ total_combos=$((total_combos + new_lines))
+ tail -n +2 "$batch_csv" >> "$SUMMARY_FILE"
+ rm "$batch_csv"
+ fi
+ done
+ done
+done
+
+elapsed=$(($(date +%s) - start_time))
+echo ""
+echo ""
+echo -e "${GREEN}=== ANALYSIS ===${NC}"
+echo "Elapsed: ${elapsed}s"
+
+# Analyze results
+total_tested=$(tail -n +2 "$SUMMARY_FILE" | wc -l | tr -d ' ')
+unsafe_combos=$(tail -n +2 "$SUMMARY_FILE" | grep -c ',true,' || true)
+unsafe_combos=${unsafe_combos:-0}
+safe_combos=$((total_tested - unsafe_combos))
+
+echo "Total tested: $total_tested"
+echo -e "Safe: ${GREEN}$safe_combos${NC}"
+echo -e "Unsafe: ${RED}$unsafe_combos${NC}"
+
+# Generate report
+RESULTS_FILE="analysis/PARAMETER_SEARCH_RESULTS.md"
+
+cat > "$RESULTS_FILE" << EOF
+# KRAIKEN Parameter Search Results
+
+## Objective
+Find optimizer parameters where the LiquidityManager NEVER loses ETH regardless of trade sequence.
+
+## Methodology
+- **Mode**: $MODE
+- **Runs per parameter combination**: $RUNS
+- **Trades per run**: $TRADES
+- **Uncapped swaps**: $UNCAPPED (trades push through position boundaries)
+- **Trade size range**: ${MINBUY}-${MAXBUY} ETH (vs 100 ETH LM balance)
+- **VWAP accumulation**: Environment reused across runs per combo
+- **Buy biases tested**: $(echo $BB | tr ',' ', ')%
+- **Total combinations tested**: $total_tested
+- **Elapsed time**: ${elapsed}s
+
+### Parameters Searched
+| Parameter | Values | Description |
+|-----------|--------|-------------|
+| capitalInefficiency | $(python3 -c "print(', '.join(f'{int(x)/1e18:.0%}' for x in '$CI'.split(',')))" 2>/dev/null || echo "$CI") | Capital buffer (0=aggressive, 1e18=conservative) |
+| anchorShare | $(python3 -c "print(', '.join(f'{int(x)/1e18:.1%}' for x in '$AS'.split(',')))" 2>/dev/null || echo "$AS") | ETH allocation to anchor vs floor |
+| anchorWidth | $(echo $AW | tr ',' ', ') | Anchor position width (1-100) |
+| discoveryDepth | $(python3 -c "print(', '.join(f'{int(x)/1e18:.0%}' for x in '$DD'.split(',')))" 2>/dev/null || echo "$DD") | Discovery liquidity density |
+| buyBias | $(echo $BB | tr ',' ', ')% | Adversarial trade mix (80=buy-heavy, 100=buy-only) |
+
+### Key Metrics
+- **Trader PnL < 0**: LM gained ETH (SAFE). Trader lost money.
+- **Trader PnL > 0**: LM lost ETH (UNSAFE). Trader extracted ETH.
+
+## Results Summary
+- **Safe combinations**: $safe_combos / $total_tested
+- **Unsafe combinations**: $unsafe_combos / $total_tested
+EOF
+
+if [ "$unsafe_combos" -gt 0 ]; then
+ {
+ echo ""
+ echo "## UNSAFE Parameters (Trader Profited = LM Lost ETH)"
+ echo ""
+ echo "| CI | AnchorShare | AnchorWidth | DiscoveryDepth | BuyBias | Max Trader PnL (ETH) |"
+ echo "|-----|-------------|-------------|----------------|---------|----------------------|"
+
+ while IFS=, read -r ci as aw dd bb maxpnl minpnl loss lmdelta; do
+ if [[ "$loss" == "true" ]]; then
+ ci_pct=$(python3 -c "print(f'{int(\"$ci\")/1e18:.0%}')" 2>/dev/null || echo "$ci")
+ as_pct=$(python3 -c "print(f'{int(\"$as\")/1e18:.1%}')" 2>/dev/null || echo "$as")
+ dd_pct=$(python3 -c "print(f'{int(\"$dd\")/1e18:.0%}')" 2>/dev/null || echo "$dd")
+ maxpnl_eth=$(python3 -c "print(f'{int(\"$maxpnl\")/1e18:+.4f}')" 2>/dev/null || echo "$maxpnl")
+ echo "| $ci_pct | $as_pct | $aw | $dd_pct | $bb | $maxpnl_eth |"
+ fi
+ done < <(tail -n +2 "$SUMMARY_FILE")
+ } >> "$RESULTS_FILE"
+fi
+
+{
+ echo ""
+ echo "## SAFE Parameters"
+ echo ""
+} >> "$RESULTS_FILE"
+
+if [ "$safe_combos" -gt 0 ]; then
+ {
+ echo "All tested parameter combinations where the LM never lost ETH:"
+ echo ""
+ echo "### Safe Ranges by Buy Bias"
+ echo ""
+ } >> "$RESULTS_FILE"
+
+ for bb_val in $(echo "$BB" | tr ',' ' '); do
+ safe_at_bb=$(tail -n +2 "$SUMMARY_FILE" | grep ",$bb_val," | grep -c ',false,' || true)
+ safe_at_bb=${safe_at_bb:-0}
+ total_at_bb=$(tail -n +2 "$SUMMARY_FILE" | grep -c ",$bb_val," || true)
+ total_at_bb=${total_at_bb:-0}
+ echo "- **BuyBias=${bb_val}%**: ${safe_at_bb}/${total_at_bb} safe" >> "$RESULTS_FILE"
+ done
+
+ {
+ echo ""
+ echo "### Top 20 Safest Combinations (most negative max trader PnL = hardest to exploit)"
+ echo ""
+ echo "| CI | AnchorShare | AnchorWidth | DiscoveryDepth | BuyBias | Max Trader PnL (ETH) |"
+ echo "|-----|-------------|-------------|----------------|---------|----------------------|"
+ } >> "$RESULTS_FILE"
+
+ tail -n +2 "$SUMMARY_FILE" | grep ',false,' | sort -t, -k6 -n | head -20 | while IFS=, read -r ci as aw dd bb maxpnl minpnl loss lmdelta; do
+ ci_pct=$(python3 -c "print(f'{int(\"$ci\")/1e18:.0%}')" 2>/dev/null || echo "$ci")
+ as_pct=$(python3 -c "print(f'{int(\"$as\")/1e18:.1%}')" 2>/dev/null || echo "$as")
+ dd_pct=$(python3 -c "print(f'{int(\"$dd\")/1e18:.0%}')" 2>/dev/null || echo "$dd")
+ maxpnl_eth=$(python3 -c "print(f'{int(\"$maxpnl\")/1e18:+.4f}')" 2>/dev/null || echo "$maxpnl")
+ echo "| $ci_pct | $as_pct | $aw | $dd_pct | $bb | $maxpnl_eth |"
+ done >> "$RESULTS_FILE"
+else
+ echo "No safe parameter combinations found." >> "$RESULTS_FILE"
+fi
+
+{
+ echo ""
+ echo "## Recommendations"
+ echo ""
+} >> "$RESULTS_FILE"
+
+if [ "$unsafe_combos" -eq 0 ]; then
+ cat >> "$RESULTS_FILE" << 'RECO'
+**All tested parameter combinations are SAFE.** The three-position strategy's asymmetric
+slippage profile effectively prevents profitable arbitrage across all tested parameters.
+RECO
+else
+ cat >> "$RESULTS_FILE" << 'RECO'
+**Some parameter combinations are UNSAFE.** The exploitation boundary depends primarily on:
+1. **anchorShare**: Higher values allocate more ETH to the thin anchor position, reducing floor protection
+2. **capitalInefficiency**: Lower values (0%) make the floor position more aggressive, increasing exploit risk
+3. **anchorWidth**: Narrower widths concentrate anchor liquidity, making it cheaper to push through
+
+### Safe Zone
+Parameters where the trader never profited across all tested scenarios.
+
+### Unsafe Zone
+Parameters where at least one test run showed trader profit (= LM ETH loss).
+The exploitation pattern is: buy→recenter→sell→recenter repeated over many cycles,
+where VWAP accumulates at inflated prices and the floor gets positioned too high.
+RECO
+fi
+
+{
+ echo ""
+ echo "---"
+ echo "*Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)*"
+} >> "$RESULTS_FILE"
+
+echo ""
+echo -e "${GREEN}Report: $RESULTS_FILE${NC}"
+echo -e "${GREEN}Data: $SUMMARY_FILE${NC}"
diff --git a/onchain/analysis/sweep-FULL-summary.csv b/onchain/analysis/sweep-FULL-summary.csv
new file mode 100644
index 0000000..47f90a3
--- /dev/null
+++ b/onchain/analysis/sweep-FULL-summary.csv
@@ -0,0 +1,253 @@
+ci,anchor_share,anchor_width,discovery_depth,buy_bias,max_trader_pnl,min_trader_pnl,any_lm_loss,lm_eth_delta
+0,100000000000000000,30,200000000000000000,80,44486458737952248326,-344363430578411493891,true,-169638741014798823362
+0,100000000000000000,30,500000000000000000,80,167054352470885235368,-77259177653417840988,true,-22435102158072601482
+0,100000000000000000,30,1000000000000000000,80,173816793379889528476,-59514356933507649733,true,-69940881107079455084
+0,100000000000000000,50,200000000000000000,80,195483692737516408951,-369152693533808532380,true,31759825248527646357
+0,100000000000000000,50,500000000000000000,80,151064658407102988593,-369225664334627951118,true,-127567825383992877106
+0,100000000000000000,50,1000000000000000000,80,32342469884268611741,-372912977224560262040,true,-101057520197727960231
+0,100000000000000000,80,200000000000000000,80,-114482208360718517702,-239725025920578087572,false,-183123902400890564257
+0,100000000000000000,80,500000000000000000,80,194910121464237681794,-404955705321896438825,true,574579522132729829104
+0,100000000000000000,80,1000000000000000000,80,142897475752009126708,-389487655450378923124,true,-193405299106155672834
+0,200000000000000000,30,200000000000000000,80,155187449165434975506,-81414371712601104428,true,-14471643115117013711
+0,200000000000000000,30,500000000000000000,80,163571941929097860168,-61891821190559980695,true,-59111909308481265028
+0,200000000000000000,30,1000000000000000000,80,165191274499760358170,-49196271006628913671,true,-91906039817996179609
+0,200000000000000000,50,200000000000000000,80,160782048458739948809,-389121911399725473143,true,-199716004946540170887
+0,200000000000000000,50,500000000000000000,80,45794784565606216985,-389791630630333203294,true,-164290408576398456600
+0,200000000000000000,50,1000000000000000000,80,158757786572777390466,-134404140735943866788,true,97343275988125971109
+0,200000000000000000,80,200000000000000000,80,194806372543088703936,-395126339452027380227,true,525330585266873287014
+0,200000000000000000,80,500000000000000000,80,195283444565288124583,-378934838255636561585,true,94461047632773348276
+0,200000000000000000,80,1000000000000000000,80,111927359456056780874,-415064060019209901141,true,-194297437373278233331
+0,300000000000000000,30,200000000000000000,80,151713710405220026922,-66803139846659683830,true,-48702870779363797114
+0,300000000000000000,30,500000000000000000,80,159120661507972218931,-53673652365812154279,true,-80419875713673270341
+0,300000000000000000,30,1000000000000000000,80,171085310457536831070,-44119439613512959138,true,-102500602604622687026
+0,300000000000000000,50,200000000000000000,80,129283876294671712502,-387556460041908335385,true,-103029945090892239733
+0,300000000000000000,50,500000000000000000,80,141092240386577048974,-137908468166928563712,true,116600148700035296369
+0,300000000000000000,50,1000000000000000000,80,153996883423908400751,-112548700738468588136,true,53350614009652912619
+0,300000000000000000,80,200000000000000000,80,194910411595087512498,-350679574532673709254,true,460479088240710843683
+0,300000000000000000,80,500000000000000000,80,167461944576477377247,-395861382229558374542,true,-193162572569588408235
+0,300000000000000000,80,1000000000000000000,80,98060499930109189113,-250716505116596324840,true,312486482933744007968
+0,400000000000000000,30,200000000000000000,80,150574660485639722638,-57216306116552183682,true,-69349041862805040791
+0,400000000000000000,30,500000000000000000,80,156124699110441137264,-47095173940362397718,true,-99832902457775308917
+0,400000000000000000,30,1000000000000000000,80,164088294742656937514,-42798144626710557224,true,-113123706754740409853
+0,400000000000000000,50,200000000000000000,80,101984891357896228984,-403703973237306529259,true,-159810963167993342184
+0,400000000000000000,50,500000000000000000,80,93050802795113211297,-112942190738660851389,true,76782355343247627703
+0,400000000000000000,50,1000000000000000000,80,146211168921899826859,-96739021177271216259,true,21069548957298981478
+0,400000000000000000,80,200000000000000000,80,195284991249546441631,-378161183910984441657,true,58207646330519942139
+0,400000000000000000,80,500000000000000000,80,126822292889133327718,-415459501485737323687,true,-193595896070916250641
+0,400000000000000000,80,1000000000000000000,80,103277645489965962501,-210716203660920866401,true,237814266045280259416
+0,500000000000000000,30,200000000000000000,80,160165089135763787724,-52457372387737530852,true,-85746495037472917363
+0,500000000000000000,30,500000000000000000,80,165616942741438695662,-43168229997509836871,true,-103769464850816973019
+0,500000000000000000,30,1000000000000000000,80,167636674824743958880,-41857951969119624936,true,-115715987428184139359
+0,500000000000000000,50,200000000000000000,80,137257398268547095084,-121785800325298887611,true,87291598212266833144
+0,500000000000000000,50,500000000000000000,80,150777245701970530819,-90149733560086496311,true,32715087184711766092
+0,500000000000000000,50,1000000000000000000,80,154578529909996436716,-82389992004970148312,true,-5468794540756498607
+0,500000000000000000,80,200000000000000000,80,195483692737516408959,-372371512988250740855,true,21463017195070812053
+0,500000000000000000,80,500000000000000000,80,181708320653268054170,-717258802272851657891,true,28819472468983323132
+0,500000000000000000,80,1000000000000000000,80,147809334942209271564,-182174948624133030510,true,183590533004646736168
+0,700000000000000000,30,200000000000000000,80,172090616605752812013,-42821103304505047624,true,-106791750982074587073
+0,700000000000000000,30,500000000000000000,80,170834047266560500604,-41111027131374479843,true,-118558136533368404361
+0,700000000000000000,30,1000000000000000000,80,167395132031342642656,-41529125330675915290,true,-124902404215783434523
+0,700000000000000000,50,200000000000000000,80,156136231279694516144,-94139527570993234727,true,14837205782972891731
+0,700000000000000000,50,500000000000000000,80,163364167838044828205,-75773855747551436700,true,-12941746241299673390
+0,700000000000000000,50,1000000000000000000,80,169048448202911124516,-67754967724795492707,true,-46320675467968598949
+0,700000000000000000,80,200000000000000000,80,120148399059968917304,-732077293217835406710,true,-4213840679965837406
+0,700000000000000000,80,500000000000000000,80,127521084589355446262,-154565617021369556225,true,140881801676534546751
+0,700000000000000000,80,1000000000000000000,80,142256248043042149315,-137790692837483515921,true,103309717403743261013
+0,1000000000000000000,30,200000000000000000,80,159409348983483522327,-45323865693161526820,true,-119163013809315791363
+0,1000000000000000000,30,500000000000000000,80,162452755509922365965,-43262157332015765635,true,-126046782829450776857
+0,1000000000000000000,30,1000000000000000000,80,159891052289713702690,-45782422542117172808,true,-130155371134741777162
+0,1000000000000000000,50,200000000000000000,80,164049839625152367034,-70616966732105789908,true,-50848406512391379874
+0,1000000000000000000,50,500000000000000000,80,166462148519741767156,-66475894559302170836,true,-62812605866902698219
+0,1000000000000000000,50,1000000000000000000,80,163133148454976439883,-64681106428906906130,true,-75993715568526322626
+0,1000000000000000000,80,200000000000000000,80,139673365082890615487,-712529516196922108915,true,-44516558108995271432
+0,1000000000000000000,80,500000000000000000,80,142321738796538591059,-114176132346686812978,true,41246991178681608486
+0,1000000000000000000,80,1000000000000000000,80,147699828470900538132,-87373605077360303171,true,7391641868694835344
+300000000000000000,100000000000000000,30,200000000000000000,80,90107301307546703312,-161862554278910606841,true,184266683567034936324
+300000000000000000,100000000000000000,30,500000000000000000,80,115842754187213666521,-149312985436998962354,true,139186011849384937074
+300000000000000000,100000000000000000,30,1000000000000000000,80,119930390142787695766,-140456076007307060965,true,106301030816141345132
+300000000000000000,100000000000000000,50,200000000000000000,80,126413797870735931602,-280837339281459536814,true,445765474456618424461
+300000000000000000,100000000000000000,50,500000000000000000,80,121184503562354436732,-249988872641610082927,true,403040445654495678798
+300000000000000000,100000000000000000,50,1000000000000000000,80,103792440020700387729,-224812536568183527173,true,309816967808204831140
+300000000000000000,100000000000000000,80,200000000000000000,80,71689243311549135464,-394188998762162443364,true,40925083278779943808
+300000000000000000,100000000000000000,80,500000000000000000,80,113356502106070524277,-394242638579300655517,true,564381739722628659999
+300000000000000000,100000000000000000,80,1000000000000000000,80,110127229214213262868,-353976416519181661719,true,555047767500413014090
+300000000000000000,200000000000000000,30,200000000000000000,80,99572622424230742776,-141870738242882295339,true,130512168429676381778
+300000000000000000,200000000000000000,30,500000000000000000,80,109559001489116450394,-124425878984435035664,true,99202104576490437214
+300000000000000000,200000000000000000,30,1000000000000000000,80,102526515175603812125,-121866086752138898655,true,82185759309751294162
+300000000000000000,200000000000000000,50,200000000000000000,80,120076418909682034930,-235571922975371769278,true,362989292124758351974
+300000000000000000,200000000000000000,50,500000000000000000,80,88354241944285805761,-214139044643556608425,true,286950076035470995362
+300000000000000000,200000000000000000,50,1000000000000000000,80,105746563945546034609,-197788747189567644373,true,240191470493631701653
+300000000000000000,200000000000000000,80,200000000000000000,80,115876988095706978431,-389158239980328590634,true,527215058577882545669
+300000000000000000,200000000000000000,80,500000000000000000,80,112395407219313592651,-339744268544626947790,true,494625112034363742481
+300000000000000000,200000000000000000,80,1000000000000000000,80,102024486124534527525,-296372731705502286051,true,477702458866675883227
+300000000000000000,300000000000000000,30,200000000000000000,80,88920464627971369227,-124240146059600588139,true,96385413636861671348
+300000000000000000,300000000000000000,30,500000000000000000,80,97158447579894841293,-115730399903882729733,true,72459372210021436981
+300000000000000000,300000000000000000,30,1000000000000000000,80,102976714355000887670,-111412838717716383372,true,63182328411283816191
+300000000000000000,300000000000000000,50,200000000000000000,80,113346591037115864789,-202568530914906266277,true,276188206403829251174
+300000000000000000,300000000000000000,50,500000000000000000,80,81537980997145678606,-187591085289987344189,true,218237262988112240956
+300000000000000000,300000000000000000,50,1000000000000000000,80,91271920387095553391,-181798195335045584065,true,188461519155115622591
+300000000000000000,300000000000000000,80,200000000000000000,80,113744203391555900599,-345764911194062960855,true,451642160967398894394
+300000000000000000,300000000000000000,80,500000000000000000,80,105249183379045062672,-293091879495295121076,true,435780194458694625987
+300000000000000000,300000000000000000,80,1000000000000000000,80,98060499930109189113,-242665341267690387608,true,385997991341989218570
+300000000000000000,400000000000000000,30,200000000000000000,80,80537083487724658096,-113753020645263888591,true,65923425252412341623
+300000000000000000,400000000000000000,30,500000000000000000,80,87186147578647587883,-109868191561636769915,true,61434776167442084227
+300000000000000000,400000000000000000,30,1000000000000000000,80,89265380428089521901,-104790916112609874802,true,49782471972386051176
+300000000000000000,400000000000000000,50,200000000000000000,80,101984891357896228984,-185379597430739908461,true,216322706985157517281
+300000000000000000,400000000000000000,50,500000000000000000,80,93050802795113211297,-167789073576034252735,true,179763854292853435315
+300000000000000000,400000000000000000,50,1000000000000000000,80,82169187485556656368,-163836078579841657095,true,150295393960451251958
+300000000000000000,400000000000000000,80,200000000000000000,80,112146686903194430162,-304946915681640331653,true,394865849110529356288
+300000000000000000,400000000000000000,80,500000000000000000,80,98444350388172076663,-249408519837231369296,true,357192004106156059233
+300000000000000000,400000000000000000,80,1000000000000000000,80,81658451002257837855,-242559466779692443036,true,345969339860429203498
+300000000000000000,500000000000000000,30,200000000000000000,80,81115008534181111585,-96644637042564352855,true,46463799974410115285
+300000000000000000,500000000000000000,30,500000000000000000,80,87929680931988001720,-103320744414857961744,true,39488138421233652604
+300000000000000000,500000000000000000,30,1000000000000000000,80,85422695889459625853,-91078038512982797942,true,36965212240887653554
+300000000000000000,500000000000000000,50,200000000000000000,80,64979024268061866500,-158615144579486207967,true,153373806381727322036
+300000000000000000,500000000000000000,50,500000000000000000,80,82517803505587784667,-151738486423671497287,true,135943843335468931896
+300000000000000000,500000000000000000,50,1000000000000000000,80,85960086184551212940,-144611233126908568330,true,118634187616683820919
+300000000000000000,500000000000000000,80,200000000000000000,80,106554680600409061408,-243445620578820512667,true,312031716836268404438
+300000000000000000,500000000000000000,80,500000000000000000,80,104779946046969534812,-209763396645828492330,true,306403500142105087962
+300000000000000000,500000000000000000,80,1000000000000000000,80,99185560258319231697,-215763870810632508434,true,281674057376863687075
+300000000000000000,700000000000000000,30,200000000000000000,80,81520663380994883518,-74457744225408771320,true,16192019004694037318
+300000000000000000,700000000000000000,30,500000000000000000,80,79013424840824728885,-67845265124252328511,true,16211848496958546465
+300000000000000000,700000000000000000,30,1000000000000000000,80,72538651012079626575,-69236170243112263953,true,10325798050469524832
+300000000000000000,700000000000000000,50,200000000000000000,80,69845516229807783673,-110626211265688035202,true,83262214777326406613
+300000000000000000,700000000000000000,50,500000000000000000,80,80662276907143907513,-100572571892647844815,true,67427855506738184219
+300000000000000000,700000000000000000,50,1000000000000000000,80,86158336079897645338,-101486811066707183694,true,63540333112507136066
+300000000000000000,700000000000000000,80,200000000000000000,80,65683979060278118145,-158807253853505997218,true,205648700914097179782
+300000000000000000,700000000000000000,80,500000000000000000,80,58303902795509903100,-154018369775207643199,true,186341379713225964843
+300000000000000000,700000000000000000,80,1000000000000000000,80,65679235679792616093,-157945643974289292406,true,171262083083818054220
+300000000000000000,1000000000000000000,30,200000000000000000,80,48030848800840149509,-50391471562312213247,true,3028289877824552727
+300000000000000000,1000000000000000000,30,500000000000000000,80,46061948912631857969,-48140270305063945692,true,4171858736076297548
+300000000000000000,1000000000000000000,30,1000000000000000000,80,45025600810425548909,-48068326690607399640,true,3286604958799171949
+300000000000000000,1000000000000000000,50,200000000000000000,80,61267913252416902198,-66372147311822058691,true,31149128611596818801
+300000000000000000,1000000000000000000,50,500000000000000000,80,64089224385289216484,-60892839378304369006,true,31921907704334962519
+300000000000000000,1000000000000000000,50,1000000000000000000,80,54658023720697948800,-57706673267471653921,true,23050124121187638187
+300000000000000000,1000000000000000000,80,200000000000000000,80,59161632604099011989,-110618169425182058975,true,99198511562295091301
+300000000000000000,1000000000000000000,80,500000000000000000,80,54474456330858328703,-91309785061472866387,true,86528498815086544607
+300000000000000000,1000000000000000000,80,1000000000000000000,80,58547662761575342558,-88716563204141709661,true,78316558694418762146
+500000000000000000,100000000000000000,30,200000000000000000,80,44486458737952248326,-175492736798642342792,true,202816972862435784210
+500000000000000000,100000000000000000,30,500000000000000000,80,36206120417758688313,-160956656045798694610,true,178290041315015296957
+500000000000000000,100000000000000000,30,1000000000000000000,80,39736839423928406979,-168771146761320369483,true,170103441273370534383
+500000000000000000,100000000000000000,50,200000000000000000,80,78711578928330705891,-259584351343254675440,true,414422124934757811228
+500000000000000000,100000000000000000,50,500000000000000000,80,74234005460738908552,-241044681680829601987,true,356670338978896219838
+500000000000000000,100000000000000000,50,1000000000000000000,80,32342469884268611741,-228505681280192717122,true,312672159583669111635
+500000000000000000,100000000000000000,80,200000000000000000,80,72263809083903043161,-300362772749047727860,true,569373379582803890410
+500000000000000000,100000000000000000,80,500000000000000000,80,72868698629180002611,-271686200332581005687,true,547108647418804290571
+500000000000000000,100000000000000000,80,1000000000000000000,80,63390941242693996825,-287842228117934993913,true,527708600464211033744
+500000000000000000,200000000000000000,30,200000000000000000,80,31065103199988951255,-154218365153302492981,true,163385555768605587896
+500000000000000000,200000000000000000,30,500000000000000000,80,30547271291789835623,-140754547013391332208,true,146413497211840620960
+500000000000000000,200000000000000000,30,1000000000000000000,80,29651367876392850752,-143068451326219418577,true,144184932744962095883
+500000000000000000,200000000000000000,50,200000000000000000,80,75289194461590512308,-230492256827587722877,true,320452471246771868058
+500000000000000000,200000000000000000,50,500000000000000000,80,45794784565606216985,-222257272790918818370,true,281629100645196876513
+500000000000000000,200000000000000000,50,1000000000000000000,80,27494765792646536294,-209034345882227715893,true,259117689321105443699
+500000000000000000,200000000000000000,80,200000000000000000,80,72861288616759974138,-261526015945077666254,true,482904621712430905217
+500000000000000000,200000000000000000,80,500000000000000000,80,67632969871181564815,-261115486097641517753,true,460572135501616131424
+500000000000000000,200000000000000000,80,1000000000000000000,80,61982651667291683137,-259241216017636384938,true,428547893524583801267
+500000000000000000,300000000000000000,30,200000000000000000,80,34538841960203899843,-127013832338825880826,true,131323188241454412199
+500000000000000000,300000000000000000,30,500000000000000000,80,27103812109069946678,-119357628782690322603,true,123282017789984093166
+500000000000000000,300000000000000000,30,1000000000000000000,80,35031536619837987338,-118715123688777620135,true,118173490035489203174
+500000000000000000,300000000000000000,50,200000000000000000,80,70793761337372631788,-197023506618685753315,true,253188476130364119821
+500000000000000000,300000000000000000,50,500000000000000000,80,45160064447757984142,-190528744609480208120,true,228173221415754471786
+500000000000000000,300000000000000000,50,1000000000000000000,80,32255668941515526011,-178104785832190684348,true,211920874224451287779
+500000000000000000,300000000000000000,80,200000000000000000,80,70976685443335367733,-219156108495643696441,true,407244156287009288505
+500000000000000000,300000000000000000,80,500000000000000000,80,62983860045325135955,-267178171921048145980,true,407833003380206788801
+500000000000000000,300000000000000000,80,1000000000000000000,80,60105995506427441011,-257897460005444137012,true,375421179830147532657
+500000000000000000,400000000000000000,30,200000000000000000,80,35677891879784204126,-103508219776316577574,true,109501690408097556667
+500000000000000000,400000000000000000,30,500000000000000000,80,30103557030084122159,-103638201376493037537,true,104053565890733664848
+500000000000000000,400000000000000000,30,1000000000000000000,80,22164257622766989250,-103032221403716395185,true,102747368693468312473
+500000000000000000,400000000000000000,50,200000000000000000,80,66274769568476490417,-157918847632576875598,true,200003311143820214148
+500000000000000000,400000000000000000,50,500000000000000000,80,62637499419605255260,-148973288226574640181,true,187109673926980077474
+500000000000000000,400000000000000000,50,1000000000000000000,80,40041383443524099903,-140195496050596969238,true,172077671723566878256
+500000000000000000,400000000000000000,80,200000000000000000,80,67583474435264671932,-181761222031898938291,true,329300627735663135156
+500000000000000000,400000000000000000,80,500000000000000000,80,61688497390002116798,-214023968137309065044,true,329938892752459499216
+500000000000000000,400000000000000000,80,1000000000000000000,80,54112381876491304163,-210650036311846002614,true,305446745987071200232
+500000000000000000,500000000000000000,30,200000000000000000,80,26087463229660139043,-90846892907319251173,true,95254486600679119959
+500000000000000000,500000000000000000,30,500000000000000000,80,20609509697044266641,-90794969531731228761,true,94581815348815544245
+500000000000000000,500000000000000000,30,1000000000000000000,80,18615877540679967888,-91434113077011390444,true,94048296144574411478
+500000000000000000,500000000000000000,50,200000000000000000,80,48995154096876831686,-134455190014312922748,true,163840444475274359574
+500000000000000000,500000000000000000,50,500000000000000000,80,35457695737137372910,-126990090068980061222,true,153435455139368155006
+500000000000000000,500000000000000000,50,1000000000000000000,80,31674022455427490050,-122448139594092920763,true,151294376817807220024
+500000000000000000,500000000000000000,80,200000000000000000,80,70351294909313197251,-185539476141624759553,true,293987377910008696590
+500000000000000000,500000000000000000,80,500000000000000000,80,68363250503695078956,-179355559231500348303,true,276188556134828461258
+500000000000000000,500000000000000000,80,1000000000000000000,80,62882051832966425927,-183218740689457814418,true,263097129816514472354
+500000000000000000,700000000000000000,30,200000000000000000,80,14672884841177386083,-73170085613778221244,true,81144908807858117272
+500000000000000000,700000000000000000,30,500000000000000000,80,15883215019214578931,-73432560581904692121,true,82488998712992121142
+500000000000000000,700000000000000000,30,1000000000000000000,80,19749698463053482590,-74339238958136662653,true,81126794756404617511
+500000000000000000,700000000000000000,50,200000000000000000,80,30116321085729410620,-89700297321919080105,true,114818465834302120477
+500000000000000000,700000000000000000,50,500000000000000000,80,22861491564074840295,-86386908167346397241,true,113889491367005838542
+500000000000000000,700000000000000000,50,1000000000000000000,80,17204104162512802251,-86974578065788181960,true,113013711279050566202
+500000000000000000,700000000000000000,80,200000000000000000,80,56911187539240733164,-125008621608389764880,true,192171714851499481658
+500000000000000000,700000000000000000,80,500000000000000000,80,55491605061147183068,-122038465663306578447,true,183882303683333002041
+500000000000000000,700000000000000000,80,1000000000000000000,80,43996304322381777452,-123131747697630669686,true,172629532441593810792
+500000000000000000,1000000000000000000,30,200000000000000000,80,14488833876677040228,-64457071415888606787,true,83099248580858262094
+500000000000000000,1000000000000000000,30,500000000000000000,80,17352784622264510429,-62342972568557503764,true,80882184967214463719
+500000000000000000,1000000000000000000,30,1000000000000000000,80,20062650065406007663,-61356883860937814021,true,82860657952626967279
+500000000000000000,1000000000000000000,50,200000000000000000,80,22202712740271559742,-64801948701401687396,true,91840223767196160627
+500000000000000000,1000000000000000000,50,500000000000000000,80,19768483654867759052,-63141945689631744199,true,67471684819300492248
+500000000000000000,1000000000000000000,50,1000000000000000000,80,23500732957913414039,-63107207879210619169,true,72112923440198258571
+500000000000000000,1000000000000000000,80,200000000000000000,80,44194855451167647673,-84430338015995379687,true,122043065665834779949
+500000000000000000,1000000000000000000,80,500000000000000000,80,41600977174740418222,-81524195953737881264,true,116276324219682089389
+500000000000000000,1000000000000000000,80,1000000000000000000,80,38552723894523388645,-85329661234512118904,true,112213452188844606617
+800000000000000000,100000000000000000,30,200000000000000000,80,36905336156534684556,-171371790526992377987,true,264620293310099405957
+800000000000000000,100000000000000000,30,500000000000000000,80,19195504442807786011,-169089212169222660103,true,262498445161576015305
+800000000000000000,100000000000000000,30,1000000000000000000,80,13338202761233202431,-156803013686707012080,true,248276112491961513602
+800000000000000000,100000000000000000,50,200000000000000000,80,38058042759277885532,-202612059110886545239,true,379693615612309742627
+800000000000000000,100000000000000000,50,500000000000000000,80,36852273288214659043,-187420175578405586341,true,348377406343646818806
+800000000000000000,100000000000000000,50,1000000000000000000,80,32342469884268611741,-177620311156643546014,true,333186182812971509378
+800000000000000000,100000000000000000,80,200000000000000000,80,22145899943216375490,-251032036729030608202,true,554183472283769980025
+800000000000000000,100000000000000000,80,500000000000000000,80,22419284166685867096,-243129172641849855521,true,513958193324268721943
+800000000000000000,100000000000000000,80,1000000000000000000,80,17467688613630627114,-276987311216036584477,true,512913241543772285054
+800000000000000000,200000000000000000,30,200000000000000000,80,31065103199988951255,-143593461993068451320,true,231636502257266223824
+800000000000000000,200000000000000000,30,500000000000000000,80,22675631660871881181,-106893637308331132525,true,215932889426683393309
+800000000000000000,200000000000000000,30,1000000000000000000,80,21061277865663568593,-141071478485198678793,true,230380815735649317208
+800000000000000000,200000000000000000,50,200000000000000000,80,32294340788263924877,-158375965418989578409,true,306898553243877227333
+800000000000000000,200000000000000000,50,500000000000000000,80,31786283323356027980,-154957820727680939814,true,294047098133520390290
+800000000000000000,200000000000000000,50,1000000000000000000,80,27494765792646536294,-154127626169673341154,true,288140029698097227289
+800000000000000000,200000000000000000,80,200000000000000000,80,23756443429234964499,-197956232742756670716,true,431280354909927238977
+800000000000000000,200000000000000000,80,500000000000000000,80,22619980599634655837,-223527231477159307931,true,432099188075514099550
+800000000000000000,200000000000000000,80,1000000000000000000,80,18496350812883736769,-220457937514786812505,true,413701684850142940952
+800000000000000000,300000000000000000,30,200000000000000000,80,27901334692866743353,-136668570069891498135,true,216296271289601050441
+800000000000000000,300000000000000000,30,500000000000000000,80,27103812109069946678,-103810360209599751554,true,198676019109835727335
+800000000000000000,300000000000000000,30,1000000000000000000,80,15167241907887095695,-99231307048051047347,true,195120962383670863949
+800000000000000000,300000000000000000,50,200000000000000000,80,31983229354294288690,-132591452604911881836,true,260892961393253677285
+800000000000000000,300000000000000000,50,500000000000000000,80,28164603926372893533,-129096406965735370237,true,258016718812427868422
+800000000000000000,300000000000000000,50,1000000000000000000,80,25482882866370742539,-129399676492688675736,true,251054432947853040160
+800000000000000000,300000000000000000,80,200000000000000000,80,23035705841219707082,-187421975163448294149,true,384445209125342488932
+800000000000000000,300000000000000000,80,500000000000000000,80,29077955346439466636,-173468098949990015840,true,356865853379189253710
+800000000000000000,300000000000000000,80,1000000000000000000,80,18536073384736111188,-177683503713478055344,true,345711726590259520354
+800000000000000000,400000000000000000,30,200000000000000000,80,26260247285102961706,-87468925181602760369,true,187267932533623614774
+800000000000000000,400000000000000000,30,500000000000000000,80,23890236047907060801,-89193603927679563026,true,186321311345585310608
+800000000000000000,400000000000000000,30,1000000000000000000,80,22164257622766989250,-91363581482957249444,true,190795273652333207670
+800000000000000000,400000000000000000,50,200000000000000000,80,28820386942698714471,-108742209300118109246,true,230683078062454922799
+800000000000000000,400000000000000000,50,500000000000000000,80,24223389724458513022,-110399096174250294967,true,225189808870007163628
+800000000000000000,400000000000000000,50,1000000000000000000,80,23434669951968625250,-107852054006081952742,true,227269093441876833567
+800000000000000000,400000000000000000,80,200000000000000000,80,31429959225488399978,-149704918054505559093,true,319169461064250188164
+800000000000000000,400000000000000000,80,500000000000000000,80,28422479260053691234,-141754395079672359988,true,300610412993899447332
+800000000000000000,400000000000000000,80,1000000000000000000,80,26156986822633581923,-136754850579053842712,true,295366574525089053281
+800000000000000000,500000000000000000,30,200000000000000000,80,20129703895388473151,-85839715094773432645,true,187860925171176099557
+800000000000000000,500000000000000000,30,500000000000000000,80,17719218011545819620,-86812492558089974199,true,188131742239938141930
+800000000000000000,500000000000000000,30,1000000000000000000,80,18615877540679967888,-86275010007780891931,true,186172116415780720864
+800000000000000000,500000000000000000,50,200000000000000000,80,21834556016404270940,-94098823856410024921,true,206800030579192303067
+800000000000000000,500000000000000000,50,500000000000000000,80,20570474444971935923,-90733491609929923824,true,207294078378913221657
+800000000000000000,500000000000000000,50,1000000000000000000,80,19627245786589672051,-90045735009417035197,true,207155106719503616524
+800000000000000000,500000000000000000,80,200000000000000000,80,30261400528168642864,-121436373923420292187,true,271202927101493819090
+800000000000000000,500000000000000000,80,500000000000000000,80,25740210272387031574,-116828814141372694492,true,262822672794623939799
+800000000000000000,500000000000000000,80,1000000000000000000,80,24594637054396371609,-113440095573296020588,true,254275757231432892909
+800000000000000000,700000000000000000,30,200000000000000000,80,9471339372967042621,-93998437958296104276,true,189693865047187048713
+800000000000000000,700000000000000000,30,500000000000000000,80,10657517196797271583,-93835485015950227194,true,189676887206548556143
+800000000000000000,700000000000000000,30,1000000000000000000,80,19749698463053482590,-92640208096258511891,true,191103747383389375792
+800000000000000000,700000000000000000,50,200000000000000000,80,14828334758639986429,-89305316989103735927,true,194177187371619811418
+800000000000000000,700000000000000000,50,500000000000000000,80,12925429302228230051,-91605937753739683882,true,192769638795558167374
+800000000000000000,700000000000000000,50,1000000000000000000,80,12371045867822184539,-93220760704551967972,true,192517045178546294484
+800000000000000000,700000000000000000,80,200000000000000000,80,23054771736948570367,-103982735347410476013,true,216862315623127923073
+800000000000000000,700000000000000000,80,500000000000000000,80,21233565037410265573,-99334603707250807450,true,214918336790619778086
+800000000000000000,700000000000000000,80,1000000000000000000,80,18953945724970167970,-104630188452660080484,true,212868313554923304854
+800000000000000000,1000000000000000000,30,200000000000000000,80,12799419517002840484,-95301900922670605048,true,199753716177349409739
+800000000000000000,1000000000000000000,30,500000000000000000,80,13897524752255559121,-98307695955918542148,true,197049050134197580201
+800000000000000000,1000000000000000000,30,1000000000000000000,80,16573634285638715620,-86765945330479750502,true,191930843763866869468
+800000000000000000,1000000000000000000,50,200000000000000000,80,7809100589691159823,-93800515444879906672,true,173600205281731715780
+800000000000000000,1000000000000000000,50,500000000000000000,80,7616068263028317786,-90770736392856725540,true,172359452971360399663
+800000000000000000,1000000000000000000,50,1000000000000000000,80,18521941207394758653,-86847506107369858404,true,175419686813318797994
+800000000000000000,1000000000000000000,80,200000000000000000,80,18894595240345422887,-84540823289529917771,true,163071117580484715820
+800000000000000000,1000000000000000000,80,500000000000000000,80,18720498797532172895,-86618984325279010053,true,164490522064959025991
+800000000000000000,1000000000000000000,80,1000000000000000000,80,16033994108252459502,-83772847866938879484,true,163629468088936677962
diff --git a/onchain/test/ReplayProfitableScenario.t.sol b/onchain/test/ReplayProfitableScenario.t.sol
index ded1f82..1b9c952 100644
--- a/onchain/test/ReplayProfitableScenario.t.sol
+++ b/onchain/test/ReplayProfitableScenario.t.sol
@@ -205,7 +205,7 @@ contract ReplayProfitableScenario is Test {
return;
}
- SwapExecutor executor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm);
+ SwapExecutor executor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm, false);
vm.prank(buyer);
weth.transfer(address(executor), amount);
@@ -222,7 +222,7 @@ contract ReplayProfitableScenario is Test {
if (amount == 0) return;
}
- SwapExecutor executor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm);
+ SwapExecutor executor = new SwapExecutor(pool, weth, kraiken, token0isWeth, lm, false);
vm.prank(seller);
kraiken.transfer(address(executor), amount);
diff --git a/onchain/test/mocks/ConfigurableOptimizer.sol b/onchain/test/mocks/ConfigurableOptimizer.sol
new file mode 100644
index 0000000..5aa2668
--- /dev/null
+++ b/onchain/test/mocks/ConfigurableOptimizer.sol
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+pragma solidity ^0.8.19;
+
+/// @title ConfigurableOptimizer
+/// @notice Optimizer mock with directly settable parameters for parameter sweep fuzzing
+/// @dev Parameters are set via constructor or setter, not environment variables (Solidity can't read env)
+contract ConfigurableOptimizer {
+ uint256 private _capitalInefficiency;
+ uint256 private _anchorShare;
+ uint24 private _anchorWidth;
+ uint256 private _discoveryDepth;
+
+ constructor(uint256 capitalInefficiency_, uint256 anchorShare_, uint24 anchorWidth_, uint256 discoveryDepth_) {
+ _capitalInefficiency = capitalInefficiency_;
+ _anchorShare = anchorShare_;
+ _anchorWidth = anchorWidth_;
+ _discoveryDepth = discoveryDepth_;
+ }
+
+ function setParams(uint256 capitalInefficiency_, uint256 anchorShare_, uint24 anchorWidth_, uint256 discoveryDepth_) external {
+ _capitalInefficiency = capitalInefficiency_;
+ _anchorShare = anchorShare_;
+ _anchorWidth = anchorWidth_;
+ _discoveryDepth = discoveryDepth_;
+ }
+
+ function calculateSentiment(uint256, uint256) public pure returns (uint256) {
+ return 0;
+ }
+
+ function getSentiment() external pure returns (uint256) {
+ return 0;
+ }
+
+ function getLiquidityParams() external view returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) {
+ capitalInefficiency = _capitalInefficiency;
+ anchorShare = _anchorShare;
+ anchorWidth = _anchorWidth;
+ discoveryDepth = _discoveryDepth;
+ }
+
+ function getDescription() external pure returns (string memory) {
+ return "Configurable Optimizer (Parameter Sweep)";
+ }
+}
diff --git a/web-app/src/views/CheatsView.vue b/web-app/src/views/CheatsView.vue
index 3df6cbb..a70ba98 100644
--- a/web-app/src/views/CheatsView.vue
+++ b/web-app/src/views/CheatsView.vue
@@ -75,6 +75,25 @@
+ Loading protocol stats… {{ statCollection.statsError }}