Skip to content

Commit

Permalink
perf: conver tick and exponent at price one to int64 (#5190)
Browse files Browse the repository at this point in the history
Closes: #XXX

## What is the purpose of the change

Convert pool's tick and exponent at price one to int64 for performance and readability
  • Loading branch information
p0mvn authored and pysel committed Jun 6, 2023
1 parent bf59ae7 commit 2a08255
Show file tree
Hide file tree
Showing 20 changed files with 239 additions and 285 deletions.
13 changes: 3 additions & 10 deletions proto/osmosis/concentrated-liquidity/pool.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,12 @@ message Pool {
(gogoproto.moretags) = "yaml:\"spot_price\"",
(gogoproto.nullable) = false
];
string current_tick = 8 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"current_tick\"",
(gogoproto.nullable) = false
];
int64 current_tick = 8 [ (gogoproto.moretags) = "yaml:\"current_tick\"" ];
// tick_spacing must be one of the authorized_tick_spacing values set in the
// concentrated-liquidity parameters
uint64 tick_spacing = 9 [ (gogoproto.moretags) = "yaml:\"tick_spacing\"" ];
string exponent_at_price_one = 10 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"exponent_at_price_one\"",
(gogoproto.nullable) = false
];
int64 exponent_at_price_one = 10
[ (gogoproto.moretags) = "yaml:\"exponent_at_price_one\"" ];

