From 694afbe9fe309a69a1530b418a1cd8df4f09d134 Mon Sep 17 00:00:00 2001 From: JulesCrown Date: Tue, 16 Jul 2024 20:47:06 +0200 Subject: [PATCH] make slide and shift one function --- onchain/script/Deploy.sol | 2 +- onchain/src/LiquidityManager.sol | 75 ++++++++--------------------- onchain/test/LiquidityManager.t.sol | 9 ++-- 3 files changed, 25 insertions(+), 61 deletions(-) diff --git a/onchain/script/Deploy.sol b/onchain/script/Deploy.sol index 4e38341..acb4b59 100644 --- a/onchain/script/Deploy.sol +++ b/onchain/script/Deploy.sol @@ -73,7 +73,7 @@ contract SepoliaScript is Script { harb.setLiquidityManager(address(liquidityManager)); (bool sent, ) = address(liquidityManager).call{value: 0.1 ether}(""); require(sent, "Failed to send Ether"); - //TODO: wait few minutes and call slide + //TODO: wait few minutes and call recenter vm.stopBroadcast(); } } diff --git a/onchain/src/LiquidityManager.sol b/onchain/src/LiquidityManager.sol index 13ffccc..f39d144 100644 --- a/onchain/src/LiquidityManager.sol +++ b/onchain/src/LiquidityManager.sol @@ -40,9 +40,6 @@ 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; - - /* ============ Potential Gov Params ============ */ - // 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% @@ -52,11 +49,6 @@ contract LiquidityManager { uint256 internal constant MIN_CAPITAL_INEFFICIENCY = 100; // 120 = 20% uint256 internal constant MAX_CAPITAL_INEFFICIENCY = 200; - - - // the 3 positions this contract is managing - enum Stage { FLOOR, ANCHOR, DISCOVERY } - // the address of the Uniswap V3 factory address private immutable factory; IWETH9 private immutable weth; @@ -65,6 +57,9 @@ contract LiquidityManager { bool private immutable token0isWeth; PoolKey private poolKey; + // the 3 positions this contract is managing + enum Stage { FLOOR, ANCHOR, DISCOVERY } + struct TokenPosition { // the liquidity of the position uint128 liquidity; @@ -86,8 +81,8 @@ contract LiquidityManager { error ZeroAddressInSetter(); error AddressAlreadySet(); - event EthScarcity(int24 currentTick, uint256 ethBalance, uint256 outstandingSupply, uint256 vwap, uint256 CAPITAL_INEFFICIENCY, uint256 ANCHOR_LIQ_SHARE, int24 vwapTick); - event EthAbundance(int24 currentTick, uint256 ethBalance, uint256 outstandingSupply, uint256 vwap, uint256 CAPITAL_INEFFICIENCY, uint256 ANCHOR_LIQ_SHARE, int24 vwapTick); + event EthScarcity(int24 currentTick, uint256 ethBalance, uint256 outstandingSupply, uint256 vwap, uint256 capitalInfefficiency, uint256 anchorLiquidityShare, int24 vwapTick); + event EthAbundance(int24 currentTick, uint256 ethBalance, uint256 outstandingSupply, uint256 vwap, uint256 capitalInfefficiency, uint256 anchorLiquidityShare, int24 vwapTick); /// @dev Function modifier to ensure that the caller is the feeDestination modifier onlyFeeDestination() { @@ -151,7 +146,6 @@ contract LiquidityManager { } receive() external payable { - } /// @notice Calculates the Uniswap V3 tick corresponding to a given price ratio between Harb and ETH. @@ -401,64 +395,31 @@ contract LiquidityManager { secondsAgo[0] = timeInterval; // 5 minutes ago secondsAgo[1] = 0; // current block timestamp - //(int56[] memory tickCumulatives,) = pool.observe(secondsAgo); int56 tickCumulativeDiff; int24 averageTick; try pool.observe(secondsAgo) returns (int56[] memory tickCumulatives, uint160[] memory) { tickCumulativeDiff = tickCumulatives[1] - tickCumulatives[0]; averageTick = int24(tickCumulativeDiff / int56(int32(timeInterval))); - // Process the data } catch { - return true; + // TODO: + return false; } return (currentTick >= averageTick - MAX_TICK_DEVIATION && currentTick <= averageTick + MAX_TICK_DEVIATION); } - /// @notice Adjusts liquidity positions upward in response to an increase in the Harb token's price. - /// @dev This function should be called when significant upward price movement is detected. It recalibrates the liquidity ranges to align with the new market conditions. - function shift() external { - require(positions[Stage.ANCHOR].liquidity > 0, "Not initialized"); + /// @notice Adjusts liquidity positions in response to an increase or decrease in the Harb token's price. + /// @dev This function should be called when significant price movement is detected. It recalibrates the liquidity ranges to align with the new market conditions. + function recenter() external { // Fetch the current tick from the Uniswap V3 pool (, int24 currentTick, , , , , ) = pool.slot0(); // check slippage with oracle require(_isPriceStable(currentTick), "price deviated from oracle"); - // ## check price moved up - { - // Check if current tick is within the specified range - int24 anchorTickLower = positions[Stage.ANCHOR].tickLower; - int24 anchorTickUpper = positions[Stage.ANCHOR].tickUpper; - - int24 centerTick = token0isWeth ? anchorTickLower + ANCHOR_SPACING : anchorTickUpper - ANCHOR_SPACING; - uint256 minAmplitude = uint256(uint24((anchorTickUpper - anchorTickLower) * 3 / 20)); - - // Determine the correct comparison direction based on token0isWeth - bool isUp = token0isWeth ? currentTick < centerTick : currentTick > centerTick; - bool isEnough = SignedMath.abs(currentTick - centerTick) > minAmplitude; - - // Check Conditions - require(isEnough, "amplitude not reached, come back later!"); - require(isUp, "call slide(), not shift()"); - } - - // ## scrape positions - _scrape(); - harb.setPreviousTotalSupply(harb.totalSupply()); - _set(currentTick); - } - - /// @notice Adjusts liquidity positions downward in response to a decrease in the Harb token's price. - /// @dev This function should be called when significant downward price movement is detected. It recalibrates the liquidity ranges to align with the new market conditions. - function slide() external { - // Fetch the current tick from the Uniswap V3 pool - (, int24 currentTick, , , , , ) = pool.slot0(); - // check slippage with oracle - require(_isPriceStable(currentTick), "price deviated from oracle"); - - // ## check price moved down + bool isUp = false; + // check how price moved if (positions[Stage.ANCHOR].liquidity > 0) { - // Check if current tick is within the specified range + // get the anchor position int24 anchorTickLower = positions[Stage.ANCHOR].tickLower; int24 anchorTickUpper = positions[Stage.ANCHOR].tickUpper; @@ -467,15 +428,19 @@ contract LiquidityManager { uint256 minAmplitude = uint256(uint24((anchorTickUpper - anchorTickLower) * 3 / 20)); // Determine the correct comparison direction based on token0isWeth - bool isDown = token0isWeth ? currentTick > centerTick : currentTick < centerTick; + isUp = token0isWeth ? currentTick < centerTick : currentTick > centerTick; bool isEnough = SignedMath.abs(currentTick - centerTick) > minAmplitude; // Check Conditions - require(isEnough, "amplitude not reached, diamond hands!"); - require(isDown, "call shift(), not slide()"); + require(isEnough, "amplitude not reached."); } + // take out all old positions _scrape(); + if (isUp) { + harb.setPreviousTotalSupply(harb.totalSupply()); + } + // set new positions _set(currentTick); } diff --git a/onchain/test/LiquidityManager.t.sol b/onchain/test/LiquidityManager.t.sol index ac954d2..7489b5b 100644 --- a/onchain/test/LiquidityManager.t.sol +++ b/onchain/test/LiquidityManager.t.sol @@ -136,7 +136,7 @@ contract LiquidityManagerTest is Test { uint256 timeBefore = block.timestamp; vm.warp(timeBefore + (60 * 60 * 5)); - try lm.slide() { + try lm.recenter() { // Check liquidity positions after slide (uint256 ethFloor, uint256 ethAnchor, uint256 ethDiscovery, uint256 harbFloor, uint256 harbAnchor, uint256 harbDiscovery) = checkLiquidityPositionsAfter("slide"); @@ -145,7 +145,7 @@ contract LiquidityManagerTest is Test { assertEq(harbFloor, 0, "slide - Floor should have no HARB"); assertEq(ethDiscovery, 0, "slide - Discovery should have no ETH"); } catch Error(string memory reason) { - if (keccak256(abi.encodePacked(reason)) == keccak256(abi.encodePacked("amplitude not reached, diamond hands!"))) { + if (keccak256(abi.encodePacked(reason)) == keccak256(abi.encodePacked("amplitude not reached."))) { console.log("slide failed on amplitude"); } else { if (!last) { @@ -160,8 +160,7 @@ contract LiquidityManagerTest is Test { uint256 timeBefore = block.timestamp; vm.warp(timeBefore + (60 * 60 * 5)); - //lm.shift(); - try lm.shift() { + try lm.recenter() { // Check liquidity positions after shift (uint256 ethFloor, uint256 ethAnchor, uint256 ethDiscovery, uint256 harbFloor, uint256 harbAnchor, uint256 harbDiscovery) = checkLiquidityPositionsAfter("shift"); assertGt(ethFloor, ethAnchor, "shift - Floor should hold more ETH than Anchor"); @@ -169,7 +168,7 @@ contract LiquidityManagerTest is Test { assertEq(harbFloor, 0, "shift - Floor should have no HARB"); assertEq(ethDiscovery, 0, "shift - Discovery should have no ETH"); } catch Error(string memory reason) { - if (keccak256(abi.encodePacked(reason)) == keccak256(abi.encodePacked("amplitude not reached, come back later!"))) { + if (keccak256(abi.encodePacked(reason)) == keccak256(abi.encodePacked("amplitude not reached."))) { console.log("shift failed on amplitude"); } else { revert(reason); // Rethrow the error if it's not the expected message