testing shift
This commit is contained in:
parent
047d1967e1
commit
0edf05a32d
2 changed files with 108 additions and 48 deletions
|
|
@ -22,6 +22,7 @@ import {Harb} from "./Harb.sol";
|
||||||
contract BaseLineLP {
|
contract BaseLineLP {
|
||||||
int24 constant TICK_SPACING = 200;
|
int24 constant TICK_SPACING = 200;
|
||||||
int24 constant ANCHOR_SPACING = 5 * TICK_SPACING;
|
int24 constant ANCHOR_SPACING = 5 * TICK_SPACING;
|
||||||
|
int24 constant DISCOVERY_SPACING = 11000;
|
||||||
// default fee of 1%
|
// default fee of 1%
|
||||||
uint24 constant FEE = uint24(10_000);
|
uint24 constant FEE = uint24(10_000);
|
||||||
// uint256 constant FLOOR = 0;
|
// uint256 constant FLOOR = 0;
|
||||||
|
|
@ -166,7 +167,7 @@ contract BaseLineLP {
|
||||||
tick_ = token0isWeth ? tick_ : -tick_;
|
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
|
// create position
|
||||||
pool.mint(
|
pool.mint(
|
||||||
address(this),
|
address(this),
|
||||||
|
|
@ -185,7 +186,7 @@ contract BaseLineLP {
|
||||||
(, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128,,) = pool.positions(positionKey);
|
(, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128,,) = pool.positions(positionKey);
|
||||||
|
|
||||||
// put into storage
|
// put into storage
|
||||||
positions[Stage.ANCHOR] = TokenPosition({
|
positions[stage] = TokenPosition({
|
||||||
liquidity: liquidity,
|
liquidity: liquidity,
|
||||||
tickLower: tickLower,
|
tickLower: tickLower,
|
||||||
tickUpper: tickUpper,
|
tickUpper: tickUpper,
|
||||||
|
|
@ -230,7 +231,7 @@ contract BaseLineLP {
|
||||||
}
|
}
|
||||||
// TODO: calculate liquidity correctly
|
// TODO: calculate liquidity correctly
|
||||||
// or make sure that we don't have to pay more than we have
|
// 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
|
// ### set Floor position
|
||||||
|
|
@ -263,13 +264,13 @@ contract BaseLineLP {
|
||||||
);
|
);
|
||||||
emit DEBUG(ethInFloor,uint256(liquidity),floorTick,startTick,token0isWeth);
|
emit DEBUG(ethInFloor,uint256(liquidity),floorTick,startTick,token0isWeth);
|
||||||
// mint
|
// mint
|
||||||
_mint(startTick, floorTick, liquidity);
|
_mint(Stage.FLOOR, startTick, floorTick, liquidity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ## set Discovery position
|
// ## set Discovery position
|
||||||
{
|
{
|
||||||
int24 tickLower = token0isWeth ? currentTick + ANCHOR_SPACING : currentTick - 11400;
|
int24 tickLower = token0isWeth ? currentTick - DISCOVERY_SPACING - ANCHOR_SPACING : currentTick + ANCHOR_SPACING;
|
||||||
int24 tickUpper = token0isWeth ? currentTick + 11400 : currentTick - ANCHOR_SPACING;
|
int24 tickUpper = token0isWeth ? currentTick - ANCHOR_SPACING : currentTick + DISCOVERY_SPACING + ANCHOR_SPACING;
|
||||||
uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
|
uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
|
||||||
uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
|
uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
|
||||||
// discovery with 1.5 times as much liquidity per tick as anchor
|
// discovery with 1.5 times as much liquidity per tick as anchor
|
||||||
|
|
@ -279,48 +280,51 @@ contract BaseLineLP {
|
||||||
uint128 liquidity = anchorLiquidity * 55 / 2;
|
uint128 liquidity = anchorLiquidity * 55 / 2;
|
||||||
uint256 harbInDiscovery;
|
uint256 harbInDiscovery;
|
||||||
if (token0isWeth) {
|
if (token0isWeth) {
|
||||||
harbInDiscovery = LiquidityAmounts.getAmount1ForLiquidity(
|
|
||||||
sqrtRatioAX96,
|
|
||||||
sqrtRatioBX96,
|
|
||||||
liquidity
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
harbInDiscovery = LiquidityAmounts.getAmount0ForLiquidity(
|
harbInDiscovery = LiquidityAmounts.getAmount0ForLiquidity(
|
||||||
sqrtRatioAX96,
|
sqrtRatioAX96,
|
||||||
sqrtRatioBX96,
|
sqrtRatioBX96,
|
||||||
liquidity
|
liquidity
|
||||||
);
|
);
|
||||||
}
|
|
||||||
// manage minting limits of harb here
|
|
||||||
if (harbInDiscovery <= harb.balanceOf(address(this))) {
|
|
||||||
_mint(tickLower, tickUpper, liquidity);
|
|
||||||
harb.burn(harb.balanceOf(address(this)));
|
|
||||||
} else {
|
} else {
|
||||||
uint256 amount = availableMint(harbInDiscovery - harb.balanceOf(address(this)));
|
harbInDiscovery = LiquidityAmounts.getAmount1ForLiquidity(
|
||||||
harb.mint(amount);
|
sqrtRatioAX96,
|
||||||
mintedToday += amount;
|
sqrtRatioBX96,
|
||||||
amount = harb.balanceOf(address(this));
|
liquidity
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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;
|
int24 amplitudeTick = anchorTickLower + (anchorTickUpper - anchorTickLower) * 3 / 20;
|
||||||
|
|
||||||
// Determine the correct comparison direction based on token0isWeth
|
// Determine the correct comparison direction based on token0isWeth
|
||||||
bool isUp = token0isWeth ? currentTick > centerTick : currentTick < centerTick;
|
bool isUp = token0isWeth ? currentTick < centerTick : currentTick > centerTick;
|
||||||
bool isEnough = token0isWeth ? currentTick > amplitudeTick : currentTick < amplitudeTick;
|
bool isEnough = token0isWeth ? currentTick < amplitudeTick : currentTick > amplitudeTick;
|
||||||
|
|
||||||
// Check Conditions
|
// Check Conditions
|
||||||
require(isUp, "call slide(), not shift()");
|
require(isUp, "call slide(), not shift()");
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {TwabController} from "pt-v5-twab-controller/TwabController.sol";
|
||||||
import {PoolAddress, PoolKey} from "@aperture/uni-v3-lib/PoolAddress.sol";
|
import {PoolAddress, PoolKey} from "@aperture/uni-v3-lib/PoolAddress.sol";
|
||||||
import "@uniswap-v3-core/interfaces/IUniswapV3Factory.sol";
|
import "@uniswap-v3-core/interfaces/IUniswapV3Factory.sol";
|
||||||
import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol";
|
import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol";
|
||||||
|
import "@aperture/uni-v3-lib/TickMath.sol";
|
||||||
import "../src/interfaces/IWETH9.sol";
|
import "../src/interfaces/IWETH9.sol";
|
||||||
import {WETH} from "solmate/tokens/WETH.sol";
|
import {WETH} from "solmate/tokens/WETH.sol";
|
||||||
import "../src/Harb.sol";
|
import "../src/Harb.sol";
|
||||||
|
|
@ -24,6 +25,8 @@ contract BaseLineLPTest is Test {
|
||||||
IUniswapV3Factory factory;
|
IUniswapV3Factory factory;
|
||||||
Stake stake;
|
Stake stake;
|
||||||
BaseLineLP liquidityManager;
|
BaseLineLP liquidityManager;
|
||||||
|
IUniswapV3Pool pool;
|
||||||
|
bool token0isWeth;
|
||||||
|
|
||||||
function sqrt(uint256 y) internal pure returns (uint256 z) {
|
function sqrt(uint256 y) internal pure returns (uint256 z) {
|
||||||
if (y > 3) {
|
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.
|
// 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;
|
uint256 price;
|
||||||
if (isEthToken0) {
|
if (token0isWeth) {
|
||||||
// ETH as token0, so we are setting the price of 1 ETH in terms of token1 (USD cent)
|
// 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
|
price = 3000 * 10**20; // 1 ETH = 3700 USD, scaled by 10^18 for precision
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -73,9 +76,10 @@ contract BaseLineLPTest is Test {
|
||||||
TwabController tc = new TwabController(60 * 60 * 24, uint32(block.timestamp));
|
TwabController tc = new TwabController(60 * 60 * 24, uint32(block.timestamp));
|
||||||
harb = new Harb("HARB", "HARB", factoryAddress, address(weth), tc);
|
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));
|
stake = new Stake(address(harb));
|
||||||
harb.setStakingPool(address(stake));
|
harb.setStakingPool(address(stake));
|
||||||
|
|
@ -87,14 +91,66 @@ contract BaseLineLPTest is Test {
|
||||||
vm.assume(account != address(0));
|
vm.assume(account != address(0));
|
||||||
vm.assume(account != address(1)); // TWAB sponsorship address
|
vm.assume(account != address(1)); // TWAB sponsorship address
|
||||||
vm.assume(account != address(2)); // tax pool address
|
vm.assume(account != address(2)); // tax pool address
|
||||||
vm.deal(account, 10 ether);
|
vm.deal(account, 15 ether);
|
||||||
vm.prank(account);
|
vm.prank(account);
|
||||||
(bool sent, ) = address(liquidityManager).call{value: 10 ether}("");
|
(bool sent, ) = address(liquidityManager).call{value: 10 ether}("");
|
||||||
require(sent, "Failed to send Ether");
|
require(sent, "Failed to send Ether");
|
||||||
|
|
||||||
|
// Try to shift liquidity manager's state, expect failure due to initial state
|
||||||
vm.expectRevert();
|
vm.expectRevert();
|
||||||
liquidityManager.shift();
|
liquidityManager.shift();
|
||||||
|
|
||||||
liquidityManager.slide();
|
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 {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue