From 18937bc60de7ae08185c61a483edc16b211b50be Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 2 Aug 2022 15:16:09 -0700 Subject: [PATCH] test(x/gamm): add liquidity event tests (manual backport #2141) (#2275) * test(gamm): add liquidity events * Apply suggestions from code review * Update x/gamm/keeper/msg_server_test.go Co-authored-by: Matt, Park <45252226+mattverse@users.noreply.github.com> Co-authored-by: Matt, Park <45252226+mattverse@users.noreply.github.com> Co-authored-by: Matt, Park <45252226+mattverse@users.noreply.github.com> --- x/gamm/keeper/internal/events/emit_test.go | 54 +++++++++++++++++ x/gamm/keeper/msg_server.go | 4 -- x/gamm/keeper/msg_server_test.go | 70 +++++++++++++++++++++- x/gamm/keeper/pool_service_test.go | 5 +- x/gamm/spec/README.md | 18 +++++- 5 files changed, 144 insertions(+), 7 deletions(-) diff --git a/x/gamm/keeper/internal/events/emit_test.go b/x/gamm/keeper/internal/events/emit_test.go index 024763b91a1..3da5f74f206 100644 --- a/x/gamm/keeper/internal/events/emit_test.go +++ b/x/gamm/keeper/internal/events/emit_test.go @@ -86,3 +86,57 @@ func (suite *GammEventsTestSuite) TestEmitSwapEvent() { }) } } + +func (suite *GammEventsTestSuite) TestEmitAddLiquidityEvent() { + testcases := map[string]struct { + ctx sdk.Context + testAccountAddr sdk.AccAddress + poolId uint64 + tokensIn sdk.Coins + }{ + "basic valid": { + ctx: suite.CreateTestContext(), + testAccountAddr: sdk.AccAddress([]byte(addressString)), + poolId: 1, + tokensIn: sdk.NewCoins(sdk.NewCoin(testDenomA, sdk.NewInt(1234))), + }, + "context with no event manager": { + ctx: sdk.Context{}, + }, + "valid with multiple tokens in": { + ctx: suite.CreateTestContext(), + testAccountAddr: sdk.AccAddress([]byte(addressString)), + poolId: 200, + tokensIn: sdk.NewCoins(sdk.NewCoin(testDenomA, sdk.NewInt(12)), sdk.NewCoin(testDenomB, sdk.NewInt(99))), + }, + } + + for name, tc := range testcases { + suite.Run(name, func() { + expectedEvents := sdk.Events{ + sdk.NewEvent( + types.TypeEvtPoolJoined, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + sdk.NewAttribute(sdk.AttributeKeySender, tc.testAccountAddr.String()), + sdk.NewAttribute(types.AttributeKeyPoolId, strconv.FormatUint(tc.poolId, 10)), + sdk.NewAttribute(types.AttributeKeyTokensIn, tc.tokensIn.String()), + ), + } + + hasNoEventManager := tc.ctx.EventManager() == nil + + // System under test. + events.EmitAddLiquidityEvent(tc.ctx, tc.testAccountAddr, tc.poolId, tc.tokensIn) + + // Assertions + if hasNoEventManager { + // If there is no event manager on context, this is a no-op. + return + } + + eventManager := tc.ctx.EventManager() + actualEvents := eventManager.Events() + suite.Equal(expectedEvents, actualEvents) + }) + } +} diff --git a/x/gamm/keeper/msg_server.go b/x/gamm/keeper/msg_server.go index 01168683208..ae72727a876 100644 --- a/x/gamm/keeper/msg_server.go +++ b/x/gamm/keeper/msg_server.go @@ -114,10 +114,6 @@ func (server msgServer) JoinPool(goCtx context.Context, msg *types.MsgJoinPool) } ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.TypeEvtPoolJoined, - sdk.NewAttribute(types.AttributeKeyPoolId, strconv.FormatUint(msg.PoolId, 10)), - ), sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), diff --git a/x/gamm/keeper/msg_server_test.go b/x/gamm/keeper/msg_server_test.go index a52251162e2..32296549b6b 100644 --- a/x/gamm/keeper/msg_server_test.go +++ b/x/gamm/keeper/msg_server_test.go @@ -213,6 +213,74 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() { } } +// TestJoinPool_Events tests that events are correctly emitted +// when calling JoinPool. +func (suite *KeeperTestSuite) TestJoinPool_Events() { + const ( + // Max positive int64. + tokenInMaxAmount = int64(^uint64(0) >> 1) + shareOut = 110 + ) + + testcases := map[string]struct { + poolId uint64 + shareOutAmount sdk.Int + tokenInMaxs sdk.Coins + expectError bool + expectedAddLiquidityEvents int + expectedMessageEvents int + }{ + "successful join": { + poolId: 1, + shareOutAmount: sdk.NewInt(shareOut), + tokenInMaxs: sdk.NewCoins( + sdk.NewCoin("foo", sdk.NewInt(tokenInMaxAmount)), + sdk.NewCoin("bar", sdk.NewInt(tokenInMaxAmount)), + sdk.NewCoin("baz", sdk.NewInt(tokenInMaxAmount)), + ), + expectedAddLiquidityEvents: 1, + expectedMessageEvents: 3, // 1 gamm + 2 tendermint. + }, + "tokenInMaxs do not match all tokens in pool - invalid join": { + poolId: 1, + shareOutAmount: sdk.NewInt(shareOut), + tokenInMaxs: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(tokenInMaxAmount))), + expectError: true, + }, + } + + for name, tc := range testcases { + suite.Run(name, func() { + suite.Setup() + ctx := suite.Ctx + + suite.PrepareBalancerPool() + suite.PrepareBalancerPool() + + msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper) + + // Reset event counts to 0 by creating a new manager. + ctx = ctx.WithEventManager(sdk.NewEventManager()) + suite.Require().Equal(0, len(ctx.EventManager().Events())) + + response, err := msgServer.JoinPool(sdk.WrapSDKContext(ctx), &types.MsgJoinPool{ + Sender: suite.TestAccs[0].String(), + PoolId: tc.poolId, + ShareOutAmount: tc.shareOutAmount, + TokenInMaxs: tc.tokenInMaxs, + }) + + if !tc.expectError { + suite.Require().NoError(err) + suite.Require().NotNil(response) + } + + assertEventEmitted(suite, ctx, types.TypeEvtPoolJoined, tc.expectedAddLiquidityEvents) + assertEventEmitted(suite, ctx, sdk.EventTypeMessage, tc.expectedMessageEvents) + }) + } +} + func assertEventEmitted(suite *KeeperTestSuite, ctx sdk.Context, eventTypeExpected string, numEventsExpected int) { allEvents := ctx.EventManager().Events() // filter out other events @@ -222,5 +290,5 @@ func assertEventEmitted(suite *KeeperTestSuite, ctx sdk.Context, eventTypeExpect actualEvents = append(actualEvents, event) } } - suite.Equal(numEventsExpected, len(actualEvents)) + suite.Require().Equal(numEventsExpected, len(actualEvents)) } diff --git a/x/gamm/keeper/pool_service_test.go b/x/gamm/keeper/pool_service_test.go index bf869075e46..80fb27a8ace 100644 --- a/x/gamm/keeper/pool_service_test.go +++ b/x/gamm/keeper/pool_service_test.go @@ -321,6 +321,9 @@ func (suite *KeeperTestSuite) TestJoinPoolNoSwap() { for _, test := range tests { suite.SetupTest() + ctx := suite.Ctx + keeper := suite.App.GAMMKeeper + // Mint some assets to the accounts. for _, acc := range suite.TestAccs { suite.FundAcc(acc, defaultAcctFunds) @@ -331,7 +334,7 @@ func (suite *KeeperTestSuite) TestJoinPoolNoSwap() { SwapFee: sdk.NewDecWithPrec(1, 2), ExitFee: sdk.NewDecWithPrec(1, 2), }, defaultPoolAssets, defaultFutureGovernor) - poolId, err := suite.App.GAMMKeeper.CreatePool(suite.Ctx, msg) + poolId, err := keeper.CreatePool(ctx, msg) suite.Require().NoError(err) test.fn(poolId) diff --git a/x/gamm/spec/README.md b/x/gamm/spec/README.md index a4924baf6ba..60fc1ac0430 100644 --- a/x/gamm/spec/README.md +++ b/x/gamm/spec/README.md @@ -951,7 +951,7 @@ osmosisd tx gamm swap-exact-amount-out 1000000ibc/27394FB092D2ECCD56123C74F36E4C ## Events -There are 4 types of events that exist in GAMM: +There are 5 types of events that exist in GAMM: * `sdk.EventTypeMessage` - "message" * `types.TypeEvtPoolJoined` - "pool_joined" @@ -965,6 +965,22 @@ This event is emitted in the message server when any of the gamm messages finish TBD +### `types.TypeEvtPoolJoined` + +This event is emitted after one of `JoinPool` or `JoinPoolNoSwap` complete joining +the requested pool successfully. + +It consists of the following attributes: + +* `sdk.AttributeKeyModule` - "module" + * The value is the module's name - "gamm". +* `sdk.AttributeKeySender` + * The value is the address of the sender who created the swap message. +* `types.AttributeKeyPoolId` + * The value is the pool id of the pool where swap occurs. +* `types.AttributeKeyTokensIn` + * The value is the string representation of the tokens being swapped in. + ### `types.TypeEvtPoolExited` TBD