From 0edf05a32d936cd42d724bb6ee740e8d162b4e21 Mon Sep 17 00:00:00 2001 From: JulesCrown Date: Sat, 27 Apr 2024 07:04:33 +0200 Subject: [PATCH] testing shift --- onchain/src/BaseLineLP.sol | 90 ++++++++++++++++++----------------- onchain/test/BaseLineLP.t.sol | 66 +++++++++++++++++++++++-- 2 files changed, 108 insertions(+), 48 deletions(-) diff --git a/onchain/src/BaseLineLP.sol b/onchain/src/BaseLineLP.sol index 0d47fcb..bd35c6d 100644 --- a/onchain/src/BaseLineLP.sol +++ b/onchain/src/BaseLineLP.sol @@ -22,6 +22,7 @@ import {Harb} from "./Harb.sol"; contract BaseLineLP { int24 constant TICK_SPACING = 200; int24 constant ANCHOR_SPACING = 5 * TICK_SPACING; + int24 constant DISCOVERY_SPACING = 11000; // default fee of 1% uint24 constant FEE = uint24(10_000); // uint256 constant FLOOR = 0; @@ -166,7 +167,7 @@ contract BaseLineLP { tick_ = token0isWeth ? tick_ : -tick_; } - function _mint(int24 tickLower, int24 tickUpper, uint128 liquidity) internal { + function _mint(Stage stage, int24 tickLower, int24 tickUpper, uint128 liquidity) internal { // create position pool.mint( address(this), @@ -185,7 +186,7 @@ contract BaseLineLP { (, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128,,) = pool.positions(positionKey); // put into storage - positions[Stage.ANCHOR] = TokenPosition({ + positions[stage] = TokenPosition({ liquidity: liquidity, tickLower: tickLower, tickUpper: tickUpper, @@ -230,7 +231,7 @@ contract BaseLineLP { } // TODO: calculate liquidity correctly // or make sure that we don't have to pay more than we have - _mint(tickLower, tickUpper, anchorLiquidity * 2); + _mint(Stage.ANCHOR, tickLower, tickUpper, anchorLiquidity * 2); } // ### set Floor position @@ -263,13 +264,13 @@ contract BaseLineLP { ); emit DEBUG(ethInFloor,uint256(liquidity),floorTick,startTick,token0isWeth); // mint - _mint(startTick, floorTick, liquidity); + _mint(Stage.FLOOR, startTick, floorTick, liquidity); } // ## set Discovery position { - int24 tickLower = token0isWeth ? currentTick + ANCHOR_SPACING : currentTick - 11400; - int24 tickUpper = token0isWeth ? currentTick + 11400 : currentTick - ANCHOR_SPACING; + int24 tickLower = token0isWeth ? currentTick - DISCOVERY_SPACING - ANCHOR_SPACING : currentTick + ANCHOR_SPACING; + int24 tickUpper = token0isWeth ? currentTick - ANCHOR_SPACING : currentTick + DISCOVERY_SPACING + ANCHOR_SPACING; uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower); uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper); // discovery with 1.5 times as much liquidity per tick as anchor @@ -279,48 +280,51 @@ contract BaseLineLP { uint128 liquidity = anchorLiquidity * 55 / 2; uint256 harbInDiscovery; if (token0isWeth) { - harbInDiscovery = LiquidityAmounts.getAmount1ForLiquidity( - sqrtRatioAX96, - sqrtRatioBX96, - liquidity - ); - } else { harbInDiscovery = LiquidityAmounts.getAmount0ForLiquidity( sqrtRatioAX96, sqrtRatioBX96, liquidity ); - } - // manage minting limits of harb here - if (harbInDiscovery <= harb.balanceOf(address(this))) { - _mint(tickLower, tickUpper, liquidity); - harb.burn(harb.balanceOf(address(this))); } else { - uint256 amount = availableMint(harbInDiscovery - harb.balanceOf(address(this))); - harb.mint(amount); - mintedToday += amount; - amount = harb.balanceOf(address(this)); - if(amount < harbInDiscovery) { - // calculate new ticks so that discovery liquidity is still - // deeper than anchor, but less wide - int24 tickWidth = int24(int256(11000 * amount / harbInDiscovery)) + ANCHOR_SPACING; - - tickWidth = tickWidth / TICK_SPACING * TICK_SPACING; - tickWidth = (tickWidth <= ANCHOR_SPACING) ? tickWidth + TICK_SPACING : tickWidth; - tickLower = token0isWeth ? currentTick - tickWidth : currentTick + ANCHOR_SPACING; - tickUpper = token0isWeth ? currentTick - ANCHOR_SPACING : currentTick + tickWidth; - sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower); - sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper); - liquidity = LiquidityAmounts.getLiquidityForAmounts( - sqrtPriceX96, - sqrtRatioAX96, - sqrtRatioBX96, - token0isWeth ? 0 : amount, - token0isWeth ? amount : 0 - ); - } - _mint(tickLower, tickUpper, liquidity); + harbInDiscovery = LiquidityAmounts.getAmount1ForLiquidity( + sqrtRatioAX96, + sqrtRatioBX96, + liquidity + ); } + harb.mint(harbInDiscovery); + _mint(Stage.DISCOVERY, tickLower, tickUpper, liquidity); + harb.burn(harb.balanceOf(address(this))); + // // manage minting limits of harb here + // if (harbInDiscovery <= harb.balanceOf(address(this))) { + // _mint(tickLower, tickUpper, liquidity); + // harb.burn(harb.balanceOf(address(this))); + // } else { + // uint256 amount = availableMint(harbInDiscovery - harb.balanceOf(address(this))); + // harb.mint(amount); + // mintedToday += amount; + // amount = harb.balanceOf(address(this)); + // if(amount < harbInDiscovery) { + // // calculate new ticks so that discovery liquidity is still + // // deeper than anchor, but less wide + // int24 tickWidth = int24(int256(11000 * amount / harbInDiscovery)) + ANCHOR_SPACING; + + // tickWidth = tickWidth / TICK_SPACING * TICK_SPACING; + // tickWidth = (tickWidth <= ANCHOR_SPACING) ? tickWidth + TICK_SPACING : tickWidth; + // tickLower = token0isWeth ? currentTick - tickWidth : currentTick + ANCHOR_SPACING; + // tickUpper = token0isWeth ? currentTick - ANCHOR_SPACING : currentTick + tickWidth; + // sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower); + // sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper); + // liquidity = LiquidityAmounts.getLiquidityForAmounts( + // sqrtPriceX96, + // sqrtRatioAX96, + // sqrtRatioBX96, + // token0isWeth ? 0 : amount, + // token0isWeth ? amount : 0 + // ); + // } + // _mint(tickLower, tickUpper, liquidity); + // } } } @@ -341,8 +345,8 @@ contract BaseLineLP { int24 amplitudeTick = anchorTickLower + (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 isUp = token0isWeth ? currentTick < centerTick : currentTick > centerTick; + bool isEnough = token0isWeth ? currentTick < amplitudeTick : currentTick > amplitudeTick; // Check Conditions require(isUp, "call slide(), not shift()"); diff --git a/onchain/test/BaseLineLP.t.sol b/onchain/test/BaseLineLP.t.sol index ab0b968..0f86346 100644 --- a/onchain/test/BaseLineLP.t.sol +++ b/onchain/test/BaseLineLP.t.sol @@ -7,6 +7,7 @@ import {TwabController} from "pt-v5-twab-controller/TwabController.sol"; import {PoolAddress, PoolKey} from "@aperture/uni-v3-lib/PoolAddress.sol"; import "@uniswap-v3-core/interfaces/IUniswapV3Factory.sol"; import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol"; +import "@aperture/uni-v3-lib/TickMath.sol"; import "../src/interfaces/IWETH9.sol"; import {WETH} from "solmate/tokens/WETH.sol"; import "../src/Harb.sol"; @@ -24,6 +25,8 @@ contract BaseLineLPTest is Test { IUniswapV3Factory factory; Stake stake; BaseLineLP liquidityManager; + IUniswapV3Pool pool; + bool token0isWeth; function sqrt(uint256 y) internal pure returns (uint256 z) { if (y > 3) { @@ -39,9 +42,9 @@ contract BaseLineLPTest is Test { // z is now the integer square root of y, or the closest integer to the square root of y. } - function initializePoolFor1Cent(bool isEthToken0, address pool) public { + function initializePoolFor1Cent(address pool) public { uint256 price; - if (isEthToken0) { + if (token0isWeth) { // ETH as token0, so we are setting the price of 1 ETH in terms of token1 (USD cent) price = 3000 * 10**20; // 1 ETH = 3700 USD, scaled by 10^18 for precision } else { @@ -73,9 +76,10 @@ contract BaseLineLPTest is Test { TwabController tc = new TwabController(60 * 60 * 24, uint32(block.timestamp)); harb = new Harb("HARB", "HARB", factoryAddress, address(weth), tc); - address pool = factory.createPool(address(weth), address(harb), FEE); + pool = IUniswapV3Pool(factory.createPool(address(weth), address(harb), FEE)); - initializePoolFor1Cent(address(weth) < address(harb), pool); + token0isWeth = address(weth) < address(harb); + initializePoolFor1Cent(address(pool)); stake = new Stake(address(harb)); harb.setStakingPool(address(stake)); @@ -87,14 +91,66 @@ contract BaseLineLPTest is Test { vm.assume(account != address(0)); vm.assume(account != address(1)); // TWAB sponsorship address vm.assume(account != address(2)); // tax pool address - vm.deal(account, 10 ether); + vm.deal(account, 15 ether); vm.prank(account); (bool sent, ) = address(liquidityManager).call{value: 10 ether}(""); require(sent, "Failed to send Ether"); + // Try to shift liquidity manager's state, expect failure due to initial state vm.expectRevert(); liquidityManager.shift(); liquidityManager.slide(); + + + // Approve the pool to transfer WETH on behalf of the account + vm.prank(account); + weth.deposit{value: 5 ether}(); + vm.prank(account); + weth.approve(address(this), 5 ether); + + + // Execute the swap + pool.swap( + account, // Recipient of the output tokens + token0isWeth, + int256(0.5 ether), + token0isWeth ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1, + abi.encode(account, int256(0.5 ether), true) + ); + + liquidityManager.shift(); } + + /*////////////////////////////////////////////////////////////// + CALLBACKS + //////////////////////////////////////////////////////////////*/ + + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata _data + ) + external + { + require(amount0Delta > 0 || amount1Delta > 0); + + (address seller, uint256 harbIn, bool buy) = abi.decode(_data, (address, uint256, bool)); + + (bool isExactInput, uint256 amountToPay) = amount0Delta > 0 + ? (!token0isWeth, uint256(amount0Delta)) + : (token0isWeth, uint256(amount1Delta)); + if (buy) { + weth.transferFrom(seller, msg.sender, amountToPay); + return; + } + require(isExactInput, "reason 1"); + // check input amount + require(amountToPay == harbIn, "reason 2"); + // transfer eth to univ3 pool + + require(harb.transferFrom(seller, msg.sender, amountToPay), "reason 3"); + } + + receive() external payable {} }