From c52390ecbf4e4ba0b79f07f8035c89b301c62e36 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Thu, 23 Jan 2025 23:41:31 -0700 Subject: [PATCH 1/4] Add SwapMetadata to TickUpdates --- testutil/apptesting/events.go | 12 ++++++++++ x/dex/keeper/limit_order_tranche.go | 4 ++-- x/dex/keeper/liquidity.go | 13 +++++++---- x/dex/keeper/liquidity_test.go | 16 +++++++++++++ x/dex/keeper/pool.go | 19 +++++++++++++--- x/dex/keeper/pool_reserves.go | 4 ++-- x/dex/types/events.go | 35 +++++++++++++++++++++++++---- 7 files changed, 88 insertions(+), 15 deletions(-) diff --git a/testutil/apptesting/events.go b/testutil/apptesting/events.go index f06410fc2..0df78a15d 100644 --- a/testutil/apptesting/events.go +++ b/testutil/apptesting/events.go @@ -65,6 +65,18 @@ func (s *KeeperTestHelper) AssertNEventValuesEmitted(eventValue string, nEvents s.Equal(nEvents, emissions, "Expected %v events, got %v", nEvents, emissions) } +func (s *KeeperTestHelper) GetAllMatchingEvents(eventValue string) (events []sdk.Event) { + allEvents := s.Ctx.EventManager().Events() + for _, event := range allEvents { + for _, attr := range event.Attributes { + if attr.Value == eventValue { + events = append(events, event) + } + } + } + return events +} + func (s *KeeperTestHelper) AssertEventValueNotEmitted(eventValue, message string) { allEvents := s.Ctx.EventManager().Events() if len(allEvents) != 0 { diff --git a/x/dex/keeper/limit_order_tranche.go b/x/dex/keeper/limit_order_tranche.go index 2c0dcae57..eeffcfd8a 100644 --- a/x/dex/keeper/limit_order_tranche.go +++ b/x/dex/keeper/limit_order_tranche.go @@ -56,7 +56,7 @@ func (k Keeper) FindLimitOrderTranche( // UpdateTranche handles the logic for all updates to active LimitOrderTranches in the KV Store. // NOTE: This method should always be called even if not all logic branches are applicable. // It avoids unnecessary repetition of logic and provides a single place to attach update event handlers. -func (k Keeper) UpdateTranche(ctx sdk.Context, tranche *types.LimitOrderTranche) { +func (k Keeper) UpdateTranche(ctx sdk.Context, tranche *types.LimitOrderTranche, swapMetadata ...types.SwapMetadata) { switch { // Tranche still has TokenIn (ReservesMakerDenom) ==> Just save the update @@ -77,7 +77,7 @@ func (k Keeper) UpdateTranche(ctx sdk.Context, tranche *types.LimitOrderTranche) ctx.EventManager().EmitEvents(types.GetEventsDecTotalOrders(tranche.Key.TradePairId)) } - ctx.EventManager().EmitEvent(types.CreateTickUpdateLimitOrderTranche(tranche)) + ctx.EventManager().EmitEvent(types.CreateTickUpdateLimitOrderTranche(tranche, swapMetadata...)) } func (k Keeper) SetLimitOrderTranche(ctx sdk.Context, tranche *types.LimitOrderTranche) { diff --git a/x/dex/keeper/liquidity.go b/x/dex/keeper/liquidity.go index 87de37680..a0d74497d 100644 --- a/x/dex/keeper/liquidity.go +++ b/x/dex/keeper/liquidity.go @@ -43,7 +43,12 @@ func (k Keeper) Swap( inAmount, outAmount := liq.Swap(remainingTakerDenom, remainingMakerDenom) - k.SaveLiquidity(ctx, liq) + swapMetadata := types.SwapMetadata{ + AmountIn: inAmount, + AmountOut: outAmount, + TokenIn: tradePairID.TakerDenom, + } + k.SaveLiquidity(ctx, liq, swapMetadata) remainingTakerDenom = remainingTakerDenom.Sub(inAmount) totalMakerDenom = totalMakerDenom.Add(outAmount) @@ -107,14 +112,14 @@ func (k Keeper) SwapWithCache( return totalIn, totalOut, orderFilled, err } -func (k Keeper) SaveLiquidity(sdkCtx sdk.Context, liquidityI types.Liquidity) { +func (k Keeper) SaveLiquidity(sdkCtx sdk.Context, liquidityI types.Liquidity, swapMetadata ...types.SwapMetadata) { switch liquidity := liquidityI.(type) { case *types.LimitOrderTranche: // If there is still makerReserves we will save the tranche as active, if not, we will move it to inactive - k.UpdateTranche(sdkCtx, liquidity) + k.UpdateTranche(sdkCtx, liquidity, swapMetadata...) case *types.PoolLiquidity: // Save updated to both sides of the pool. If one of the sides is empty it will be deleted - k.UpdatePool(sdkCtx, liquidity.Pool) + k.UpdatePool(sdkCtx, liquidity.Pool, swapMetadata...) default: panic("Invalid liquidity type") } diff --git a/x/dex/keeper/liquidity_test.go b/x/dex/keeper/liquidity_test.go index ce08905ba..0ec64b19e 100644 --- a/x/dex/keeper/liquidity_test.go +++ b/x/dex/keeper/liquidity_test.go @@ -547,6 +547,22 @@ func (s *DexTestSuite) TestSwapExhaustsLOAndLP() { // There should be total of 6 tick updates // (limitOrder, 2x deposit, 2x swap LP, swap LO) s.AssertNEventValuesEmitted(types.TickUpdateEventKey, 6) + + tickUpdates := s.GetAllMatchingEvents(types.TickUpdateEventKey) + + // LimitOrder TickUpdate has correct SwapMetadatrra + loTickUpdate := tickUpdates[3] + loSwapIn, _ := loTickUpdate.GetAttribute(types.AttributeSwapAmountIn) + loSwapOut, _ := loTickUpdate.GetAttribute(types.AttributeSwapAmountOut) + s.Equal("10000000", loSwapIn.Value) + s.Equal("10000000", loSwapOut.Value) + + // LP TickUpdate has correct SwapMetadatrra + lpTickUpdate := tickUpdates[5] + lpSwapIn, _ := lpTickUpdate.GetAttribute(types.AttributeSwapAmountIn) + lpSwapOut, _ := lpTickUpdate.GetAttribute(types.AttributeSwapAmountOut) + s.Equal("9000000", lpSwapIn.Value) + s.Equal("8999100", lpSwapOut.Value) } // Test helpers /////////////////////////////////////////////////////////////// diff --git a/x/dex/keeper/pool.go b/x/dex/keeper/pool.go index f4c13f6b2..6100297aa 100644 --- a/x/dex/keeper/pool.go +++ b/x/dex/keeper/pool.go @@ -137,9 +137,22 @@ func (k Keeper) GetPoolIDByParams( // UpdatePool handles the logic for all updates to Pools in the KV Store. // It provides a convenient way to save both sides of the pool reserves. -func (k Keeper) UpdatePool(ctx sdk.Context, pool *types.Pool) { - k.UpdatePoolReserves(ctx, pool.LowerTick0) - k.UpdatePoolReserves(ctx, pool.UpperTick1) +func (k Keeper) UpdatePool(ctx sdk.Context, pool *types.Pool, swapMetadata ...types.SwapMetadata) { + if len(swapMetadata) == 1 { + //Only pass the swapMetadata to the poolReserves that is being swapped against + if swapMetadata[0].TokenIn == pool.LowerTick0.Key.TradePairId.TakerDenom { + k.UpdatePoolReserves(ctx, pool.LowerTick0, swapMetadata...) + k.UpdatePoolReserves(ctx, pool.UpperTick1) + } else { + k.UpdatePoolReserves(ctx, pool.LowerTick0) + k.UpdatePoolReserves(ctx, pool.UpperTick1, swapMetadata...) + } + } else { + k.UpdatePoolReserves(ctx, pool.LowerTick0) + k.UpdatePoolReserves(ctx, pool.UpperTick1) + + } + } // GetPoolCount get the total number of pools diff --git a/x/dex/keeper/pool_reserves.go b/x/dex/keeper/pool_reserves.go index df870e21d..79af46466 100644 --- a/x/dex/keeper/pool_reserves.go +++ b/x/dex/keeper/pool_reserves.go @@ -44,7 +44,7 @@ func (k Keeper) RemovePoolReserves(ctx sdk.Context, poolReservesID *types.PoolRe // UpdatePoolReserves handles the logic for all updates to PoolReserves in the KV Store. // NOTE: This method should always be called even if not all logic branches are applicable. // It avoids unnecessary repetition of logic and provides a single place to attach update event handlers. -func (k Keeper) UpdatePoolReserves(ctx sdk.Context, reserves *types.PoolReserves) { +func (k Keeper) UpdatePoolReserves(ctx sdk.Context, reserves *types.PoolReserves, swapMetadata ...types.SwapMetadata) { if reserves.HasToken() { // The pool still has ReservesMakerDenom; save it as is k.SetPoolReserves(ctx, reserves) @@ -57,5 +57,5 @@ func (k Keeper) UpdatePoolReserves(ctx sdk.Context, reserves *types.PoolReserves // TODO: This will create a bit of extra noise since UpdatePoolReserves is called for both sides of the pool, // but not in some cases only one side has been updated // This should be solved upstream by better tracking of dirty ticks - ctx.EventManager().EmitEvent(types.CreateTickUpdatePoolReserves(*reserves)) + ctx.EventManager().EmitEvent(types.CreateTickUpdatePoolReserves(*reserves, swapMetadata...)) } diff --git a/x/dex/types/events.go b/x/dex/types/events.go index 4f96e826b..72455a62e 100644 --- a/x/dex/types/events.go +++ b/x/dex/types/events.go @@ -263,6 +263,21 @@ func CancelLimitOrderEvent( return sdk.NewEvent(sdk.EventTypeMessage, attrs...) } +type SwapMetadata struct { + AmountIn math.Int + AmountOut math.Int + TokenIn string +} + +func addSwapMetadata(event sdk.Event, swapMetadata SwapMetadata) sdk.Event { + swapAttrs := []sdk.Attribute{ + sdk.NewAttribute(AttributeSwapAmountIn, swapMetadata.AmountIn.String()), + sdk.NewAttribute(AttributeSwapAmountOut, swapMetadata.AmountOut.String()), + } + + return event.AppendAttributes(swapAttrs...) +} + func TickUpdateEvent( token0 string, token1 string, @@ -285,10 +300,10 @@ func TickUpdateEvent( return sdk.NewEvent(EventTypeTickUpdate, attrs...) } -func CreateTickUpdatePoolReserves(tick PoolReserves) sdk.Event { +func CreateTickUpdatePoolReserves(tick PoolReserves, swapMetadata ...SwapMetadata) sdk.Event { tradePairID := tick.Key.TradePairId pairID := tradePairID.MustPairID() - return TickUpdateEvent( + tickUpdate := TickUpdateEvent( pairID.Token0, pairID.Token1, tradePairID.MakerDenom, @@ -296,12 +311,17 @@ func CreateTickUpdatePoolReserves(tick PoolReserves) sdk.Event { tick.ReservesMakerDenom, sdk.NewAttribute(AttributeFee, strconv.FormatUint(tick.Key.Fee, 10)), ) + if len(swapMetadata) == 1 { + tickUpdate = addSwapMetadata(tickUpdate, swapMetadata[0]) + } + + return tickUpdate } -func CreateTickUpdateLimitOrderTranche(tranche *LimitOrderTranche) sdk.Event { +func CreateTickUpdateLimitOrderTranche(tranche *LimitOrderTranche, swapMetadata ...SwapMetadata) sdk.Event { tradePairID := tranche.Key.TradePairId pairID := tradePairID.MustPairID() - return TickUpdateEvent( + tickUpdate := TickUpdateEvent( pairID.Token0, pairID.Token1, tradePairID.MakerDenom, @@ -309,6 +329,13 @@ func CreateTickUpdateLimitOrderTranche(tranche *LimitOrderTranche) sdk.Event { tranche.ReservesMakerDenom, sdk.NewAttribute(AttributeTrancheKey, tranche.Key.TrancheKey), ) + + if len(swapMetadata) == 1 { + tickUpdate = addSwapMetadata(tickUpdate, swapMetadata[0]) + + } + + return tickUpdate } func CreateTickUpdateLimitOrderTranchePurge(tranche *LimitOrderTranche) sdk.Event { From a3b55f31bdb39c4c3842d50958c3cba51f8fc5ac Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Thu, 23 Jan 2025 23:47:54 -0700 Subject: [PATCH 2/4] fmt --- x/dex/keeper/pool.go | 3 +-- x/dex/types/events.go | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x/dex/keeper/pool.go b/x/dex/keeper/pool.go index 6100297aa..2d16ea9ec 100644 --- a/x/dex/keeper/pool.go +++ b/x/dex/keeper/pool.go @@ -139,7 +139,7 @@ func (k Keeper) GetPoolIDByParams( // It provides a convenient way to save both sides of the pool reserves. func (k Keeper) UpdatePool(ctx sdk.Context, pool *types.Pool, swapMetadata ...types.SwapMetadata) { if len(swapMetadata) == 1 { - //Only pass the swapMetadata to the poolReserves that is being swapped against + // Only pass the swapMetadata to the poolReserves that is being swapped against if swapMetadata[0].TokenIn == pool.LowerTick0.Key.TradePairId.TakerDenom { k.UpdatePoolReserves(ctx, pool.LowerTick0, swapMetadata...) k.UpdatePoolReserves(ctx, pool.UpperTick1) @@ -152,7 +152,6 @@ func (k Keeper) UpdatePool(ctx sdk.Context, pool *types.Pool, swapMetadata ...ty k.UpdatePoolReserves(ctx, pool.UpperTick1) } - } // GetPoolCount get the total number of pools diff --git a/x/dex/types/events.go b/x/dex/types/events.go index 72455a62e..c856b7fd3 100644 --- a/x/dex/types/events.go +++ b/x/dex/types/events.go @@ -332,7 +332,6 @@ func CreateTickUpdateLimitOrderTranche(tranche *LimitOrderTranche, swapMetadata if len(swapMetadata) == 1 { tickUpdate = addSwapMetadata(tickUpdate, swapMetadata[0]) - } return tickUpdate From 1a062b723a39c86eab37f8f46d0b29407f5ae719 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Fri, 24 Jan 2025 23:15:29 -0700 Subject: [PATCH 3/4] fix typo + extra test case --- x/dex/keeper/liquidity_test.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/x/dex/keeper/liquidity_test.go b/x/dex/keeper/liquidity_test.go index 0ec64b19e..9d8f47f09 100644 --- a/x/dex/keeper/liquidity_test.go +++ b/x/dex/keeper/liquidity_test.go @@ -557,12 +557,20 @@ func (s *DexTestSuite) TestSwapExhaustsLOAndLP() { s.Equal("10000000", loSwapIn.Value) s.Equal("10000000", loSwapOut.Value) - // LP TickUpdate has correct SwapMetadatrra + // LP TickUpdate has correct SwapMetadata lpTickUpdate := tickUpdates[5] lpSwapIn, _ := lpTickUpdate.GetAttribute(types.AttributeSwapAmountIn) lpSwapOut, _ := lpTickUpdate.GetAttribute(types.AttributeSwapAmountOut) s.Equal("9000000", lpSwapIn.Value) s.Equal("8999100", lpSwapOut.Value) + + // opposite LP TickUpdate has no SwapMetadata + lpTickUpdateOppositeTick := tickUpdates[4] + _, found := lpTickUpdateOppositeTick.GetAttribute(types.AttributeSwapAmountIn) + s.False(found) + _, found = lpTickUpdateOppositeTick.GetAttribute(types.AttributeSwapAmountOut) + s.False(found) + } // Test helpers /////////////////////////////////////////////////////////////// From 58539fc2171f414a854491dcd4f9f16eaa926feb Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Mon, 27 Jan 2025 16:10:14 -0700 Subject: [PATCH 4/4] fmt --- x/dex/keeper/liquidity_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/dex/keeper/liquidity_test.go b/x/dex/keeper/liquidity_test.go index 9d8f47f09..7f3348f19 100644 --- a/x/dex/keeper/liquidity_test.go +++ b/x/dex/keeper/liquidity_test.go @@ -570,7 +570,6 @@ func (s *DexTestSuite) TestSwapExhaustsLOAndLP() { s.False(found) _, found = lpTickUpdateOppositeTick.GetAttribute(types.AttributeSwapAmountOut) s.False(found) - } // Test helpers ///////////////////////////////////////////////////////////////