// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.19; /** * @title Simple Scenario Analysis for LiquidityManager * @notice Lightweight analysis script for researching profitable trading scenarios * @dev Separated from unit tests to focus on research and scenario discovery * Run with: forge script analysis/SimpleAnalysis.s.sol --ffi */ import "../test/LiquidityManager.t.sol"; contract SimpleAnalysis is LiquidityManagerTest { uint256 public scenariosAnalyzed; uint256 public profitableScenarios; /// @notice Entry point for forge script execution function run() public { console.log("Starting LiquidityManager Scenario Analysis..."); console.log("This will analyze trading scenarios for profitability."); // Example analysis with predefined parameters uint8[] memory amounts = new uint8[](10); amounts[0] = 100; amounts[1] = 50; amounts[2] = 75; amounts[3] = 120; amounts[4] = 30; amounts[5] = 90; amounts[6] = 45; amounts[7] = 110; amounts[8] = 60; amounts[9] = 80; runAnalysis(10, 3, amounts); console.log("Analysis complete. Check statistics:"); (uint256 total, uint256 profitable) = getStats(); console.log("Total scenarios:", total); console.log("Profitable scenarios:", profitable); } /// @notice Analyzes a trading scenario for profitability /// @dev Records CSV data if profitable - THIS IS NOT A UNIT TEST function runAnalysis(uint8 numActions, uint8 frequency, uint8[] memory amounts) public { // Bound inputs vm.assume(numActions > 3 && numActions <= 50); vm.assume(frequency > 0 && frequency < 20); vm.assume(amounts.length >= numActions); // Setup _setupCustom(false, 50 ether); uint256 balanceBefore = weth.balanceOf(account); // Execute trading sequence (need to convert memory to calldata) _executeRandomTradingSequenceWrapper(numActions, frequency, amounts); uint256 balanceAfter = weth.balanceOf(account); scenariosAnalyzed++; // Check profitability if (balanceAfter > balanceBefore) { profitableScenarios++; uint256 profit = balanceAfter - balanceBefore; console.log("[ALERT] Profitable scenario found!"); console.log("Profit:", vm.toString(profit)); console.log("Actions:", numActions); console.log("Frequency:", frequency); // Write CSV for analysis to analysis folder writeCSVToFile("./analysis/profitable_scenario.csv"); } console.log("Scenario", scenariosAnalyzed, balanceAfter > balanceBefore ? "PROFIT" : "SAFE"); } /// @notice Wrapper to handle memory to calldata conversion function _executeRandomTradingSequenceWrapper(uint8 numActions, uint8 frequency, uint8[] memory amounts) internal { // Create a simple trading sequence without the complex calldata dependency uint8 f = 0; for (uint i = 0; i < numActions && i < amounts.length; i++) { uint256 amount = (uint256(amounts[i]) * 1 ether) + 1 ether; uint256 harbergBal = harberg.balanceOf(account); // Execute trade based on current balances if (harbergBal == 0) { amount = amount % (weth.balanceOf(account) / 2); amount = amount == 0 ? weth.balanceOf(account) / 10 : amount; if (amount > 0) buy(amount); } else if (weth.balanceOf(account) == 0) { sell(amount % harbergBal); } else { if (amount % 2 == 0) { amount = amount % (weth.balanceOf(account) / 2); amount = amount == 0 ? weth.balanceOf(account) / 10 : amount; if (amount > 0) buy(amount); } else { sell(amount % harbergBal); } } // Periodic recentering if (f >= frequency) { recenter(false); f = 0; } else { f++; } } // Final cleanup uint256 finalHarbBal = harberg.balanceOf(account); if (finalHarbBal > 0) { sell(finalHarbBal); } recenter(true); } /// @notice Get analysis statistics function getStats() public view returns (uint256 total, uint256 profitable) { return (scenariosAnalyzed, profitableScenarios); } }