fixed visualizer
This commit is contained in:
parent
e021aff978
commit
c2d7c3c6c3
4 changed files with 138 additions and 46 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue