Skip to content

Commit

Permalink
concentrated liquidity: further swap/lp work (#3101)
Browse files Browse the repository at this point in the history
* further swap generalization

* add step and swap state

* Update test.yml

* Update test.yml

* Further generalize swaps and lp (#3111)

* Change sqrt to caller

* Remove margin of error from mint

* Change Pool to have dec curr price

* Remove swap structs

* Adams comments

* address code review comments

* final additions

* address code review comments

* code review

Co-authored-by: Matt, Park <[email protected]>
  • Loading branch information
czarcas7ic and mattverse authored Oct 24, 2022
1 parent 5a8b313 commit 0e7e02a
Show file tree
Hide file tree
Showing 11 changed files with 316 additions and 198 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
push:
branches:
- "main"
- "concentrated-liquidity-main"
- "v[0-9]**"
workflow_dispatch:

Expand Down Expand Up @@ -124,3 +125,4 @@ jobs:
-
name: Test e2e and Upgrade
run: make test-e2e-ci

30 changes: 15 additions & 15 deletions proto/osmosis/concentrated-liquidity/concentratedPool.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,47 @@ import "gogoproto/gogo.proto";
option go_package = "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity";

message Pool {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;
option (cosmos_proto.implements_interface) = "PoolI";

string address = 1 [(gogoproto.moretags) = "yaml:\"address\""];
uint64 id = 2;
string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ];
uint64 id = 2;

// Amount of total liquidity
string liquidity = 3 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.nullable) = false
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.nullable) = false
];

string token0 = 4;
string token1 = 5;

string current_sqrt_price = 6 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"spot_price\"",
(gogoproto.nullable) = false
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.moretags) = "yaml:\"spot_price\"",
(gogoproto.nullable) = false
];
string current_tick = 7 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"current_tick\"",
(gogoproto.nullable) = false
(gogoproto.moretags) = "yaml:\"current_tick\"",
(gogoproto.nullable) = false
];
}

message TickInfo {
string liquidity = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.nullable) = false
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.nullable) = false
];
}

message Position {
string liquidity = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.nullable) = false
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.nullable) = false
];
}
60 changes: 30 additions & 30 deletions x/concentrated-liquidity/concentratedPool.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions x/concentrated-liquidity/export_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package concentrated_liquidity

import (
cltypes "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
)

// OrderInitialPoolDenoms sets the pool denoms of a cl pool
func (p *Pool) OrderInitialPoolDenoms(denom0, denom1 string) error {
return p.orderInitialPoolDenoms(denom0, denom1)
func OrderInitialPoolDenoms(denom0, denom1 string) (string, string, error) {
return cltypes.OrderInitialPoolDenoms(denom0, denom1)
}
24 changes: 10 additions & 14 deletions x/concentrated-liquidity/lp.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
)

