2026-02-04 20:58:30 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
pragma solidity ^0.8.19;
|
|
|
|
|
|
|
|
|
|
import { ConfigurableOptimizer } from "../test/mocks/ConfigurableOptimizer.sol";
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
import { FuzzingBase } from "./helpers/FuzzingBase.sol";
|
2026-02-04 20:58:30 +00:00
|
|
|
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).
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
contract ParameterSweepFuzzing is FuzzingBase {
|
2026-02-04 20:58:30 +00:00
|
|
|
ConfigurableOptimizer optimizer;
|
|
|
|
|
|
|
|
|
|
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"));
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
_initInfrastructure();
|
2026-02-04 20:58:30 +00:00
|
|
|
|
|
|
|
|
summaryFile = string(abi.encodePacked("analysis/sweep-", tag, "-summary.csv"));
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
vm.writeFile(summaryFile, "ci,anchor_share,anchor_width,discovery_depth,buy_bias,worst_trader_pnl,best_trader_pnl,any_lm_loss,lm_eth_delta\n");
|
2026-02-04 20:58:30 +00:00
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
optimizer = new ConfigurableOptimizer(ci, as_, aw, dd);
|
|
|
|
|
cfgBuyBias = bb;
|
|
|
|
|
|
|
|
|
|
// Setup environment once — VWAP accumulates across all runs
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
_setupEnvironment(address(optimizer), comboIdx % 2 == 0, cfgUncapped);
|
2026-02-04 20:58:30 +00:00
|
|
|
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
int256 worstPnl = type(int256).min;
|
|
|
|
|
int256 bestPnl = type(int256).max;
|
2026-02-04 20:58:30 +00:00
|
|
|
bool anyLoss = false;
|
|
|
|
|
|
|
|
|
|
uint256 lmSystemStart = _getLmSystemEth();
|
|
|
|
|
|
|
|
|
|
for (uint256 runIdx = 0; runIdx < cfgRunsPerCombo; runIdx++) {
|
|
|
|
|
RunResult memory result = _executeRun(runIdx);
|
|
|
|
|
|
|
|
|
|
int256 pnl = int256(result.traderFinalEth) - int256(result.traderInitEth);
|
|
|
|
|
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
if (pnl > worstPnl) worstPnl = pnl;
|
|
|
|
|
if (pnl < bestPnl) bestPnl = pnl;
|
2026-02-04 20:58:30 +00:00
|
|
|
if (pnl > 0) anyLoss = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint256 lmSystemEnd = _getLmSystemEth();
|
|
|
|
|
int256 lmDelta = int256(lmSystemEnd) - int256(lmSystemStart);
|
|
|
|
|
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
// Write summary row
|
2026-02-04 20:58:30 +00:00
|
|
|
string memory row = string(abi.encodePacked(vm.toString(ci), ",", vm.toString(as_), ",", vm.toString(uint256(aw)), ","));
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
row = string(abi.encodePacked(row, vm.toString(dd), ",", vm.toString(bb), ",", vm.toString(worstPnl), ","));
|
|
|
|
|
row = string(abi.encodePacked(row, vm.toString(bestPnl), ",", anyLoss ? "true" : "false", ",", vm.toString(lmDelta)));
|
2026-02-04 20:58:30 +00:00
|
|
|
vm.writeLine(summaryFile, row);
|
|
|
|
|
|
|
|
|
|
if (anyLoss) {
|
|
|
|
|
console2.log("UNSAFE combo", comboIdx);
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
console2.log(" worstPnl:", worstPnl);
|
2026-02-04 20:58:30 +00:00
|
|
|
console2.log(" lmDelta:", lmDelta);
|
|
|
|
|
} else if (comboIdx % 5 == 0) {
|
|
|
|
|
console2.log("Progress:", comboIdx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _executeRun(uint256 runIndex) internal returns (RunResult memory result) {
|
|
|
|
|
// DON'T re-setup environment — reuse existing so VWAP accumulates
|
|
|
|
|
result.lmEthInit = _getLmSystemEth();
|
|
|
|
|
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
// Clean up leftover tokens from previous run to prevent PnL leakage
|
|
|
|
|
_cleanupTraderTokens();
|
|
|
|
|
|
2026-02-04 20:58:30 +00:00
|
|
|
// Fund trader fresh each run
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
vm.deal(trader, LM_FUNDING_ETH);
|
2026-02-04 20:58:30 +00:00
|
|
|
vm.prank(trader);
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
weth.deposit{ value: LM_FUNDING_ETH }();
|
2026-02-04 20:58:30 +00:00
|
|
|
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) {
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
uint256 range = cfgMaxBuy - cfgMinBuy;
|
|
|
|
|
uint256 amount = (cfgMinBuy * 1 ether) + (uint256(keccak256(abi.encodePacked(runIndex, i, "buy"))) % (range * 1 ether));
|
|
|
|
|
if (!_executeBuy(amount)) result.numBuysFailed++;
|
2026-02-04 20:58:30 +00:00
|
|
|
} else {
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
uint256 krkBal = kraiken.balanceOf(trader);
|
|
|
|
|
if (krkBal > 0) {
|
|
|
|
|
uint256 pct = SELL_PCT_MIN + (uint256(keccak256(abi.encodePacked(runIndex, i, "sell"))) % SELL_PCT_RANGE);
|
|
|
|
|
uint256 amount = krkBal * pct / 100;
|
|
|
|
|
_executeSell(amount);
|
|
|
|
|
}
|
2026-02-04 20:58:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_tryRecenter();
|
|
|
|
|
_liquidateTraderHoldings();
|
chore: analysis tooling, research artifacts, and code quality
- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps
- Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT
- FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation
- Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear,
AS sweep, VWAP fix validation
- Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs
- Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:22:03 +00:00
|
|
|
_recoverStuckTokens();
|
2026-02-04 20:58:30 +00:00
|
|
|
|
|
|
|
|
result.lmEthFinal = _getLmSystemEth();
|
|
|
|
|
result.traderFinalEth = weth.balanceOf(trader);
|
|
|
|
|
}
|
|
|
|
|
}
|