diff --git a/onchain/analysis/CLAUDE.md b/onchain/analysis/CLAUDE.md index f98c40e..4944885 100644 --- a/onchain/analysis/CLAUDE.md +++ b/onchain/analysis/CLAUDE.md @@ -2,6 +2,8 @@ Tools for testing the KRAIKEN LiquidityManager's resilience against various trading strategies to identify scenarios where traders can profit. +**CRITICAL**: THE IMPLEMENTATION IS NOT TO BE CHANGED. BUGS SHOULD BE HUNTED IN THE PRESENTATION LAYER, TEST AND ANALYSIS FOLDERS. + ## Quick Start ```bash diff --git a/onchain/analysis/FuzzingAnalysis.s.sol b/onchain/analysis/FuzzingAnalysis.s.sol index ec4b80f..1631ba5 100644 --- a/onchain/analysis/FuzzingAnalysis.s.sol +++ b/onchain/analysis/FuzzingAnalysis.s.sol @@ -19,6 +19,7 @@ import "../test/mocks/MockOptimizer.sol"; import "../test/mocks/RandomScenarioOptimizer.sol"; import "./helpers/CSVManager.sol"; import "./helpers/SwapExecutor.sol"; +import {LiquidityAmounts} from "@aperture/uni-v3-lib/LiquidityAmounts.sol"; /** * @title FuzzingAnalysis @@ -330,19 +331,24 @@ contract FuzzingAnalysis is Test, CSVManager { } function _recordPositionData(string memory label) internal { - (,int24 currentTick,,,,,) = pool.slot0(); + (uint160 sqrtPriceX96,int24 currentTick,,,,,) = pool.slot0(); // Get each position (uint128 floorLiq, int24 floorLower, int24 floorUpper) = lm.positions(ThreePositionStrategy.Stage.FLOOR); (uint128 anchorLiq, int24 anchorLower, int24 anchorUpper) = lm.positions(ThreePositionStrategy.Stage.ANCHOR); (uint128 discoveryLiq, int24 discoveryLower, int24 discoveryUpper) = lm.positions(ThreePositionStrategy.Stage.DISCOVERY); - // Calculate ETH and HARB amounts in each position - // For visualization purposes, we'll estimate based on liquidity distribution - uint256 totalLiq = uint256(floorLiq) + uint256(anchorLiq) + uint256(discoveryLiq); - uint256 totalEth = weth.balanceOf(address(lm)); - uint256 totalHarb = harberg.balanceOf(address(lm)); + // Debug: Log liquidity values + if (keccak256(bytes(label)) == keccak256(bytes("Initial"))) { + console.log("=== LIQUIDITY VALUES ==="); + console.log("Floor liquidity:", uint256(floorLiq)); + console.log("Anchor liquidity:", uint256(anchorLiq)); + console.log("Discovery liquidity:", uint256(discoveryLiq)); + console.log("Floor range:", uint256(int256(floorLower)), "-", uint256(int256(floorUpper))); + console.log("Current tick:", uint256(int256(currentTick))); + } + // Calculate ETH and HARB amounts in each position using proper Uniswap math uint256 floorEth = 0; uint256 floorHarb = 0; uint256 anchorEth = 0; @@ -350,19 +356,100 @@ contract FuzzingAnalysis is Test, CSVManager { uint256 discoveryEth = 0; uint256 discoveryHarb = 0; - if (totalLiq > 0) { - // Rough approximation based on whether current tick is in range - if (currentTick >= floorLower && currentTick < floorUpper && floorLiq > 0) { - floorEth = (totalEth * uint256(floorLiq)) / totalLiq / 2; - floorHarb = (totalHarb * uint256(floorLiq)) / totalLiq / 2; + // Calculate amounts for each position using LiquidityAmounts library + if (floorLiq > 0) { + uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(floorLower); + uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(floorUpper); + + // Calculate actual deposited amounts based on position relative to current price + if (token0isWeth) { + if (currentTick < floorLower) { + // Position is above current price - contains only token1 (KRAIKEN) + floorEth = 0; + // Use position's lower tick for actual deposited amount + floorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq); + } else if (currentTick >= floorUpper) { + // Position is below current price - contains only token0 (WETH) + // Use position's upper tick for actual deposited amount + floorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq); + floorHarb = 0; + } else { + // Current price is within the position + floorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, floorLiq); + floorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, floorLiq); + } + } else { + if (currentTick < floorLower) { + // Position is above current price + floorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq); + floorEth = 0; + } else if (currentTick >= floorUpper) { + // Position is below current price + floorHarb = 0; + floorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, floorLiq); + } else { + // Current price is within the position + floorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, floorLiq); + floorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, floorLiq); + } } - if (currentTick >= anchorLower && currentTick < anchorUpper && anchorLiq > 0) { - anchorEth = (totalEth * uint256(anchorLiq)) / totalLiq / 2; - anchorHarb = (totalHarb * uint256(anchorLiq)) / totalLiq / 2; + } + + if (anchorLiq > 0) { + uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(anchorLower); + uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(anchorUpper); + + if (token0isWeth) { + if (currentTick < anchorLower) { + anchorEth = 0; + anchorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq); + } else if (currentTick >= anchorUpper) { + anchorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq); + anchorHarb = 0; + } else { + anchorEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, anchorLiq); + anchorHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, anchorLiq); + } + } else { + if (currentTick < anchorLower) { + anchorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq); + anchorEth = 0; + } else if (currentTick >= anchorUpper) { + anchorHarb = 0; + anchorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, anchorLiq); + } else { + anchorHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, anchorLiq); + anchorEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, anchorLiq); + } } - if (currentTick >= discoveryLower && currentTick < discoveryUpper && discoveryLiq > 0) { - discoveryEth = (totalEth * uint256(discoveryLiq)) / totalLiq / 2; - discoveryHarb = (totalHarb * uint256(discoveryLiq)) / totalLiq / 2; + } + + if (discoveryLiq > 0) { + uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(discoveryLower); + uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(discoveryUpper); + + if (token0isWeth) { + if (currentTick < discoveryLower) { + discoveryEth = 0; + discoveryHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq); + } else if (currentTick >= discoveryUpper) { + discoveryEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq); + discoveryHarb = 0; + } else { + discoveryEth = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, discoveryLiq); + discoveryHarb = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, discoveryLiq); + } + } else { + if (currentTick < discoveryLower) { + discoveryHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq); + discoveryEth = 0; + } else if (currentTick >= discoveryUpper) { + discoveryHarb = 0; + discoveryEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, discoveryLiq); + } else { + discoveryHarb = LiquidityAmounts.getAmount0ForLiquidity(sqrtPriceX96, sqrtRatioBX96, discoveryLiq); + discoveryEth = LiquidityAmounts.getAmount1ForLiquidity(sqrtRatioAX96, sqrtPriceX96, discoveryLiq); + } } } diff --git a/onchain/analysis/helpers/CSVHelper.sol b/onchain/analysis/helpers/CSVHelper.sol index 5e00b43..1faa13b 100644 --- a/onchain/analysis/helpers/CSVHelper.sol +++ b/onchain/analysis/helpers/CSVHelper.sol @@ -15,7 +15,7 @@ library CSVHelper { */ function createPositionsHeader() internal pure returns (string memory) { return - "precedingAction, currentTick, floorTickLower, floorTickUpper, floorEth, floorHarb, anchorTickLower, anchorTickUpper, anchorEth, anchorHarb, discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryHarb, token0isWeth"; + "precedingAction, currentTick, floorTickLower, floorTickUpper, floorToken0, floorToken1, anchorTickLower, anchorTickUpper, anchorToken0, anchorToken1, discoveryTickLower, discoveryTickUpper, discoveryToken0, discoveryToken1, token0isWeth"; } function createTimeSeriesHeader() internal pure returns (string memory) { diff --git a/onchain/analysis/scenario-visualizer.html b/onchain/analysis/scenario-visualizer.html index 0e0226e..8c70d05 100644 --- a/onchain/analysis/scenario-visualizer.html +++ b/onchain/analysis/scenario-visualizer.html @@ -125,10 +125,10 @@