feat: Optimize discovery position depth calculation

- Implement dynamic discovery depth based on anchor position share
- Add configurable discovery_max_multiple (1.5-4x) for flexible adjustment
- Update BullMarketOptimizer with new depth calculation logic
- Fix scenario visualizer floor position visibility
- Add comprehensive tests for discovery depth behavior

The discovery position now dynamically adjusts its depth based on the anchor
position's share of total liquidity, allowing for more effective price discovery
while maintaining protection against manipulation.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
johba 2025-08-16 16:45:24 +02:00
parent 7ac6b33850
commit 2205ae719b
8 changed files with 383 additions and 95 deletions

View file

@ -76,13 +76,13 @@ contract MockThreePositionStrategy is ThreePositionStrategy {
}
function setAnchorPosition(int24 currentTick, uint256 anchorEthBalance, PositionParams memory params)
external returns (uint256) {
external returns (uint256, uint128) {
return _setAnchorPosition(currentTick, anchorEthBalance, params);
}
function setDiscoveryPosition(int24 currentTick, uint256 pulledHarb, PositionParams memory params)
function setDiscoveryPosition(int24 currentTick, uint128 anchorLiquidity, PositionParams memory params)
external returns (uint256) {
return _setDiscoveryPosition(currentTick, pulledHarb, params);
return _setDiscoveryPosition(currentTick, anchorLiquidity, params);
}
function setFloorPosition(
@ -163,7 +163,7 @@ contract ThreePositionStrategyTest is TestConstants {
ThreePositionStrategy.PositionParams memory params = getDefaultParams();
uint256 anchorEthBalance = 20 ether; // 20% of total
uint256 pulledHarb = strategy.setAnchorPosition(CURRENT_TICK, anchorEthBalance, params);
(uint256 pulledHarb, ) = strategy.setAnchorPosition(CURRENT_TICK, anchorEthBalance, params);
// Verify position was created
assertEq(strategy.getMintedPositionsCount(), 1, "Should have minted one position");
@ -212,16 +212,26 @@ contract ThreePositionStrategyTest is TestConstants {
function testDiscoveryPositionDependsOnAnchor() public {
ThreePositionStrategy.PositionParams memory params = getDefaultParams();
uint256 pulledHarb = 1000 ether; // Simulated from anchor
uint128 anchorLiquidity = 1000e18; // Simulated anchor liquidity
uint256 discoveryAmount = strategy.setDiscoveryPosition(CURRENT_TICK, pulledHarb, params);
uint256 discoveryAmount = strategy.setDiscoveryPosition(CURRENT_TICK, anchorLiquidity, params);
// Discovery amount should be proportional to pulledHarb
// Discovery amount should be proportional to anchor liquidity
assertGt(discoveryAmount, 0, "Discovery amount should be positive");
assertGt(discoveryAmount, pulledHarb / 100, "Discovery should be meaningful portion of pulled HARB");
MockThreePositionStrategy.MintedPosition memory pos = strategy.getMintedPosition(0);
assertEq(uint256(pos.stage), uint256(ThreePositionStrategy.Stage.DISCOVERY), "Should be discovery position");
// Discovery liquidity should ensure multiple times more liquidity per tick
uint256 expectedMultiplier = 200 + (800 * params.discoveryDepth / 10 ** 18);
// Calculate anchor width (same calculation as in _setDiscoveryPosition)
int24 anchorSpacing = 200 + (34 * int24(params.anchorWidth) * 200 / 100);
int24 anchorWidth = 2 * anchorSpacing;
// Adjust for width difference
uint128 expectedLiquidity = uint128(
uint256(anchorLiquidity) * expectedMultiplier * 11000 / (100 * uint256(int256(anchorWidth)))
);
assertEq(pos.liquidity, expectedLiquidity, "Discovery liquidity should match expected multiple adjusted for width");
}
function testDiscoveryPositionPlacement() public {
@ -231,8 +241,8 @@ contract ThreePositionStrategyTest is TestConstants {
// Test with WETH as token0
strategy = new MockThreePositionStrategy(HARB_TOKEN, WETH_TOKEN, token0IsWeth, ETH_BALANCE, OUTSTANDING_SUPPLY);
uint256 pulledHarb = 1000 ether;
strategy.setDiscoveryPosition(CURRENT_TICK, pulledHarb, params);
uint128 anchorLiquidity = 1000e18;
strategy.setDiscoveryPosition(CURRENT_TICK, anchorLiquidity, params);
MockThreePositionStrategy.MintedPosition memory pos = strategy.getMintedPosition(0);
@ -245,12 +255,12 @@ contract ThreePositionStrategyTest is TestConstants {
ThreePositionStrategy.PositionParams memory params = getDefaultParams();
params.discoveryDepth = 10 ** 18; // Maximum depth (100%)
uint256 pulledHarb = 1000 ether;
uint256 discoveryAmount1 = strategy.setDiscoveryPosition(CURRENT_TICK, pulledHarb, params);
uint128 anchorLiquidity = 1000e18;
uint256 discoveryAmount1 = strategy.setDiscoveryPosition(CURRENT_TICK, anchorLiquidity, params);
strategy.clearMintedPositions();
params.discoveryDepth = 0; // Minimum depth
uint256 discoveryAmount2 = strategy.setDiscoveryPosition(CURRENT_TICK, pulledHarb, params);
uint256 discoveryAmount2 = strategy.setDiscoveryPosition(CURRENT_TICK, anchorLiquidity, params);
assertGt(discoveryAmount1, discoveryAmount2, "Higher discovery depth should result in more tokens");
}

View file

@ -16,22 +16,22 @@ contract BullMarketOptimizer {
}
/// @notice Returns whale attack liquidity parameters
/// @return capitalInefficiency 10% - very aggressive
/// @return capitalInefficiency 0% - very aggressive
/// @return anchorShare 95% - massive anchor concentration
/// @return anchorWidth 80 - moderate width
/// @return discoveryDepth 5% - minimal discovery
/// @return anchorWidth 1000 - moderate width
/// @return discoveryDepth Testing value: 1e18
function getLiquidityParams()
external
pure
returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth)
{
capitalInefficiency = 0; // 10% - very aggressive
anchorShare = 1e18; // 95% - massive anchor position
anchorWidth = 1000; // moderate width (was 10)
discoveryDepth = 1e18; // 5% - minimal discovery
capitalInefficiency = 0; // 0% - very aggressive
anchorShare = 95 * 10 ** 16; // 95% - massive anchor position
anchorWidth = 50; // 50% - medium width for concentrated liquidity
discoveryDepth = 1e18; // Testing this value
}
function getDescription() external pure returns (string memory) {
return "Bull Market (Whale Attack Parameters)";
return "Bull Market (Testing discoveryDepth)";
}
}