From 0766ef99411aa058a2b8b33e0017fcecee72a572 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Fri, 14 Jun 2024 18:39:53 -0400 Subject: [PATCH 1/5] Add a migration to recalculate price to use high prec_dec precision --- x/dex/migrations/v3/store.go | 87 +++++++++++++++++++++++++++++-- x/dex/migrations/v3/store_test.go | 54 +++++++++++++++++++ 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/x/dex/migrations/v3/store.go b/x/dex/migrations/v3/store.go index 5180eeae7..c9404d239 100644 --- a/x/dex/migrations/v3/store.go +++ b/x/dex/migrations/v3/store.go @@ -15,11 +15,23 @@ import ( // MigrateStore performs in-place store migrations. // The migration adds new dex params -- GoodTilPurgeAllowance & MaxJITsPerBlock// for handling JIT orders. func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { - err := migrateParams(ctx, cdc, storeKey) - if err != nil { + if err := migrateParams(ctx, cdc, storeKey); err != nil { + return err + } + + if err := migrateLimitOrderExpirations(ctx, cdc, storeKey); err != nil { return err } - return migrateLimitOrderExpirations(ctx, cdc, storeKey) + + if err := migrateTickLiquidityPrices(ctx, cdc, storeKey); err != nil { + return err + } + + if err := migrateInactiveTranchePrices(ctx, cdc, storeKey); err != nil { + return err + } + + return nil } func migrateParams(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { @@ -92,3 +104,72 @@ func migrateLimitOrderExpirations(ctx sdk.Context, cdc codec.BinaryCodec, storeK return nil } + +func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + ctx.Logger().Info("Migrating TickLiquidity Prices...") + + // Iterate through all tickLiquidity + store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.TickLiquidityKeyPrefix)) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + + for ; iterator.Valid(); iterator.Next() { + var tickLiq types.TickLiquidity + var updatedTickLiq types.TickLiquidity + cdc.MustUnmarshal(iterator.Value(), &tickLiq) + // Recalculate all prices by precisionUpdateMultiplier + switch liquidity := tickLiq.Liquidity.(type) { + case *types.TickLiquidity_LimitOrderTranche: + liquidity.LimitOrderTranche.PriceTakerToMaker = types.MustCalcPrice(liquidity.LimitOrderTranche.Key.TickIndexTakerToMaker) + updatedTickLiq = types.TickLiquidity{Liquidity: liquidity} + case *types.TickLiquidity_PoolReserves: + poolReservesKey := liquidity.PoolReserves.Key + liquidity.PoolReserves.PriceTakerToMaker = types.MustCalcPrice(poolReservesKey.TickIndexTakerToMaker) + liquidity.PoolReserves.PriceOppositeTakerToMaker = poolReservesKey.Counterpart().MustPriceTakerToMaker() + updatedTickLiq = types.TickLiquidity{Liquidity: liquidity} + + default: + panic("Tick does not contain valid liqudityType") + } + // Store the updated tickLiquidity + bz := cdc.MustMarshal(&updatedTickLiq) + store.Set(iterator.Key(), bz) + } + + err := iterator.Close() + if err != nil { + return err + } + + ctx.Logger().Info("Finished migrating TickLiquidity Prices...") + + return nil +} + +func migrateInactiveTranchePrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + ctx.Logger().Info("Migrating InactiveLimitOrderTranche Prices...") + + // Iterate through all tickLiquidity + store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.InactiveLimitOrderTrancheKeyPrefix)) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + + for ; iterator.Valid(); iterator.Next() { + var tranche types.LimitOrderTranche + cdc.MustUnmarshal(iterator.Value(), &tranche) + // Multiply all price by precisionUpdateMultiplier + + tranche.PriceTakerToMaker = types.MustCalcPrice(tranche.Key.TickIndexTakerToMaker) + + // Store the updated tickLiquidity + bz := cdc.MustMarshal(&tranche) + store.Set(iterator.Key(), bz) + } + + err := iterator.Close() + if err != nil { + return err + } + + ctx.Logger().Info("Finished Migrating InactiveLimitOrderTranche Prices...") + + return nil +} diff --git a/x/dex/migrations/v3/store_test.go b/x/dex/migrations/v3/store_test.go index 7dc44dc37..8e4c3caf1 100644 --- a/x/dex/migrations/v3/store_test.go +++ b/x/dex/migrations/v3/store_test.go @@ -117,3 +117,57 @@ func (suite *V3DexMigrationTestSuite) TestLimitOrderExpirationUpgrade() { allExp := app.DexKeeper.GetAllLimitOrderExpiration(ctx) suite.Require().Equal(len(lOExpirations), len(allExp)) } + +func (suite *V3DexMigrationTestSuite) TestPriceUpdates() { + var ( + app = suite.GetNeutronZoneApp(suite.ChainA) + storeKey = app.GetKey(types.StoreKey) + ctx = suite.ChainA.GetContext() + cdc = app.AppCodec() + ) + + // Write tranche with incorrect price + trancheKey := &types.LimitOrderTrancheKey{ + TradePairId: types.MustNewTradePairID("TokenA", "TokenB"), + TickIndexTakerToMaker: -50, + TrancheKey: "123", + } + tranche := &types.LimitOrderTranche{ + Key: trancheKey, + PriceTakerToMaker: math.ZeroPrecDec(), + } + // create active tranche + app.DexKeeper.SetLimitOrderTranche(ctx, tranche) + // create inactive tranche + app.DexKeeper.SetInactiveLimitOrderTranche(ctx, tranche) + + // Write poolReserves with old precision + poolKey := &types.PoolReservesKey{ + TradePairId: types.MustNewTradePairID("TokenA", "TokenB"), + TickIndexTakerToMaker: 60000, + Fee: 1, + } + poolReserves := &types.PoolReserves{ + Key: poolKey, + PriceTakerToMaker: math.ZeroPrecDec(), + PriceOppositeTakerToMaker: math.ZeroPrecDec(), + } + + app.DexKeeper.SetPoolReserves(ctx, poolReserves) + + // Run migration + suite.NoError(v3.MigrateStore(ctx, cdc, storeKey)) + + // Check LimitOrderTranche has correct price + newTranche := app.DexKeeper.GetLimitOrderTranche(ctx, trancheKey) + suite.True(newTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815")), "was : %v", newTranche.PriceTakerToMaker) + + // check InactiveLimitOrderTranche has correct price + inactiveTranche, _ := app.DexKeeper.GetInactiveLimitOrderTranche(ctx, trancheKey) + suite.True(inactiveTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815")), "was : %v", newTranche.PriceTakerToMaker) + + // Check PoolReserves has the correct prices + newPool, _ := app.DexKeeper.GetPoolReserves(ctx, poolKey) + suite.True(newPool.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("0.002479495864288162666675923")), "was : %v", newPool.PriceTakerToMaker) + suite.True(newPool.PriceOppositeTakerToMaker.Equal(math.MustNewPrecDecFromStr("403.227141612124702272520931931")), "was : %v", newPool.PriceOppositeTakerToMaker) +} From ae627fef7cfb354f05d8fe785ef4237657020efd Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Fri, 14 Jun 2024 18:56:51 -0400 Subject: [PATCH 2/5] misc formatting and cleanup --- x/dex/migrations/v3/store.go | 4 +++- x/dex/migrations/v3/store_test.go | 15 +++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/x/dex/migrations/v3/store.go b/x/dex/migrations/v3/store.go index c9404d239..1f3079a46 100644 --- a/x/dex/migrations/v3/store.go +++ b/x/dex/migrations/v3/store.go @@ -106,6 +106,7 @@ func migrateLimitOrderExpirations(ctx sdk.Context, cdc codec.BinaryCodec, storeK } func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore ctx.Logger().Info("Migrating TickLiquidity Prices...") // Iterate through all tickLiquidity @@ -146,6 +147,7 @@ func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey } func migrateInactiveTranchePrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore ctx.Logger().Info("Migrating InactiveLimitOrderTranche Prices...") // Iterate through all tickLiquidity @@ -169,7 +171,7 @@ func migrateInactiveTranchePrices(ctx sdk.Context, cdc codec.BinaryCodec, storeK return err } - ctx.Logger().Info("Finished Migrating InactiveLimitOrderTranche Prices...") + ctx.Logger().Info("Finished migrating InactiveLimitOrderTranche Prices...") return nil } diff --git a/x/dex/migrations/v3/store_test.go b/x/dex/migrations/v3/store_test.go index 8e4c3caf1..5f9e4a7ba 100644 --- a/x/dex/migrations/v3/store_test.go +++ b/x/dex/migrations/v3/store_test.go @@ -136,12 +136,12 @@ func (suite *V3DexMigrationTestSuite) TestPriceUpdates() { Key: trancheKey, PriceTakerToMaker: math.ZeroPrecDec(), } - // create active tranche app.DexKeeper.SetLimitOrderTranche(ctx, tranche) - // create inactive tranche + + // also create inactive tranche app.DexKeeper.SetInactiveLimitOrderTranche(ctx, tranche) - // Write poolReserves with old precision + // Write poolReserves with incorrect prices poolKey := &types.PoolReservesKey{ TradePairId: types.MustNewTradePairID("TokenA", "TokenB"), TickIndexTakerToMaker: 60000, @@ -152,7 +152,6 @@ func (suite *V3DexMigrationTestSuite) TestPriceUpdates() { PriceTakerToMaker: math.ZeroPrecDec(), PriceOppositeTakerToMaker: math.ZeroPrecDec(), } - app.DexKeeper.SetPoolReserves(ctx, poolReserves) // Run migration @@ -160,14 +159,14 @@ func (suite *V3DexMigrationTestSuite) TestPriceUpdates() { // Check LimitOrderTranche has correct price newTranche := app.DexKeeper.GetLimitOrderTranche(ctx, trancheKey) - suite.True(newTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815")), "was : %v", newTranche.PriceTakerToMaker) + suite.True(newTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815"))) // check InactiveLimitOrderTranche has correct price inactiveTranche, _ := app.DexKeeper.GetInactiveLimitOrderTranche(ctx, trancheKey) - suite.True(inactiveTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815")), "was : %v", newTranche.PriceTakerToMaker) + suite.True(inactiveTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815"))) // Check PoolReserves has the correct prices newPool, _ := app.DexKeeper.GetPoolReserves(ctx, poolKey) - suite.True(newPool.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("0.002479495864288162666675923")), "was : %v", newPool.PriceTakerToMaker) - suite.True(newPool.PriceOppositeTakerToMaker.Equal(math.MustNewPrecDecFromStr("403.227141612124702272520931931")), "was : %v", newPool.PriceOppositeTakerToMaker) + suite.True(newPool.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("0.002479495864288162666675923"))) + suite.True(newPool.PriceOppositeTakerToMaker.Equal(math.MustNewPrecDecFromStr("403.227141612124702272520931931"))) } From b42c0d7189aedc2630285c7909dd3555b47bcd7a Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Thu, 20 Jun 2024 14:43:58 -0400 Subject: [PATCH 3/5] don't write during iteration also wrap errors --- x/dex/migrations/v3/store.go | 39 ++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/x/dex/migrations/v3/store.go b/x/dex/migrations/v3/store.go index 1f3079a46..3afae19a8 100644 --- a/x/dex/migrations/v3/store.go +++ b/x/dex/migrations/v3/store.go @@ -3,6 +3,7 @@ package v3 import ( "errors" + errorsmod "cosmossdk.io/errors" "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" @@ -84,7 +85,7 @@ func migrateLimitOrderExpirations(ctx sdk.Context, cdc codec.BinaryCodec, storeK err := iterator.Close() if err != nil { - return err + return errorsmod.Wrap(err, "iterator failed to close during migration") } for i, key := range expirationKeys { @@ -105,6 +106,11 @@ func migrateLimitOrderExpirations(ctx sdk.Context, cdc codec.BinaryCodec, storeK return nil } +type migrationUpdate struct { + key []byte + val []byte +} + func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore ctx.Logger().Info("Migrating TickLiquidity Prices...") @@ -112,12 +118,13 @@ func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey // Iterate through all tickLiquidity store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.TickLiquidityKeyPrefix)) iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + ticksToUpdate := make([]migrationUpdate, 0) for ; iterator.Valid(); iterator.Next() { var tickLiq types.TickLiquidity var updatedTickLiq types.TickLiquidity cdc.MustUnmarshal(iterator.Value(), &tickLiq) - // Recalculate all prices by precisionUpdateMultiplier + // Recalculate all prices switch liquidity := tickLiq.Liquidity.(type) { case *types.TickLiquidity_LimitOrderTranche: liquidity.LimitOrderTranche.PriceTakerToMaker = types.MustCalcPrice(liquidity.LimitOrderTranche.Key.TickIndexTakerToMaker) @@ -131,14 +138,20 @@ func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey default: panic("Tick does not contain valid liqudityType") } - // Store the updated tickLiquidity + bz := cdc.MustMarshal(&updatedTickLiq) - store.Set(iterator.Key(), bz) + ticksToUpdate = append(ticksToUpdate, migrationUpdate{key: iterator.Key(), val: bz}) + } err := iterator.Close() if err != nil { - return err + return errorsmod.Wrap(err, "iterator failed to close during migration") + } + + // Store the updated TickLiquidity + for _, v := range ticksToUpdate { + store.Set(v.key, v.val) } ctx.Logger().Info("Finished migrating TickLiquidity Prices...") @@ -150,25 +163,29 @@ func migrateInactiveTranchePrices(ctx sdk.Context, cdc codec.BinaryCodec, storeK // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore ctx.Logger().Info("Migrating InactiveLimitOrderTranche Prices...") - // Iterate through all tickLiquidity + // Iterate through all InactiveTranches store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.InactiveLimitOrderTrancheKeyPrefix)) iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + ticksToUpdate := make([]migrationUpdate, 0) for ; iterator.Valid(); iterator.Next() { var tranche types.LimitOrderTranche cdc.MustUnmarshal(iterator.Value(), &tranche) - // Multiply all price by precisionUpdateMultiplier - + // Recalculate price tranche.PriceTakerToMaker = types.MustCalcPrice(tranche.Key.TickIndexTakerToMaker) - // Store the updated tickLiquidity bz := cdc.MustMarshal(&tranche) - store.Set(iterator.Key(), bz) + ticksToUpdate = append(ticksToUpdate, migrationUpdate{key: iterator.Key(), val: bz}) } err := iterator.Close() if err != nil { - return err + return errorsmod.Wrap(err, "iterator failed to close during migration") + } + + // Store the updated InactiveTranches + for _, v := range ticksToUpdate { + store.Set(v.key, v.val) } ctx.Logger().Info("Finished migrating InactiveLimitOrderTranche Prices...") From 56b0ff77ef3841eef69835fa67caf800f90cda33 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Fri, 21 Jun 2024 13:37:17 +0300 Subject: [PATCH 4/5] move migrateTickLiquidityPrices and migrateInactiveTranchePrices to another (v4) consensus migration to simplify testnet migration --- x/dex/keeper/migrations.go | 6 ++ x/dex/migrations/v3/store.go | 96 ------------------------- x/dex/migrations/v3/store_test.go | 53 -------------- x/dex/migrations/v4/store.go | 112 ++++++++++++++++++++++++++++++ x/dex/migrations/v4/store_test.go | 73 +++++++++++++++++++ x/dex/module.go | 4 ++ 6 files changed, 195 insertions(+), 149 deletions(-) create mode 100644 x/dex/migrations/v4/store.go create mode 100644 x/dex/migrations/v4/store_test.go diff --git a/x/dex/keeper/migrations.go b/x/dex/keeper/migrations.go index f08b14797..ef9a8c2bb 100644 --- a/x/dex/keeper/migrations.go +++ b/x/dex/keeper/migrations.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" v3 "github.com/neutron-org/neutron/v4/x/dex/migrations/v3" + v4 "github.com/neutron-org/neutron/v4/x/dex/migrations/v4" ) // Migrator is a struct for handling in-place store migrations. @@ -20,3 +21,8 @@ func NewMigrator(keeper Keeper) Migrator { func (m Migrator) Migrate2to3(ctx sdk.Context) error { return v3.MigrateStore(ctx, m.keeper.cdc, m.keeper.storeKey) } + +// Migrate2to3 migrates from version 3 to 4. +func (m Migrator) Migrate3to4(ctx sdk.Context) error { + return v4.MigrateStore(ctx, m.keeper.cdc, m.keeper.storeKey) +} diff --git a/x/dex/migrations/v3/store.go b/x/dex/migrations/v3/store.go index 3afae19a8..bb26392f1 100644 --- a/x/dex/migrations/v3/store.go +++ b/x/dex/migrations/v3/store.go @@ -23,15 +23,6 @@ func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.St if err := migrateLimitOrderExpirations(ctx, cdc, storeKey); err != nil { return err } - - if err := migrateTickLiquidityPrices(ctx, cdc, storeKey); err != nil { - return err - } - - if err := migrateInactiveTranchePrices(ctx, cdc, storeKey); err != nil { - return err - } - return nil } @@ -105,90 +96,3 @@ func migrateLimitOrderExpirations(ctx sdk.Context, cdc codec.BinaryCodec, storeK return nil } - -type migrationUpdate struct { - key []byte - val []byte -} - -func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { - // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore - ctx.Logger().Info("Migrating TickLiquidity Prices...") - - // Iterate through all tickLiquidity - store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.TickLiquidityKeyPrefix)) - iterator := storetypes.KVStorePrefixIterator(store, []byte{}) - ticksToUpdate := make([]migrationUpdate, 0) - - for ; iterator.Valid(); iterator.Next() { - var tickLiq types.TickLiquidity - var updatedTickLiq types.TickLiquidity - cdc.MustUnmarshal(iterator.Value(), &tickLiq) - // Recalculate all prices - switch liquidity := tickLiq.Liquidity.(type) { - case *types.TickLiquidity_LimitOrderTranche: - liquidity.LimitOrderTranche.PriceTakerToMaker = types.MustCalcPrice(liquidity.LimitOrderTranche.Key.TickIndexTakerToMaker) - updatedTickLiq = types.TickLiquidity{Liquidity: liquidity} - case *types.TickLiquidity_PoolReserves: - poolReservesKey := liquidity.PoolReserves.Key - liquidity.PoolReserves.PriceTakerToMaker = types.MustCalcPrice(poolReservesKey.TickIndexTakerToMaker) - liquidity.PoolReserves.PriceOppositeTakerToMaker = poolReservesKey.Counterpart().MustPriceTakerToMaker() - updatedTickLiq = types.TickLiquidity{Liquidity: liquidity} - - default: - panic("Tick does not contain valid liqudityType") - } - - bz := cdc.MustMarshal(&updatedTickLiq) - ticksToUpdate = append(ticksToUpdate, migrationUpdate{key: iterator.Key(), val: bz}) - - } - - err := iterator.Close() - if err != nil { - return errorsmod.Wrap(err, "iterator failed to close during migration") - } - - // Store the updated TickLiquidity - for _, v := range ticksToUpdate { - store.Set(v.key, v.val) - } - - ctx.Logger().Info("Finished migrating TickLiquidity Prices...") - - return nil -} - -func migrateInactiveTranchePrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { - // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore - ctx.Logger().Info("Migrating InactiveLimitOrderTranche Prices...") - - // Iterate through all InactiveTranches - store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.InactiveLimitOrderTrancheKeyPrefix)) - iterator := storetypes.KVStorePrefixIterator(store, []byte{}) - ticksToUpdate := make([]migrationUpdate, 0) - - for ; iterator.Valid(); iterator.Next() { - var tranche types.LimitOrderTranche - cdc.MustUnmarshal(iterator.Value(), &tranche) - // Recalculate price - tranche.PriceTakerToMaker = types.MustCalcPrice(tranche.Key.TickIndexTakerToMaker) - - bz := cdc.MustMarshal(&tranche) - ticksToUpdate = append(ticksToUpdate, migrationUpdate{key: iterator.Key(), val: bz}) - } - - err := iterator.Close() - if err != nil { - return errorsmod.Wrap(err, "iterator failed to close during migration") - } - - // Store the updated InactiveTranches - for _, v := range ticksToUpdate { - store.Set(v.key, v.val) - } - - ctx.Logger().Info("Finished migrating InactiveLimitOrderTranche Prices...") - - return nil -} diff --git a/x/dex/migrations/v3/store_test.go b/x/dex/migrations/v3/store_test.go index 5f9e4a7ba..7dc44dc37 100644 --- a/x/dex/migrations/v3/store_test.go +++ b/x/dex/migrations/v3/store_test.go @@ -117,56 +117,3 @@ func (suite *V3DexMigrationTestSuite) TestLimitOrderExpirationUpgrade() { allExp := app.DexKeeper.GetAllLimitOrderExpiration(ctx) suite.Require().Equal(len(lOExpirations), len(allExp)) } - -func (suite *V3DexMigrationTestSuite) TestPriceUpdates() { - var ( - app = suite.GetNeutronZoneApp(suite.ChainA) - storeKey = app.GetKey(types.StoreKey) - ctx = suite.ChainA.GetContext() - cdc = app.AppCodec() - ) - - // Write tranche with incorrect price - trancheKey := &types.LimitOrderTrancheKey{ - TradePairId: types.MustNewTradePairID("TokenA", "TokenB"), - TickIndexTakerToMaker: -50, - TrancheKey: "123", - } - tranche := &types.LimitOrderTranche{ - Key: trancheKey, - PriceTakerToMaker: math.ZeroPrecDec(), - } - app.DexKeeper.SetLimitOrderTranche(ctx, tranche) - - // also create inactive tranche - app.DexKeeper.SetInactiveLimitOrderTranche(ctx, tranche) - - // Write poolReserves with incorrect prices - poolKey := &types.PoolReservesKey{ - TradePairId: types.MustNewTradePairID("TokenA", "TokenB"), - TickIndexTakerToMaker: 60000, - Fee: 1, - } - poolReserves := &types.PoolReserves{ - Key: poolKey, - PriceTakerToMaker: math.ZeroPrecDec(), - PriceOppositeTakerToMaker: math.ZeroPrecDec(), - } - app.DexKeeper.SetPoolReserves(ctx, poolReserves) - - // Run migration - suite.NoError(v3.MigrateStore(ctx, cdc, storeKey)) - - // Check LimitOrderTranche has correct price - newTranche := app.DexKeeper.GetLimitOrderTranche(ctx, trancheKey) - suite.True(newTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815"))) - - // check InactiveLimitOrderTranche has correct price - inactiveTranche, _ := app.DexKeeper.GetInactiveLimitOrderTranche(ctx, trancheKey) - suite.True(inactiveTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815"))) - - // Check PoolReserves has the correct prices - newPool, _ := app.DexKeeper.GetPoolReserves(ctx, poolKey) - suite.True(newPool.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("0.002479495864288162666675923"))) - suite.True(newPool.PriceOppositeTakerToMaker.Equal(math.MustNewPrecDecFromStr("403.227141612124702272520931931"))) -} diff --git a/x/dex/migrations/v4/store.go b/x/dex/migrations/v4/store.go new file mode 100644 index 000000000..89766ff25 --- /dev/null +++ b/x/dex/migrations/v4/store.go @@ -0,0 +1,112 @@ +package v4 + +import ( + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/neutron-org/neutron/v4/x/dex/types" +) + +// MigrateStore performs in-place store migrations. +// The migration adds new dex params -- GoodTilPurgeAllowance & MaxJITsPerBlock// for handling JIT orders. +func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + if err := migrateTickLiquidityPrices(ctx, cdc, storeKey); err != nil { + return err + } + + if err := migrateInactiveTranchePrices(ctx, cdc, storeKey); err != nil { + return err + } + + return nil +} + +type migrationUpdate struct { + key []byte + val []byte +} + +func migrateTickLiquidityPrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore + ctx.Logger().Info("Migrating TickLiquidity Prices...") + + // Iterate through all tickLiquidity + store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.TickLiquidityKeyPrefix)) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + ticksToUpdate := make([]migrationUpdate, 0) + + for ; iterator.Valid(); iterator.Next() { + var tickLiq types.TickLiquidity + var updatedTickLiq types.TickLiquidity + cdc.MustUnmarshal(iterator.Value(), &tickLiq) + // Recalculate all prices + switch liquidity := tickLiq.Liquidity.(type) { + case *types.TickLiquidity_LimitOrderTranche: + liquidity.LimitOrderTranche.PriceTakerToMaker = types.MustCalcPrice(liquidity.LimitOrderTranche.Key.TickIndexTakerToMaker) + updatedTickLiq = types.TickLiquidity{Liquidity: liquidity} + case *types.TickLiquidity_PoolReserves: + poolReservesKey := liquidity.PoolReserves.Key + liquidity.PoolReserves.PriceTakerToMaker = types.MustCalcPrice(poolReservesKey.TickIndexTakerToMaker) + liquidity.PoolReserves.PriceOppositeTakerToMaker = poolReservesKey.Counterpart().MustPriceTakerToMaker() + updatedTickLiq = types.TickLiquidity{Liquidity: liquidity} + + default: + panic("Tick does not contain valid liqudityType") + } + + bz := cdc.MustMarshal(&updatedTickLiq) + ticksToUpdate = append(ticksToUpdate, migrationUpdate{key: iterator.Key(), val: bz}) + + } + + err := iterator.Close() + if err != nil { + return errorsmod.Wrap(err, "iterator failed to close during migration") + } + + // Store the updated TickLiquidity + for _, v := range ticksToUpdate { + store.Set(v.key, v.val) + } + + ctx.Logger().Info("Finished migrating TickLiquidity Prices...") + + return nil +} + +func migrateInactiveTranchePrices(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + // Due to change in precision of PrecDec between v2 and v3 we need to recompute all PrecDecs in the kvstore + ctx.Logger().Info("Migrating InactiveLimitOrderTranche Prices...") + + // Iterate through all InactiveTranches + store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(types.InactiveLimitOrderTrancheKeyPrefix)) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + ticksToUpdate := make([]migrationUpdate, 0) + + for ; iterator.Valid(); iterator.Next() { + var tranche types.LimitOrderTranche + cdc.MustUnmarshal(iterator.Value(), &tranche) + // Recalculate price + tranche.PriceTakerToMaker = types.MustCalcPrice(tranche.Key.TickIndexTakerToMaker) + + bz := cdc.MustMarshal(&tranche) + ticksToUpdate = append(ticksToUpdate, migrationUpdate{key: iterator.Key(), val: bz}) + } + + err := iterator.Close() + if err != nil { + return errorsmod.Wrap(err, "iterator failed to close during migration") + } + + // Store the updated InactiveTranches + for _, v := range ticksToUpdate { + store.Set(v.key, v.val) + } + + ctx.Logger().Info("Finished migrating InactiveLimitOrderTranche Prices...") + + return nil +} diff --git a/x/dex/migrations/v4/store_test.go b/x/dex/migrations/v4/store_test.go new file mode 100644 index 000000000..10aa1bded --- /dev/null +++ b/x/dex/migrations/v4/store_test.go @@ -0,0 +1,73 @@ +package v4_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/neutron-org/neutron/v4/testutil" + "github.com/neutron-org/neutron/v4/utils/math" + v4 "github.com/neutron-org/neutron/v4/x/dex/migrations/v4" + "github.com/neutron-org/neutron/v4/x/dex/types" +) + +type V4DexMigrationTestSuite struct { + testutil.IBCConnectionTestSuite +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(V4DexMigrationTestSuite)) +} + +func (suite *V4DexMigrationTestSuite) TestPriceUpdates() { + var ( + app = suite.GetNeutronZoneApp(suite.ChainA) + storeKey = app.GetKey(types.StoreKey) + ctx = suite.ChainA.GetContext() + cdc = app.AppCodec() + ) + + // Write tranche with incorrect price + trancheKey := &types.LimitOrderTrancheKey{ + TradePairId: types.MustNewTradePairID("TokenA", "TokenB"), + TickIndexTakerToMaker: -50, + TrancheKey: "123", + } + tranche := &types.LimitOrderTranche{ + Key: trancheKey, + PriceTakerToMaker: math.ZeroPrecDec(), + } + app.DexKeeper.SetLimitOrderTranche(ctx, tranche) + + // also create inactive tranche + app.DexKeeper.SetInactiveLimitOrderTranche(ctx, tranche) + + // Write poolReserves with incorrect prices + poolKey := &types.PoolReservesKey{ + TradePairId: types.MustNewTradePairID("TokenA", "TokenB"), + TickIndexTakerToMaker: 60000, + Fee: 1, + } + poolReserves := &types.PoolReserves{ + Key: poolKey, + PriceTakerToMaker: math.ZeroPrecDec(), + PriceOppositeTakerToMaker: math.ZeroPrecDec(), + } + app.DexKeeper.SetPoolReserves(ctx, poolReserves) + + // Run migration + suite.NoError(v4.MigrateStore(ctx, cdc, storeKey)) + + // Check LimitOrderTranche has correct price + newTranche := app.DexKeeper.GetLimitOrderTranche(ctx, trancheKey) + suite.True(newTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815"))) + + // check InactiveLimitOrderTranche has correct price + inactiveTranche, _ := app.DexKeeper.GetInactiveLimitOrderTranche(ctx, trancheKey) + suite.True(inactiveTranche.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("1.005012269623051203500693815"))) + + // Check PoolReserves has the correct prices + newPool, _ := app.DexKeeper.GetPoolReserves(ctx, poolKey) + suite.True(newPool.PriceTakerToMaker.Equal(math.MustNewPrecDecFromStr("0.002479495864288162666675923"))) + suite.True(newPool.PriceOppositeTakerToMaker.Equal(math.MustNewPrecDecFromStr("403.227141612124702272520931931"))) +} diff --git a/x/dex/module.go b/x/dex/module.go index 3e1e31136..f2fa6cb52 100644 --- a/x/dex/module.go +++ b/x/dex/module.go @@ -158,6 +158,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3); err != nil { panic(fmt.Sprintf("failed to migrate x/dex from version 2 to 3: %v", err)) } + + if err := cfg.RegisterMigration(types.ModuleName, 3, m.Migrate3to4); err != nil { + panic(fmt.Sprintf("failed to migrate x/dex from version 3 to 4: %v", err)) + } } // RegisterInvariants registers the capability module's invariants. From c9d55c5dc6c0a1691b0ca8c00ec2baadf655b29b Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Fri, 21 Jun 2024 13:38:14 +0300 Subject: [PATCH 5/5] fix comment --- x/dex/migrations/v4/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/dex/migrations/v4/store.go b/x/dex/migrations/v4/store.go index 89766ff25..61dd9a922 100644 --- a/x/dex/migrations/v4/store.go +++ b/x/dex/migrations/v4/store.go @@ -11,7 +11,7 @@ import ( ) // MigrateStore performs in-place store migrations. -// The migration adds new dex params -- GoodTilPurgeAllowance & MaxJITsPerBlock// for handling JIT orders. +// Due to change in precision of PrecDec between v3 and v4 we need to recompute all PrecDecs in the kvstore func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { if err := migrateTickLiquidityPrices(ctx, cdc, storeKey); err != nil { return err