From 8f7b426daa47973b72ec6eb64fd2ab80b1a3cf72 Mon Sep 17 00:00:00 2001 From: JulesCrown Date: Sun, 28 Apr 2024 07:00:53 +0200 Subject: [PATCH] wip shift --- onchain/src/BaseLineLP.sol | 50 +++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/onchain/src/BaseLineLP.sol b/onchain/src/BaseLineLP.sol index bd35c6d..3bfb0c5 100644 --- a/onchain/src/BaseLineLP.sol +++ b/onchain/src/BaseLineLP.sol @@ -9,6 +9,7 @@ import "@aperture/uni-v3-lib/LiquidityAmounts.sol"; import "@aperture/uni-v3-lib/PoolAddress.sol"; import "@aperture/uni-v3-lib/CallbackValidation.sol"; import "@openzeppelin/token/ERC20/IERC20.sol"; +import "@openzeppelin/utils/math/SignedMath.sol"; import {ABDKMath64x64} from "@abdk/ABDKMath64x64.sol"; import "./interfaces/IWETH9.sol"; import {Harb} from "./Harb.sol"; @@ -89,7 +90,10 @@ contract BaseLineLP { // take care of harb harb.mint(token0isWeth ? amount1Owed : amount0Owed); // pack ETH - weth.deposit{value: token0isWeth ? amount0Owed : amount1Owed}(); + uint256 ethOwed = token0isWeth ? amount0Owed : amount1Owed; + if (weth.balanceOf(address(this)) < ethOwed) { + weth.deposit{value: address(this).balance}(); + } // do transfers if (amount0Owed > 0) IERC20(poolKey.token0).transfer(msg.sender, amount0Owed); if (amount1Owed > 0) IERC20(poolKey.token1).transfer(msg.sender, amount1Owed); @@ -128,28 +132,30 @@ contract BaseLineLP { return (lastDay, mintedToday); } + function ethIn(Stage s) public view returns (uint256 _ethInPosition) { uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(positions[s].tickLower); uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(positions[s].tickUpper); if (token0isWeth) { _ethInPosition = LiquidityAmounts.getAmount0ForLiquidity( - sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity + sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2 ); } else { _ethInPosition = LiquidityAmounts.getAmount1ForLiquidity( - sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity + sqrtRatioAX96, sqrtRatioBX96, positions[s].liquidity / 2 ); } } uint160 internal constant MIN_SQRT_RATIO = 4295128739; - function tickAtPrice(uint256 tokenAmount, uint256 ethAmount) internal view returns (int24 tick_) { + function tickAtPrice(uint256 tokenAmount, uint256 ethAmount) internal returns (int24 tick_) { require(ethAmount > 0, "ETH amount cannot be zero"); uint160 sqrtPriceX96; if (tokenAmount == 0) { sqrtPriceX96 = MIN_SQRT_RATIO; } else { + emit DEBUG(tokenAmount,ethAmount,0,0,token0isWeth); // 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. int128 priceRatio = ABDKMath64x64.div( @@ -160,6 +166,7 @@ contract BaseLineLP { sqrtPriceX96 = uint160( int160(ABDKMath64x64.sqrt(priceRatio) << 32) ); + emit DEBUG(uint256(int256(priceRatio >> 64)),uint256(sqrtPriceX96 >> 96),0,0,token0isWeth); } // Proceed as before. tick_ = TickMath.getTickAtSqrtRatio(sqrtPriceX96); @@ -239,13 +246,13 @@ contract BaseLineLP { int24 startTick = token0isWeth ? currentTick + ANCHOR_SPACING : currentTick - ANCHOR_SPACING; // all remaining eth will be put into this position - uint256 ethInFloor = address(this).balance; + uint256 ethInFloor = address(this).balance + weth.balanceOf(address(this)); int24 floorTick; // calculate price at which all HARB can be bought back uint256 _outstanding = outstanding(); if (_outstanding > 0) { floorTick = tickAtPrice(_outstanding, ethInFloor); - emit DEBUG(ethInFloor,0,floorTick,startTick,token0isWeth); + emit DEBUG(ethInFloor,_outstanding,floorTick,startTick,token0isWeth); // put a position symetrically around the price, startTick being edge on one side floorTick = token0isWeth ? startTick + (floorTick - startTick) : floorTick - (startTick - floorTick); @@ -342,11 +349,11 @@ contract BaseLineLP { int24 anchorTickUpper = positions[Stage.ANCHOR].tickUpper; // center tick can be calculated positive and negative numbers the same int24 centerTick = anchorTickLower + ((anchorTickUpper - anchorTickLower) / 2); - int24 amplitudeTick = anchorTickLower + (anchorTickUpper - anchorTickLower) * 3 / 20; + 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 = token0isWeth ? currentTick < amplitudeTick : currentTick > amplitudeTick; + bool isEnough = SignedMath.abs(currentTick - centerTick) > minAmplitude; // Check Conditions require(isUp, "call slide(), not shift()"); @@ -358,21 +365,33 @@ contract BaseLineLP { for (uint256 i=uint256(Stage.FLOOR); i <= uint256(Stage.DISCOVERY); i++) { TokenPosition storage position = positions[Stage(i)]; (uint256 amount0, uint256 amount1) = pool.burn(position.tickLower, position.tickUpper, position.liquidity); + // the actual amounts collected are returned + (amount0, amount1) = pool.collect( + address(this), + position.tickLower, + position.tickUpper, + uint128(amount0), + uint128(amount1) + ); if (i == uint256(Stage.ANCHOR)) { ethInAnchor = token0isWeth ? amount0 : amount1; } } // TODO: handle fees - + // ## set new positions // reduce Anchor by 10% of new ETH. It will be moved into Floor uint256 initialEthInAnchor = ethIn(Stage.ANCHOR); ethInAnchor -= (ethInAnchor - initialEthInAnchor) * 10 / LIQUIDITY_RATIO_DIVISOR; + // cap anchor size at 10 % of total ETH - uint256 ethBalance = address(this).balance; + uint256 ethBalance = address(this).balance + weth.balanceOf(address(this)); + // event DEBUG(uint256 indexed eth, uint256 indexed outstanding, int24 indexed floorTick, int24 startTick, bool ethIs0); + emit DEBUG(ethInAnchor,weth.balanceOf(address(this)),0,0, token0isWeth); ethInAnchor = (ethInAnchor > ethBalance / 10) ? ethBalance / 10 : ethInAnchor; + currentTick = currentTick / TICK_SPACING * TICK_SPACING; _set(sqrtPriceX96, currentTick, ethInAnchor); } @@ -403,12 +422,19 @@ contract BaseLineLP { for (uint256 i=uint256(Stage.FLOOR); i <= uint256(Stage.DISCOVERY); i++) { TokenPosition storage position = positions[Stage(i)]; if (position.liquidity > 0) { - pool.burn(position.tickLower, position.tickUpper, position.liquidity); + (uint256 amount0, uint256 amount1) = pool.burn(position.tickLower, position.tickUpper, position.liquidity); + (amount0, amount1) = pool.collect( + address(this), + position.tickLower, + position.tickUpper, + uint128(amount0), + uint128(amount1) + ); // TODO: handle fees } } - uint256 ethBalance = address(this).balance; + uint256 ethBalance = address(this).balance + weth.balanceOf(address(this)); if (ethBalance == 0) { // TODO: set only discovery return;