make slide and shift one function

This commit is contained in:
JulesCrown 2024-07-16 20:47:06 +02:00
parent ae8c3a1e4f
commit 694afbe9fe
3 changed files with 25 additions and 61 deletions

View file

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

View file

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

View file

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