From 0766ef99411aa058a2b8b33e0017fcecee72a572 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Fri, 14 Jun 2024 18:39:53 -0400 Subject: [PATCH] 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) +}