From 0329a5da4f9702736614dc1ae51e066fca48848a Mon Sep 17 00:00:00 2001 From: roleengineer Date: Tue, 13 Aug 2024 17:06:12 +0300 Subject: [PATCH] priceRatio stored and used in vwap always ETH/HARB. fixed compatibility. --- onchain/src/LiquidityManager.sol | 28 ++++++++++++++++------------ onchain/test/LiquidityManager.t.sol | 9 +++++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/onchain/src/LiquidityManager.sol b/onchain/src/LiquidityManager.sol index 800e3d9..0df1b22 100644 --- a/onchain/src/LiquidityManager.sol +++ b/onchain/src/LiquidityManager.sol @@ -24,7 +24,7 @@ import {Harberg} from "./Harberg.sol"; * - Discovery Position: Expands liquidity by minting new Harberg tokens as the price rises, capturing potential growth in the ecosystem. * The contract dynamically adjusts these positions in response to market movements to maintain strategic liquidity levels and support the Harberg token's price. * It also collects and transfers fees generated from trading activities to a designated fee destination. - * @dev Utilizes Uniswap V3's concentrated liquidity feature, enabling highly efficient use of capital. + * @dev Utilizes Uniswap V3's concentrated liquidity feature, enabling highly efficient use of capital. */ contract LiquidityManager { using Math for uint256; @@ -45,7 +45,7 @@ contract LiquidityManager { // only working with UNI V3 1% fee tier pools uint24 internal constant FEE = uint24(10_000); uint160 internal constant MIN_SQRT_RATIO = 4295128739; - // ANCHOR_LIQ_SHARE is the mininum share of total ETH in control + // ANCHOR_LIQ_SHARE is the mininum share of total ETH in control // that will be left to put into anchor positon. uint256 internal constant MIN_ANCHOR_LIQ_SHARE = 5; // 5 = 5% uint256 internal constant MAX_ANCHOR_LIQ_SHARE = 25; @@ -166,7 +166,8 @@ contract LiquidityManager { function tickAtPrice(bool t0isWeth, uint256 tokenAmount, uint256 ethAmount) internal pure returns (int24 tick_) { require(ethAmount > 0, "ETH amount cannot be zero"); if (tokenAmount == 0) { - tick_ = t0isWeth ? TickMath.MIN_TICK : TickMath.MAX_TICK; + // HARB/ETH + tick_ = TickMath.MAX_TICK; } else { // Use a fixed-point library or more precise arithmetic for the division here. // For example, using ABDKMath64x64 for a more precise division and square root calculation. @@ -174,17 +175,19 @@ contract LiquidityManager { int128(int256(tokenAmount)), int128(int256(ethAmount)) ); - tick_ = tickAtPriceRatio(t0isWeth, priceRatioX64); + // HARB/ETH + tick_ = tickAtPriceRatio(priceRatioX64); } + // convert to tick in a pool + tick_ = t0isWeth ? tick_ : -tick_; } - function tickAtPriceRatio(bool t0isWeth, int128 priceRatioX64) internal pure returns (int24 tick_) { + function tickAtPriceRatio(int128 priceRatioX64) internal pure returns (int24 tick_) { // Convert the price ratio into a sqrt price in the format expected by Uniswap's TickMath. uint160 sqrtPriceX96 = uint160( int160(ABDKMath64x64.sqrt(priceRatioX64) << 32) ); tick_ = TickMath.getTickAtSqrtRatio(sqrtPriceX96); - tick_ = t0isWeth ? tick_ : -tick_; } /// @notice Calculates the price ratio from a given Uniswap V3 tick as HARB/ETH. @@ -241,16 +244,17 @@ contract LiquidityManager { // not enough ETH, find a lower price requiredEthForBuyback = floorEthBalance; vwapTick = tickAtPrice(token0isWeth, outstandingSupply * capitalInfefficiency / 100 , requiredEthForBuyback); - emit EthScarcity(currentTick, ethBalance, outstandingSupply, vwapX96, capitalInfefficiency, anchorLiquidityShare, vwapTick); + emit EthScarcity(currentTick, ethBalance, outstandingSupply, vwapX96, capitalInfefficiency, anchorLiquidityShare, vwapTick); } else if (vwapX96 == 0) { requiredEthForBuyback = floorEthBalance; vwapTick = currentTick; } else { // recalculate vwap with capital inefficiency vwapX96 = cumulativeVolumeWeightedPriceX96 * capitalInfefficiency / 100 / cumulativeVolume; // in harb/eth - vwapTick = tickAtPriceRatio(token0isWeth, int128(int256 (vwapX96 >> 32))); - - vwapTick = token0isWeth ? vwapTick : -vwapTick; + // ETH/HARB tick + vwapTick = tickAtPriceRatio(int128(int256(vwapX96 >> 32))); + // convert to pool tick + vwapTick = token0isWeth ? -vwapTick : vwapTick; emit EthAbundance(currentTick, ethBalance, outstandingSupply, vwapX96, capitalInfefficiency, anchorLiquidityShare, vwapTick); } // never make floor smaller than anchor @@ -265,7 +269,7 @@ contract LiquidityManager { vwapTick = (vwapTick > currentTick - ANCHOR_SPACING) ? currentTick - ANCHOR_SPACING : vwapTick; } - // normalize tick position for pool + // normalize tick position for pool vwapTick = vwapTick / TICK_SPACING * TICK_SPACING; // calculate liquidity uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(vwapTick); @@ -336,7 +340,7 @@ contract LiquidityManager { ); } _mint(Stage.DISCOVERY, tickLower, tickUpper, liquidity); - harb.burn(harb.balanceOf(address(this))); + harb.burn(harb.balanceOf(address(this))); } } diff --git a/onchain/test/LiquidityManager.t.sol b/onchain/test/LiquidityManager.t.sol index 56a9094..ad0a4ef 100644 --- a/onchain/test/LiquidityManager.t.sol +++ b/onchain/test/LiquidityManager.t.sol @@ -127,6 +127,7 @@ contract LiquidityManagerTest is Test { lm = new LiquidityManager(factoryAddress, address(weth), address(harberg)); lm.setFeeDestination(feeDestination); harberg.setLiquidityManager(address(lm)); + harberg.setLiquidityPool(address(pool)); vm.deal(address(lm), 10 ether); createCSVHeader(); } @@ -137,7 +138,7 @@ contract LiquidityManagerTest is Test { vm.warp(timeBefore + (60 * 60 * 5)); try lm.recenter() { - + // Check liquidity positions after slide (uint256 ethFloor, uint256 ethAnchor, uint256 ethDiscovery, uint256 harbergFloor, uint256 harbergAnchor, uint256 harbergDiscovery) = checkLiquidityPositionsAfter("slide"); assertGt(ethFloor, ethAnchor, "slide - Floor should hold more ETH than Anchor"); @@ -180,7 +181,7 @@ contract LiquidityManagerTest is Test { function getBalancesPool(LiquidityManager.Stage s) internal view returns (int24 currentTick, int24 tickLower, int24 tickUpper, uint256 ethAmount, uint256 harbergAmount) { (,tickLower, tickUpper) = lm.positions(s); (uint128 liquidity, , , ,) = pool.positions(keccak256(abi.encodePacked(address(lm), tickLower, tickUpper))); - + // Fetch the current price from the pool uint160 sqrtPriceX96; (sqrtPriceX96, currentTick, , , , , ) = pool.slot0(); @@ -425,7 +426,7 @@ contract LiquidityManagerTest is Test { // assertEq(ethDiscovery, 0, "Discovery should not have ETH"); // assertEq(harbergFloor, 0, "Floor should have no HARB"); // assertGt(harbergAnchor, 0, "Anchor should have HARB"); - // assertGt(harbergDiscovery, 0, "Discovery should have HARB"); + // assertGt(harbergDiscovery, 0, "Discovery should have HARB"); // // Introduce large buy to push into discovery // buy(3 ether); @@ -619,4 +620,4 @@ contract LiquidityManagerTest is Test { assertGt(traderBalanceBefore, traderBalanceAfter, "trader should not have made profit"); } -} \ No newline at end of file +}