Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add state for Mint: tick and Position #3136

Merged
merged 10 commits into from
Oct 25, 2022
Merged
9 changes: 7 additions & 2 deletions proto/osmosis/concentrated-liquidity/concentratedPool.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ message Pool {
}

message TickInfo {
string liquidity = 1 [
string liquidity_gross = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.moretags) = "yaml:\"liquidity_gross\"",
(gogoproto.nullable) = false
];
string liquidity_net = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"liquidity_net\"",
(gogoproto.nullable) = false
];
}
Expand Down
121 changes: 86 additions & 35 deletions x/concentrated-liquidity/concentratedPool.pb.go

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

28 changes: 21 additions & 7 deletions x/concentrated-liquidity/lp.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,28 @@ 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.setPosition(ctx, poolId, owner, lowerTick, upperTick, Position{})
// k.updatePositionWithLiquidity(ctx, poolId, owner, lowerTick, upperTick, liquidityIn)

// update tickInfo state
// TODO: come back to sdk.Int vs sdk.Dec state & truncation
err = k.initOrUpdateTick(ctx, poolId, lowerTick, liquidityIn.TruncateInt(), false)
if err != nil {
return sdk.Int{}, sdk.Int{}, err
}

// TODO: come back to sdk.Int vs sdk.Dec state & truncation
err = k.initOrUpdateTick(ctx, poolId, upperTick, liquidityIn.TruncateInt(), true)
if err != nil {
return sdk.Int{}, sdk.Int{}, err
}

// update position state
// TODO: come back to sdk.Int vs sdk.Dec state & truncation
err = k.initOrUpdatePosition(ctx, poolId, owner, lowerTick, upperTick, liquidityIn.TruncateInt())
if err != nil {
return sdk.Int{}, sdk.Int{}, err
}

// now calculate amount for token0 and token1
pool := k.getPoolbyId(ctx, poolId)

currentSqrtPrice := pool.CurrentSqrtPrice
Expand Down
17 changes: 16 additions & 1 deletion x/concentrated-liquidity/lp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,22 @@ func (s *KeeperTestSuite) TestMint() {

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)

// check position state
position, err := s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, poolId, s.TestAccs[0], lowerTick, upperTick)
s.Require().NoError(err)
s.Require().Equal(sdk.NewInt(1517), position.Liquidity)

// check tick state
lowerTickInfo, err := s.App.ConcentratedLiquidityKeeper.GetTickInfo(s.Ctx, poolId, lowerTick)
s.Require().NoError(err)
s.Require().Equal(sdk.NewInt(1517), lowerTickInfo.LiquidityGross)
s.Require().Equal(sdk.NewInt(1517), lowerTickInfo.LiquidityNet)

upperTickInfo, err := s.App.ConcentratedLiquidityKeeper.GetTickInfo(s.Ctx, poolId, upperTick)
s.Require().NoError(err)
s.Require().Equal(sdk.NewInt(1517), upperTickInfo.LiquidityGross)
s.Require().Equal(sdk.NewInt(-1517), upperTickInfo.LiquidityNet)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain the math behind getting 1517?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the liquidity we put in initially as the testing params

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a comment for that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

}
39 changes: 28 additions & 11 deletions x/concentrated-liquidity/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,53 @@ package concentrated_liquidity

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/gogo/protobuf/proto"

"github.com/osmosis-labs/osmosis/v12/osmoutils"
types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
)