func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, liquidityIn sdk.Int, lowerTick, upperTick int64) (amtDenom0, amtDenom1 sdk.Int, err error) {
func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, liquidityIn sdk.Dec, lowerTick, upperTick int64) (amtDenom0, amtDenom1 sdk.Int, err error) {
// ensure types.MinTick <= lowerTick < types.MaxTick
// TODO (bez): Add unit tests.
if lowerTick < types.MinTick || lowerTick >= types.MaxTick {
Expand All @@ -24,26 +24,22 @@ func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, liqui
if liquidityIn.IsZero() {
return sdk.Int{}, sdk.Int{}, fmt.Errorf("token in amount is zero")
}

// TODO: we need to check if TickInfo is initialized on a specific tick before updating, otherwise get wont work
// k.setTickInfo(ctx, poolId, lowerTick, TickInfo{})
// k.UpdateTickWithNewLiquidity(ctx, poolId, lowerTick, liquidityIn)
// k.setTickInfo(ctx, poolId, upperTick, TickInfo{})
// k.UpdateTickWithNewLiquidity(ctx, poolId, upperTick, liquidityIn)

// k.updatePositionWithLiquidity(ctx, poolId, owner.String(), lowerTick, upperTick, liquidityIn)
// k.setPosition(ctx, poolId, owner, lowerTick, upperTick, Position{})
// k.updatePositionWithLiquidity(ctx, poolId, owner, lowerTick, upperTick, liquidityIn)

pool := k.getPoolbyId(ctx, poolId)

currentSqrtPrice := pool.CurrentSqrtPrice
sqrtRatioUpperTick, err := k.getSqrtRatioAtTick(upperTick)
if err != nil {
return sdk.Int{}, sdk.Int{}, err
}
sqrtRatioLowerTick, err := k.getSqrtRatioAtTick(lowerTick)
if err != nil {
return sdk.Int{}, sdk.Int{}, err
}
sqrtRatioUpperTick, _ := k.tickToSqrtPrice(sdk.NewInt(upperTick))
sqrtRatioLowerTick, _ := k.tickToSqrtPrice(sdk.NewInt(lowerTick))

amtDenom0 = calcAmount0Delta(currentSqrtPrice.ToDec(), sqrtRatioUpperTick, liquidityIn.ToDec()).RoundInt()
amtDenom1 = calcAmount1Delta(currentSqrtPrice.ToDec(), sqrtRatioLowerTick, liquidityIn.ToDec()).RoundInt()
amtDenom0 = calcAmount0Delta(liquidityIn, currentSqrtPrice, sqrtRatioUpperTick).RoundInt()
amtDenom1 = calcAmount1Delta(liquidityIn, currentSqrtPrice, sqrtRatioLowerTick).RoundInt()

return amtDenom0, amtDenom1, nil
}
Expand Down
22 changes: 13 additions & 9 deletions x/concentrated-liquidity/lp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,29 @@ func (s *KeeperTestSuite) TestMint() {
// current tick: 85176
// lower tick: 84222
// upper tick: 86129
// liquidity(token in):1517882343751509868544
// current sqrt price: 5602277097478614198912276234240
// denom0: uosmo
// liquidity(token in):1517882323
// current sqrt price: 70710678
// denom0: eth
// denom1: usdc
poolId := uint64(1)
currentTick := sdk.NewInt(85176)
lowerTick := int64(84222)
upperTick := int64(86129)
liquidity, ok := sdk.NewIntFromString("1517882343751509868544")
s.Require().True(ok)
currentSqrtP, ok := sdk.NewIntFromString("5602277097478614198912276234240")
s.Require().True(ok)
denom0 := "uosmo"
liquidity, err := sdk.NewDecFromStr("1517.882323")
s.Require().NoError(err)
// currentSqrtP, ok := sdk.NewIntFromString("70710678")
currentSqrtP, err := sdk.NewDecFromStr("70.710678")
s.Require().NoError(err)
denom0 := "eth"
denom1 := "usdc"

s.SetupTest()

s.App.ConcentratedLiquidityKeeper.CreateNewConcentratedLiquidityPool(s.Ctx, poolId, denom0, denom1, currentSqrtP, currentTick)

_, _, err := s.App.ConcentratedLiquidityKeeper.Mint(s.Ctx, poolId, s.TestAccs[0], liquidity, lowerTick, upperTick)
asset0, asset1, err := s.App.ConcentratedLiquidityKeeper.Mint(s.Ctx, poolId, s.TestAccs[0], liquidity, lowerTick, upperTick)
s.Require().NoError(err)

s.Require().Equal(sdk.NewInt(1), asset0)
s.Require().Equal(sdk.NewInt(5000), asset1)
}
40 changes: 39 additions & 1 deletion x/concentrated-liquidity/math.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package concentrated_liquidity

import sdk "github.com/cosmos/cosmos-sdk/types"
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// liquidity0 takes an amount of asset0 in the pool as well as the sqrtpCur and the nextPrice
// sqrtPriceA is the smaller of sqrtpCur and the nextPrice
Expand Down Expand Up @@ -52,3 +54,39 @@ func calcAmount1Delta(liq, sqrtPriceA, sqrtPriceB sdk.Dec) sdk.Dec {
diff := sqrtPriceB.Sub(sqrtPriceA)
return liq.Mul(diff)
}

// computeSwapStep calculates the amountIn, amountOut, and the next sqrtPrice given current price, price target, tick liquidity, and amount available to swap
// lte is reference to "less than or equal", which determines if we are moving left or right of the current price to find the next initialized tick with liquidity
func computeSwapStep(sqrtPriceCurrent, sqrtPriceTarget, liquidity, amountRemaining sdk.Dec, lte bool) (sqrtPriceNext sdk.Dec, amountIn sdk.Dec, amountOut sdk.Dec) {
if lte {
sqrtPriceNext = getNextSqrtPriceFromAmount1RoundingDown(sqrtPriceCurrent, liquidity, amountRemaining)
amountIn = calcAmount1Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
amountOut = calcAmount0Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
} else {
sqrtPriceNext = getNextSqrtPriceFromAmount0RoundingUp(sqrtPriceCurrent, liquidity, amountRemaining)
amountIn = calcAmount0Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
amountOut = calcAmount1Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
}
return sqrtPriceNext, amountIn, amountOut
}

func getNextSqrtPriceFromAmount0RoundingUp(sqrtPriceCurrent, liquidity, amountRemaining sdk.Dec) (sqrtPriceNext sdk.Dec) {
numerator := liquidity.Mul(sdk.NewDec(2))
product := amountRemaining.Mul(sqrtPriceCurrent)

if product.Quo(amountRemaining).Equal(sqrtPriceCurrent) {
denominator := numerator.Add(product)
if denominator.GTE(numerator) {
numerator = numerator.Mul(sqrtPriceCurrent)
sqrtPriceNext = numerator.QuoRoundUp(denominator)
return sqrtPriceNext
}
}
denominator := numerator.Quo(sqrtPriceCurrent).Add(amountRemaining)
sqrtPriceNext = numerator.QuoRoundUp(denominator)
return sqrtPriceNext
}

func getNextSqrtPriceFromAmount1RoundingDown(sqrtPriceCurrent, liquidity, amountRemaining sdk.Dec) (sqrtPriceNext sdk.Dec) {
return sqrtPriceCurrent.Add(amountRemaining.Quo(liquidity))
}
Loading

0 comments on commit 0e7e02a

Please sign in to comment.