added harb-lib

This commit is contained in:
JulesCrown 2024-04-03 21:43:12 +02:00
parent ea1b007283
commit 5a8c80e838
15 changed files with 4876 additions and 48 deletions

View file

@ -212,46 +212,7 @@ contract BaseLineLP {
});
}
// call this function when price has moved up 15%
function shift() external {
// Fetch the current tick from the Uniswap V3 pool
(uint160 sqrtPriceX96, int24 currentTick, , , , , ) = pool.slot0();
// TODO: check slippage with 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;
// center tick can be calculated positive and negative numbers the same
int24 centerTick = anchorTickLower + ((anchorTickUpper - anchorTickLower) / 2);
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;
// Check Conditions
require(isUp, "call slide(), not shift()");
require(isEnough, "amplitude not reached, come back later");
}
// ## scrape positions
uint256 ethInAnchor;
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);
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;
function _set(uint160 sqrtPriceX96, int24 currentTick, uint256 ethInNewAnchor) internal {
// ### set Anchor position
uint128 anchorLiquidity;
{
@ -261,11 +222,11 @@ contract BaseLineLP {
uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
if (token0isWeth) {
anchorLiquidity = LiquidityAmounts.getLiquidityForAmount0(
sqrtRatioAX96, sqrtRatioBX96, ethInAnchor
sqrtRatioAX96, sqrtRatioBX96, ethInNewAnchor
);
} else {
anchorLiquidity = LiquidityAmounts.getLiquidityForAmount1(
sqrtRatioAX96, sqrtRatioBX96, ethInAnchor
sqrtRatioAX96, sqrtRatioBX96, ethInNewAnchor
);
}
_mint(tickLower, tickUpper, anchorLiquidity);
@ -322,16 +283,103 @@ contract BaseLineLP {
}
_mint(tickLower, tickUpper, liquidity);
}
}
// call this function when price has moved up 15%
function shift() external {
require(positions[Stage.ANCHOR].liquidity > 0, "Not initialized");
// Fetch the current tick from the Uniswap V3 pool
(uint160 sqrtPriceX96, int24 currentTick, , , , , ) = pool.slot0();
// TODO: check slippage with 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;
// center tick can be calculated positive and negative numbers the same
int24 centerTick = anchorTickLower + ((anchorTickUpper - anchorTickLower) / 2);
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;
// Check Conditions
require(isUp, "call slide(), not shift()");
require(isEnough, "amplitude not reached, come back later!");
}
// ## scrape positions
uint256 ethInAnchor;
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);
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;
ethInAnchor = (ethInAnchor > ethBalance / 10) ? ethBalance / 10 : ethInAnchor;
_set(sqrtPriceX96, currentTick, ethInAnchor);
}
function slide() external {
// check price moved down
// check price moved down enough
// scrape positions
// get outstanding upply and capacity
// set new positions
// burn harb
// Fetch the current tick from the Uniswap V3 pool
(uint160 sqrtPriceX96, int24 currentTick, , , , , ) = pool.slot0();
// TODO: check slippage with oracle
// ## check price moved down
if (positions[Stage.ANCHOR].liquidity > 0) {
// Check if current tick is within the specified range
int24 anchorTickLower = positions[Stage.ANCHOR].tickLower;
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;
// Determine the correct comparison direction based on token0isWeth
bool isDown = token0isWeth ? currentTick < centerTick : currentTick > centerTick;
bool isEnough = token0isWeth ? currentTick < amplitudeTick : currentTick > amplitudeTick;
// Check Conditions
require(isDown, "call shift(), not slide()");
require(isEnough, "amplitude not reached, diamond hands!");
}
// ## scrape positions
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);
// TODO: handle fees
}
}
uint256 ethBalance = address(this).balance;
if (ethBalance == 0) {
// TODO: set only discovery
return;
}
uint256 ethInAnchor = ethIn(Stage.ANCHOR);
uint256 ethInFloor = ethIn(Stage.FLOOR);
// use previous ration of Floor to Anchor
uint256 ethInNewAnchor = ethBalance * ethInAnchor / (ethInAnchor + ethInFloor);
// but cap anchor size at 10 % of total ETH
ethInNewAnchor = (ethInNewAnchor > ethBalance / 10) ? ethBalance / 10 : ethInNewAnchor;
_set(sqrtPriceX96, currentTick, ethInNewAnchor);
}
}

View file

@ -88,6 +88,7 @@ contract Stake is IStake {
if (sharesWanted < minStake) {
revert SharesTooLow(receiver, assets, sharesWanted, minStake);
}
// TODO: check that position size is multiple of minStake
// run through all suggested positions to snatch
for (uint256 i = 0; i < positionsToSnatch.length; i++) {
@ -104,6 +105,8 @@ contract Stake is IStake {
// TODO: what if someone calls payTax and exitPosition in the same transaction?
_payTax(pos, 0);
_exitPosition(positionsToSnatch[i], pos);
// TODO: exit positions partially, if needed
// TODO: avoid greeving where more positions are freed than needed.
}
// try to make a new position in the free space and hope it is big enough