fixed visualizer

This commit is contained in:
johba 2025-08-10 11:56:21 +02:00
parent e021aff978
commit c2d7c3c6c3
4 changed files with 138 additions and 46 deletions

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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) {

View file

@ -125,10 +125,10 @@
<body>
<h2>Kraiken Liquidity Position Simulator</h2>
<div style="background-color: #e3f2fd; border-radius: 4px; padding: 15px; margin-bottom: 20px; border-left: 4px solid #2196f3;">
<strong>📊 Anti-Arbitrage Three-Position Strategy (After Token Assignment Fix)</strong><br>
<em>Floor (ETH Reserve)</em>: Deep liquidity holding ETH for dormant whale protection<br>
<em>Anchor (Shallow Pool)</em>: Mixed tokens around current price for fast slippage<br>
<em>Discovery (KRAIKEN Mint)</em>: Deep edge liquidity minting KRAIKEN for price expansion
<strong>📊 Anti-Arbitrage Three-Position Strategy</strong><br>
<em>Floor</em>: Deep liquidity position - contains ETH when below current price, KRAIKEN when above<br>
<em>Anchor</em>: Shallow liquidity around current price for fast slippage<br>
<em>Discovery</em>: Edge liquidity position - contains KRAIKEN when below current price, ETH when above
</div>
<div id="status">Loading profitable scenario data...</div>
<textarea id="csvInput" placeholder="Paste CSV formatted data here..." style="display: none;"></textarea>
@ -157,10 +157,10 @@
// Default matches test setup: DEFAULT_TOKEN0_IS_WETH = false
const ethIsToken0 = false;
// Position Economic Model (After Token Assignment Fix):
// - Floor Position: Primarily holds ETH for dormant whale protection
// Position Economic Model:
// - Floor Position: Deep liquidity - holds KRAIKEN above price, ETH below price
// - Anchor Position: Mixed tokens around current price for shallow liquidity
// - Discovery Position: Primarily holds KRAIKEN for price discovery expansion
// - Discovery Position: Edge liquidity - holds ETH above price, KRAIKEN below price
// Auto-load CSV data on page load
document.addEventListener('DOMContentLoaded', function() {
@ -248,37 +248,40 @@
data.forEach(row => {
const precedingAction = row.precedingAction;
const currentTick = parseFloat(row.currentTick);
const token0isWeth = row.token0isWeth === 'true' || row.token0isWeth === true;
const floorTickLower = parseFloat(row.floorTickLower);
const floorTickUpper = parseFloat(row.floorTickUpper);
const floorEth = parseFloat(row.floorEth) / 1e18;
const floorKraiken = parseFloat(row.floorHarb) / 1e18; // Updated from floorHarb
// Swap floor values to match expected behavior
const floorEth = parseFloat(row.floorToken1 || row.floorHarb) / 1e18;
const floorKraiken = parseFloat(row.floorToken0 || row.floorEth) / 1e18;
const anchorTickLower = parseFloat(row.anchorTickLower);
const anchorTickUpper = parseFloat(row.anchorTickUpper);
const anchorEth = parseFloat(row.anchorEth) / 1e18;
const anchorKraiken = parseFloat(row.anchorHarb) / 1e18; // Updated from anchorHarb
const anchorEth = parseFloat(row.anchorToken0 || row.anchorEth) / 1e18;
const anchorKraiken = parseFloat(row.anchorToken1 || row.anchorHarb) / 1e18;
const discoveryTickLower = parseFloat(row.discoveryTickLower);
const discoveryTickUpper = parseFloat(row.discoveryTickUpper);
const discoveryEth = parseFloat(row.discoveryEth) / 1e18;
const discoveryKraiken = parseFloat(row.discoveryHarb) / 1e18; // Updated from discoveryHarb
// Swap discovery values to match expected behavior
const discoveryEth = parseFloat(row.discoveryToken1 || row.discoveryHarb) / 1e18;
const discoveryKraiken = parseFloat(row.discoveryToken0 || row.discoveryEth) / 1e18;
let actionAmount = '';
let additionalInfo = '';
if (previousRow) {
const prevFloorEth = parseFloat(previousRow.floorEth) / 1e18;
const prevFloorKraiken = parseFloat(previousRow.floorHarb) / 1e18;
const prevAnchorEth = parseFloat(previousRow.anchorEth) / 1e18;
const prevAnchorKraiken = parseFloat(previousRow.anchorHarb) / 1e18;
const prevDiscoveryEth = parseFloat(previousRow.discoveryEth) / 1e18;
const prevDiscoveryKraiken = parseFloat(previousRow.discoveryHarb) / 1e18;
const prevFloorEth = parseFloat(previousRow.floorToken1 || previousRow.floorHarb) / 1e18;
const prevFloorKraiken = parseFloat(previousRow.floorToken0 || previousRow.floorEth) / 1e18;
const prevAnchorEth = parseFloat(previousRow.anchorToken0 || previousRow.anchorEth) / 1e18;
const prevAnchorKraiken = parseFloat(previousRow.anchorToken1 || previousRow.anchorHarb) / 1e18;
const prevDiscoveryEth = parseFloat(previousRow.discoveryToken1 || previousRow.discoveryHarb) / 1e18;
const prevDiscoveryKraiken = parseFloat(previousRow.discoveryToken0 || previousRow.discoveryEth) / 1e18;
const ethDifference = (floorEth + anchorEth + discoveryEth) - (prevFloorEth + prevAnchorEth + prevDiscoveryEth);
const kraikenDifference = (floorKraiken + anchorKraiken + discoveryKraiken) - (prevFloorKraiken + prevAnchorKraiken + prevDiscoveryKraiken);
if (precedingAction.startsWith('buy')) {
if (precedingAction.toLowerCase().includes('buy')) {
actionAmount = `${precedingAction} ETH`;
additionalInfo = `(${Math.abs(kraikenDifference).toFixed(6)} KRAIKEN bought)`;
} else if (precedingAction.startsWith('sell')) {
} else if (precedingAction.toLowerCase().includes('sell')) {
actionAmount = `${precedingAction} KRAIKEN`;
additionalInfo = `(${Math.abs(ethDifference).toFixed(6)} ETH bought)`;
} else {
@ -293,7 +296,7 @@
simulateEnhanced(headline, currentTick,
floorTickLower, floorTickUpper, floorEth, floorKraiken,
anchorTickLower, anchorTickUpper, anchorEth, anchorKraiken,
discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken);
discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken, token0isWeth);
previousRow = row;
});
}
@ -359,7 +362,7 @@
function simulateEnhanced(precedingAction, currentTick,
floorTickLower, floorTickUpper, floorEth, floorKraiken,
anchorTickLower, anchorTickUpper, anchorEth, anchorKraiken,
discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken) {
discoveryTickLower, discoveryTickUpper, discoveryEth, discoveryKraiken, token0isWeth) {
// Position data structure with liquidity calculations
const positions = {
@ -368,8 +371,8 @@
tickUpper: floorTickUpper,
eth: floorEth,
kraiken: floorKraiken,
name: 'Floor (ETH Reserve)',
liquidity: ethIsToken0 ?
name: 'Floor',
liquidity: token0isWeth ?
calculateUniV3Liquidity(floorEth, floorKraiken, floorTickLower, floorTickUpper, currentTick) :
calculateUniV3Liquidity(floorKraiken, floorEth, floorTickLower, floorTickUpper, currentTick)
},
@ -379,7 +382,7 @@
eth: anchorEth,
kraiken: anchorKraiken,
name: 'Anchor (Shallow Pool)',
liquidity: ethIsToken0 ?
liquidity: token0isWeth ?
calculateUniV3Liquidity(anchorEth, anchorKraiken, anchorTickLower, anchorTickUpper, currentTick) :
calculateUniV3Liquidity(anchorKraiken, anchorEth, anchorTickLower, anchorTickUpper, currentTick)
},
@ -388,8 +391,8 @@
tickUpper: discoveryTickUpper,
eth: discoveryEth,
kraiken: discoveryKraiken,
name: 'Discovery (KRAIKEN Mint)',
liquidity: ethIsToken0 ?
name: 'Discovery',
liquidity: token0isWeth ?
calculateUniV3Liquidity(discoveryEth, discoveryKraiken, discoveryTickLower, discoveryTickUpper, currentTick) :
calculateUniV3Liquidity(discoveryKraiken, discoveryEth, discoveryTickLower, discoveryTickUpper, currentTick)
}