// nolint: unused
func (k Keeper) updatePositionWithLiquidity(ctx sdk.Context,
func (k Keeper) initOrUpdatePosition(ctx sdk.Context,
poolId uint64,
owner sdk.AccAddress,
lowerTick, upperTick int64,
liquidityDelta sdk.Int,
) {
position := k.getPosition(ctx, poolId, owner, lowerTick, upperTick)
) (err error) {
position, err := k.GetPosition(ctx, poolId, owner, lowerTick, upperTick)
if err != nil {
return err
}

liquidityBefore := position.Liquidity
liquidityAfter := liquidityBefore.Add(liquidityDelta)
var liquidityAfter sdk.Int
if liquidityDelta.IsNegative() {
liquidityAfter = liquidityBefore.Sub(liquidityDelta)
} else {
liquidityAfter = liquidityBefore.Add(liquidityDelta)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be clear, this means that no matter what, we are adding liquidity to liquidityAfter, even if we have a negative delta right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if we have a negative delta, we don't want to subtract it from liquidityBefore, so we do another negative to add the absolute value of liquidityDelta


position.Liquidity = liquidityAfter

k.setPosition(ctx, poolId, owner, lowerTick, upperTick, position)
return nil
}

// nolint: unused
func (k Keeper) getPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64) Position {
func (k Keeper) GetPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64) (position Position, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason we had to make this public?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for testing purposes / I don't think we have security vulnerability exposing getter method

store := ctx.KVStore(k.storeKey)

var position Position
positionStruct := Position{}
key := types.KeyPosition(poolId, owner, lowerTick, upperTick)
osmoutils.MustGet(store, key, &position)

return position
bz := store.Get(key)
if bz == nil {
return Position{Liquidity: sdk.ZeroInt()}, nil
}
mattverse marked this conversation as resolved.
Show resolved Hide resolved

err = proto.Unmarshal(bz, &positionStruct)
if err != nil {
return positionStruct, err
}

return positionStruct, nil
}

// nolint: unused
Expand Down
59 changes: 50 additions & 9 deletions x/concentrated-liquidity/tick.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
db "github.com/tendermint/tm-db"

"github.com/gogo/protobuf/proto"

"github.com/osmosis-labs/osmosis/v12/osmomath"
"github.com/osmosis-labs/osmosis/v12/osmoutils"
types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
Expand All @@ -26,14 +28,42 @@ func (k Keeper) tickToSqrtPrice(tickIndex sdk.Int) (sdk.Dec, error) {
// return sdk.Int{}
// }

func (k Keeper) UpdateTickWithNewLiquidity(ctx sdk.Context, poolId uint64, tickIndex int64, liquidityDelta sdk.Int) {
tickInfo := k.getTickInfo(ctx, poolId, tickIndex)
func (k Keeper) initOrUpdateTick(ctx sdk.Context, poolId uint64, tickIndex int64, liquidityIn sdk.Int, upper bool) (err error) {
tickInfo, err := k.GetTickInfo(ctx, poolId, tickIndex)
if err != nil {
return err
}

// calculate liquidityGross, which does not care about whether liquidityIn is positive or negative
liquidityBefore := tickInfo.LiquidityGross
var liquidityAfter sdk.Int
if liquidityIn.IsNegative() {
liquidityAfter = liquidityBefore.Sub(liquidityIn)
} else {
liquidityAfter = liquidityBefore.Add(liquidityIn)
}
tickInfo.LiquidityGross = liquidityAfter

liquidityBefore := tickInfo.Liquidity
liquidityAfter := liquidityBefore.Add(liquidityDelta)
tickInfo.Liquidity = liquidityAfter
// calculate liquidityNet, which we take into account and track depending on whether liquidityIn is positive or negative
if upper {
tickInfo.LiquidityNet = tickInfo.LiquidityNet.Sub(liquidityIn)
} else {
tickInfo.LiquidityNet = tickInfo.LiquidityNet.Add(liquidityIn)
}

k.setTickInfo(ctx, poolId, tickIndex, tickInfo)

return nil
}

// nolint: unused
func (k Keeper) crossTick(ctx sdk.Context, poolId uint64, tickIndex int64) (liquidityDelta sdk.Int, err error) {
tickInfo, err := k.GetTickInfo(ctx, poolId, tickIndex)
if err != nil {
return sdk.Int{}, err
}

return tickInfo.LiquidityNet, nil
}

// NextInitializedTick returns the next initialized tick index based on the
Expand Down Expand Up @@ -87,12 +117,23 @@ func (k Keeper) NextInitializedTick(ctx sdk.Context, poolId uint64, tickIndex in
return 0, false
}

func (k Keeper) getTickInfo(ctx sdk.Context, poolId uint64, tickIndex int64) TickInfo {
// getTickInfo gets tickInfo given poolId and tickIndex. Returns a boolean field that returns true if value is found for given key.
func (k Keeper) GetTickInfo(ctx sdk.Context, poolId uint64, tickIndex int64) (tickInfo TickInfo, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason we also made this public?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for testing purposes / I don't think we have security vulnerability exposing getter method

store := ctx.KVStore(k.storeKey)
tickInfo := TickInfo{}
tickStruct := TickInfo{}
key := types.KeyTick(poolId, tickIndex)
osmoutils.MustGet(store, key, &tickInfo)
return tickInfo

bz := store.Get(key)
mattverse marked this conversation as resolved.
Show resolved Hide resolved
if bz == nil {
return TickInfo{LiquidityGross: sdk.ZeroInt(), LiquidityNet: sdk.ZeroInt()}, err
}

err = proto.Unmarshal(bz, &tickStruct)
if err != nil {
return tickStruct, err
}

return tickStruct, nil
}

func (k Keeper) setTickInfo(ctx sdk.Context, poolId uint64, tickIndex int64, tickInfo TickInfo) {
Expand Down