// swap_fee is the ratio that is charged on the amount of token in.
string swap_fee = 11 [
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (s *IntegrationTestSuite) TestConcentratedLiquidity() {
concentratedPool := s.updatedPool(chainANode, poolID)

// Sanity check that pool initialized with valid parameters (the ones that we haven't explicitly specified)
s.Require().Equal(concentratedPool.GetCurrentTick().Int64(), int64(0))
s.Require().Equal(concentratedPool.GetCurrentTick(), int64(0))
s.Require().Equal(concentratedPool.GetCurrentSqrtPrice(), sdk.ZeroDec())
s.Require().Equal(concentratedPool.GetLiquidity(), sdk.ZeroDec())

Expand All @@ -231,7 +231,7 @@ func (s *IntegrationTestSuite) TestConcentratedLiquidity() {
s.Require().Equal(concentratedPool.GetToken0(), denom0)
s.Require().Equal(concentratedPool.GetToken1(), denom1)
s.Require().Equal(concentratedPool.GetTickSpacing(), tickSpacing)
s.Require().Equal(concentratedPool.GetExponentAtPriceOne().Int64(), cltypes.ExponentAtPriceOne)
s.Require().Equal(concentratedPool.GetExponentAtPriceOne(), cltypes.ExponentAtPriceOne)
s.Require().Equal(concentratedPool.GetSwapFee(sdk.Context{}), sdk.MustNewDecFromStr(swapFee))

fundTokens := []string{"100000000uosmo", "100000000uion", "100000000stake"}
Expand Down
16 changes: 8 additions & 8 deletions x/concentrated-liquidity/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,14 @@ func BenchmarkSwapExactAmountIn(b *testing.B) {
// Decreasing price so want to be below current tick

// minTick <= lowerTick <= currentTick
lowerTick = rand.Int63n(currentTick.Int64()-types.MinTick+1) + types.MinTick
lowerTick = rand.Int63n(currentTick-types.MinTick+1) + types.MinTick
// lowerTick <= upperTick <= currentTick
upperTick = currentTick.Int64() - rand.Int63n(int64(math.Abs(float64(currentTick.Int64()-lowerTick))))
upperTick = currentTick - rand.Int63n(int64(math.Abs(float64(currentTick-lowerTick))))
} else {
// Increasing price so want to be above current tick

// currentTick <= lowerTick <= maxTick
lowerTick := rand.Int63n(types.MaxTick-currentTick.Int64()+1) + currentTick.Int64()
lowerTick := rand.Int63n(types.MaxTick-currentTick+1) + currentTick
// lowerTick <= upperTick <= maxTick
upperTick = types.MaxTick - rand.Int63n(int64(math.Abs(float64(types.MaxTick-lowerTick))))
}
Expand Down Expand Up @@ -171,8 +171,8 @@ func BenchmarkSwapExactAmountIn(b *testing.B) {
// Within 10 ticks of the current
if tickSpacing <= 10 {
for i := 0; i < numberOfPositions; i++ {
lowerTick := currentTick.Int64() - 10
upperTick := currentTick.Int64() + 10
lowerTick := currentTick - 10
upperTick := currentTick + 10

tokenDesired0 := sdk.NewCoin(denom0, sdk.NewInt(maxAmountDeposited).MulRaw(5))
tokenDesired1 := sdk.NewCoin(denom1, sdk.NewInt(maxAmountDeposited).MulRaw(5))
Expand All @@ -190,8 +190,8 @@ func BenchmarkSwapExactAmountIn(b *testing.B) {

// Within 100 ticks of the current
for i := 0; i < numberOfPositions; i++ {
lowerTick := currentTick.Int64() - 100
upperTick := currentTick.Int64() + 100
lowerTick := currentTick - 100
upperTick := currentTick + 100
// Normalize lowerTick to be a multiple of tickSpacing
lowerTick = lowerTick + (tickSpacing - lowerTick%tickSpacing)
// Normalize upperTick to be a multiple of tickSpacing
Expand All @@ -214,7 +214,7 @@ func BenchmarkSwapExactAmountIn(b *testing.B) {
swapAmountIn := sdk.MustNewDecFromStr(amountIn).TruncateInt()
largeSwapInCoin := sdk.NewCoin(denomIn, swapAmountIn)

liquidityNet, err := clKeeper.GetTickLiquidityNetInDirection(s.Ctx, pool.GetId(), largeSwapInCoin.Denom, currentTick, sdk.Int{})
liquidityNet, err := clKeeper.GetTickLiquidityNetInDirection(s.Ctx, pool.GetId(), largeSwapInCoin.Denom, sdk.NewInt(currentTick), sdk.Int{})
noError(err)

fmt.Println("num_ticks_traversed", len(liquidityNet))
Expand Down
2 changes: 1 addition & 1 deletion x/concentrated-liquidity/client/query_proto_wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (q Querier) LiquidityNetInDirection(ctx sdk.Context, req clquery.LiquidityN
return nil, err
}

return &clquery.LiquidityNetInDirectionResponse{LiquidityDepths: liquidityDepths, CurrentLiquidity: pool.GetLiquidity(), CurrentTick: pool.GetCurrentTick().Int64()}, nil
return &clquery.LiquidityNetInDirectionResponse{LiquidityDepths: liquidityDepths, CurrentLiquidity: pool.GetLiquidity(), CurrentTick: pool.GetCurrentTick()}, nil
}

func (q Querier) ClaimableFees(ctx sdk.Context, req clquery.ClaimableFeesRequest) (*clquery.ClaimableFeesResponse, error) {
Expand Down
4 changes: 2 additions & 2 deletions x/concentrated-liquidity/fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (k Keeper) getFeeGrowthOutside(ctx sdk.Context, poolId uint64, lowerTick, u
if err != nil {
return sdk.DecCoins{}, err
}
currentTick := pool.GetCurrentTick().Int64()
currentTick := pool.GetCurrentTick()

// get lower, upper tick info
lowerTickInfo, err := k.GetTickInfo(ctx, poolId, lowerTick)
Expand Down Expand Up @@ -164,7 +164,7 @@ func (k Keeper) getInitialFeeGrowthOppositeDirectionOfLastTraversalForTick(ctx s
return sdk.DecCoins{}, err
}

currentTick := pool.GetCurrentTick().Int64()
currentTick := pool.GetCurrentTick()
if currentTick >= tick {
feeAccumulator, err := k.GetFeeAccumulator(ctx, poolId)
if err != nil {
Expand Down
32 changes: 16 additions & 16 deletions x/concentrated-liquidity/fees_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,11 @@ func (s *KeeperTestSuite) TestGetFeeGrowthOutside() {
var pool types.ConcentratedPoolExtension
if tc.poolSetup {
pool = s.PrepareConcentratedPool()
currentTick := pool.GetCurrentTick().Int64()
currentTick := pool.GetCurrentTick()

s.initializeTick(s.Ctx, currentTick, tc.lowerTick, defaultInitialLiquidity, tc.lowerTickFeeGrowthOutside, emptyUptimeTrackers, false)
s.initializeTick(s.Ctx, currentTick, tc.upperTick, defaultInitialLiquidity, tc.upperTickFeeGrowthOutside, emptyUptimeTrackers, true)
pool.SetCurrentTick(sdk.NewInt(tc.currentTick))
pool.SetCurrentTick(tc.currentTick)
err := s.App.ConcentratedLiquidityKeeper.SetPool(s.Ctx, pool)
s.Require().NoError(err)
err = s.App.ConcentratedLiquidityKeeper.ChargeFee(s.Ctx, validPoolId, tc.globalFeeGrowth)
Expand Down Expand Up @@ -916,7 +916,7 @@ func (s *KeeperTestSuite) TestQueryAndCollectFees() {

s.initializeTick(ctx, tc.currentTick, tc.upperTick, tc.initialLiquidity, tc.upperTickFeeGrowthOutside, emptyUptimeTrackers, true)

validPool.SetCurrentTick(sdk.NewInt(tc.currentTick))
validPool.SetCurrentTick(tc.currentTick)
err = clKeeper.SetPool(ctx, validPool)
s.Require().NoError(err)

Expand Down Expand Up @@ -1179,7 +1179,7 @@ func (s *KeeperTestSuite) TestPrepareClaimableFees() {
s.initializeFeeAccumulatorPositionWithLiquidity(ctx, validPoolId, tc.lowerTick, tc.upperTick, DefaultPositionId, tc.initialLiquidity)
s.initializeTick(ctx, tc.currentTick, tc.lowerTick, tc.initialLiquidity, tc.lowerTickFeeGrowthOutside, emptyUptimeTrackers, false)
s.initializeTick(ctx, tc.currentTick, tc.upperTick, tc.initialLiquidity, tc.upperTickFeeGrowthOutside, emptyUptimeTrackers, true)
validPool.SetCurrentTick(sdk.NewInt(tc.currentTick))
validPool.SetCurrentTick(tc.currentTick)

_ = clKeeper.SetPool(ctx, validPool)

Expand Down Expand Up @@ -1287,10 +1287,10 @@ func (s *KeeperTestSuite) TestInitOrUpdateFeeAccumulatorPosition_UpdatingPositio
s.crossTickAndChargeFee(poolId, DefaultLowerTick)
}

err := s.App.ConcentratedLiquidityKeeper.InitOrUpdateTick(s.Ctx, poolId, pool.GetCurrentTick().Int64(), DefaultLowerTick, DefaultLiquidityAmt, false)
err := s.App.ConcentratedLiquidityKeeper.InitOrUpdateTick(s.Ctx, poolId, pool.GetCurrentTick(), DefaultLowerTick, DefaultLiquidityAmt, false)
s.Require().NoError(err)

err = s.App.ConcentratedLiquidityKeeper.InitOrUpdateTick(s.Ctx, poolId, pool.GetCurrentTick().Int64(), DefaultUpperTick, DefaultLiquidityAmt, true)
err = s.App.ConcentratedLiquidityKeeper.InitOrUpdateTick(s.Ctx, poolId, pool.GetCurrentTick(), DefaultUpperTick, DefaultLiquidityAmt, true)
s.Require().NoError(err)

// InitOrUpdateFeeAccumulatorPosition #1 lower tick to upper tick
Expand Down Expand Up @@ -1456,11 +1456,11 @@ func (s *KeeperTestSuite) TestFunctional_Fees_Swaps() {

// Swap multiple times USDC for ETH, therefore increasing the spot price
ticksActivatedAfterEachSwap, totalFeesExpected, _, _ := s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin1, ETH, types.MaxSpotPrice, positions.numSwaps)
s.CollectAndAssertFees(s.Ctx, clPool.GetId(), totalFeesExpected, positionIds, [][]sdk.Int{ticksActivatedAfterEachSwap}, onlyUSDC, positions)
s.CollectAndAssertFees(s.Ctx, clPool.GetId(), totalFeesExpected, positionIds, [][]int64{ticksActivatedAfterEachSwap}, onlyUSDC, positions)

// Swap multiple times ETH for USDC, therefore decreasing the spot price
ticksActivatedAfterEachSwap, totalFeesExpected, _, _ = s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin0, USDC, types.MinSpotPrice, positions.numSwaps)
s.CollectAndAssertFees(s.Ctx, clPool.GetId(), totalFeesExpected, positionIds, [][]sdk.Int{ticksActivatedAfterEachSwap}, onlyETH, positions)
s.CollectAndAssertFees(s.Ctx, clPool.GetId(), totalFeesExpected, positionIds, [][]int64{ticksActivatedAfterEachSwap}, onlyETH, positions)

// Do the same swaps as before, however this time we collect fees after both swap directions are complete.
ticksActivatedAfterEachSwapUp, totalFeesExpectedUp, _, _ := s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin1, ETH, types.MaxSpotPrice, positions.numSwaps)
Expand All @@ -1469,7 +1469,7 @@ func (s *KeeperTestSuite) TestFunctional_Fees_Swaps() {

// We expect all positions to have both denoms in their fee accumulators except USDC for the overlapping range position since
// it was not activated during the USDC -> ETH swap direction but was activated during the ETH -> USDC swap direction.
ticksActivatedAfterEachSwapTest := [][]sdk.Int{ticksActivatedAfterEachSwapUp, ticksActivatedAfterEachSwapDown}
ticksActivatedAfterEachSwapTest := [][]int64{ticksActivatedAfterEachSwapUp, ticksActivatedAfterEachSwapDown}
denomsExpected := [][]string{{USDC, ETH}, {USDC, ETH}, {USDC, ETH}, {NoUSDCExpected, ETH}}

s.CollectAndAssertFees(s.Ctx, clPool.GetId(), totalFeesExpected, positionIds, ticksActivatedAfterEachSwapTest, denomsExpected, positions)
Expand Down Expand Up @@ -1514,7 +1514,7 @@ func (s *KeeperTestSuite) TestFunctional_Fees_LP() {
s.Require().NoError(err)

// Collect fees.
feesCollected := s.collectFeesAndCheckInvariance(ctx, 0, DefaultMinTick, DefaultMaxTick, positionIdOne, sdk.NewCoins(), []string{USDC}, [][]sdk.Int{ticksActivatedAfterEachSwap})
feesCollected := s.collectFeesAndCheckInvariance(ctx, 0, DefaultMinTick, DefaultMaxTick, positionIdOne, sdk.NewCoins(), []string{USDC}, [][]int64{ticksActivatedAfterEachSwap})
expectedFeesTruncated := totalFeesExpected
for i, feeToken := range totalFeesExpected {
// We run expected fees through a cycle of divison and multiplication by liquidity to capture appropriate rounding behavior
Expand Down Expand Up @@ -1547,7 +1547,7 @@ func (s *KeeperTestSuite) TestFunctional_Fees_LP() {
_, err = s.App.ConcentratedLiquidityKeeper.CollectFees(ctx, owner, positionIdTwo)
s.Require().Error(err)

feesCollected = s.collectFeesAndCheckInvariance(ctx, 0, DefaultMinTick, DefaultMaxTick, positionIdOne, sdk.NewCoins(), []string{ETH}, [][]sdk.Int{ticksActivatedAfterEachSwap})
feesCollected = s.collectFeesAndCheckInvariance(ctx, 0, DefaultMinTick, DefaultMaxTick, positionIdOne, sdk.NewCoins(), []string{ETH}, [][]int64{ticksActivatedAfterEachSwap})

// total fees * half liquidity / (full liquidity + half liquidity)
expectesFeesCollected := totalFeesExpected.AmountOf(ETH).ToDec().Mul(halfLiquidity.Quo(fullLiquidity.Add(halfLiquidity))).TruncateInt()
Expand All @@ -1565,7 +1565,7 @@ func (s *KeeperTestSuite) TestFunctional_Fees_LP() {
// CollectAndAssertFees collects fees from a given pool for all positions and verifies that the total fees collected match the expected total fees.
// The method also checks that if the ticks that were active during the swap lie within the range of a position, then the position's fee accumulators
// are not empty. The total fees collected are compared to the expected total fees within an additive tolerance defined by an error tolerance struct.
func (s *KeeperTestSuite) CollectAndAssertFees(ctx sdk.Context, poolId uint64, totalFees sdk.Coins, positionIds [][]uint64, activeTicks [][]sdk.Int, expectedFeeDenoms [][]string, positions Positions) {
func (s *KeeperTestSuite) CollectAndAssertFees(ctx sdk.Context, poolId uint64, totalFees sdk.Coins, positionIds [][]uint64, activeTicks [][]int64, expectedFeeDenoms [][]string, positions Positions) {
var totalFeesCollected sdk.Coins
// Claim full range position fees across all four accounts
for i := 0; i < positions.numFullRange; i++ {
Expand Down Expand Up @@ -1602,12 +1602,12 @@ func (s *KeeperTestSuite) CollectAndAssertFees(ctx sdk.Context, poolId uint64, t

// tickStatusInvariance tests if the swap position was active during the given tick range and
// checks that the fees collected are non-zero if the position was active, or zero otherwise.
func (s *KeeperTestSuite) tickStatusInvariance(ticksActivatedAfterEachSwap [][]sdk.Int, lowerTick, upperTick int64, coins sdk.Coins, expectedFeeDenoms []string) {
func (s *KeeperTestSuite) tickStatusInvariance(ticksActivatedAfterEachSwap [][]int64, lowerTick, upperTick int64, coins sdk.Coins, expectedFeeDenoms []string) {
var positionWasActive bool
// Check if the position was active during the swap
for i, ticks := range ticksActivatedAfterEachSwap {
for _, tick := range ticks {
if tick.GTE(sdk.NewInt(lowerTick)) && tick.LTE(sdk.NewInt(upperTick)) {
if tick >= lowerTick && tick <= upperTick {
positionWasActive = true
break
}
Expand All @@ -1626,7 +1626,7 @@ func (s *KeeperTestSuite) tickStatusInvariance(ticksActivatedAfterEachSwap [][]s

// swapAndTrackXTimesInARow performs `numSwaps` swaps and tracks the tick activated after each swap.
// It also returns the total fees collected, the total token in, and the total token out.
func (s *KeeperTestSuite) swapAndTrackXTimesInARow(poolId uint64, coinIn sdk.Coin, coinOutDenom string, priceLimit sdk.Dec, numSwaps int) (ticksActivatedAfterEachSwap []sdk.Int, totalFees sdk.Coins, totalTokenIn sdk.Coin, totalTokenOut sdk.Coin) {
func (s *KeeperTestSuite) swapAndTrackXTimesInARow(poolId uint64, coinIn sdk.Coin, coinOutDenom string, priceLimit sdk.Dec, numSwaps int) (ticksActivatedAfterEachSwap []int64, totalFees sdk.Coins, totalTokenIn sdk.Coin, totalTokenOut sdk.Coin) {
// Retrieve pool
clPool, err := s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, poolId)
s.Require().NoError(err)
Expand Down Expand Up @@ -1656,7 +1656,7 @@ func (s *KeeperTestSuite) swapAndTrackXTimesInARow(poolId uint64, coinIn sdk.Coi
}

// collectFeesAndCheckInvariance collects fees from the concentrated liquidity pool and checks the resulting tick status invariance.
func (s *KeeperTestSuite) collectFeesAndCheckInvariance(ctx sdk.Context, accountIndex int, minTick, maxTick int64, positionId uint64, feesCollected sdk.Coins, expectedFeeDenoms []string, activeTicks [][]sdk.Int) (totalFeesCollected sdk.Coins) {
func (s *KeeperTestSuite) collectFeesAndCheckInvariance(ctx sdk.Context, accountIndex int, minTick, maxTick int64, positionId uint64, feesCollected sdk.Coins, expectedFeeDenoms []string, activeTicks [][]int64) (totalFeesCollected sdk.Coins) {
coins, err := s.App.ConcentratedLiquidityKeeper.CollectFees(ctx, s.TestAccs[accountIndex], positionId)
s.Require().NoError(err)
totalFeesCollected = feesCollected.Add(coins...)
Expand Down
4 changes: 2 additions & 2 deletions x/concentrated-liquidity/incentives.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (k Keeper) getInitialUptimeGrowthOppositeDirectionOfLastTraversalForTick(ct
return []sdk.DecCoins{}, err
}

currentTick := pool.GetCurrentTick().Int64()
currentTick := pool.GetCurrentTick()
if currentTick >= tick {
uptimeAccumulatorValues, err := k.getUptimeAccumulatorValues(ctx, poolId)
if err != nil {
Expand Down Expand Up @@ -566,7 +566,7 @@ func (k Keeper) GetUptimeGrowthInsideRange(ctx sdk.Context, poolId uint64, lower
}

// Get current, lower, and upper ticks
currentTick := pool.GetCurrentTick().Int64()
currentTick := pool.GetCurrentTick()
lowerTickInfo, err := k.GetTickInfo(ctx, poolId, lowerTick)
if err != nil {
return []sdk.DecCoins{}, err
Expand Down
Loading

0 comments on commit 2a08255

Please sign in to comment.