Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(x/gamm): remove liquidity events #2186

Merged
merged 11 commits into from
Aug 3, 2022
17 changes: 17 additions & 0 deletions app/apptesting/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package apptesting

import sdk "github.com/cosmos/cosmos-sdk/types"

// AssertEventEmitted asserts that ctx's event manager has emitted the given number of events
// of the given type.
func (s *KeeperTestHelper) AssertEventEmitted(ctx sdk.Context, eventTypeExpected string, numEventsExpected int) {
allEvents := ctx.EventManager().Events()
// filter out other events
actualEvents := make([]sdk.Event, 0)
for _, event := range allEvents {
if event.Type == eventTypeExpected {
actualEvents = append(actualEvents, event)
}
}
s.Equal(numEventsExpected, len(actualEvents))
}
54 changes: 54 additions & 0 deletions x/gamm/keeper/internal/events/emit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,57 @@ func (suite *GammEventsTestSuite) TestEmitAddLiquidityEvent() {
})
}
}

func (suite *GammEventsTestSuite) TestEmitRemoveLiquidityEvent() {
testcases := map[string]struct {
ctx sdk.Context
testAccountAddr sdk.AccAddress
poolId uint64
tokensOut sdk.Coins
}{
"basic valid": {
ctx: suite.CreateTestContext(),
testAccountAddr: sdk.AccAddress([]byte(addressString)),
poolId: 1,
tokensOut: sdk.NewCoins(sdk.NewCoin(testDenomA, sdk.NewInt(1234))),
},
"context with no event manager": {
ctx: sdk.Context{},
},
"valid with multiple tokens in": {
p0mvn marked this conversation as resolved.
Show resolved Hide resolved
ctx: suite.CreateTestContext(),
testAccountAddr: sdk.AccAddress([]byte(addressString)),
poolId: 200,
tokensOut: 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.TypeEvtPoolExited,
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.AttributeKeyTokensOut, tc.tokensOut.String()),
),
}

hasNoEventManager := tc.ctx.EventManager() == nil

// System under test.
events.EmitRemoveLiquidityEvent(tc.ctx, tc.testAccountAddr, tc.poolId, tc.tokensOut)

// 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)
})
}
}
4 changes: 0 additions & 4 deletions x/gamm/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,6 @@ func (server msgServer) ExitPool(goCtx context.Context, msg *types.MsgExitPool)
}

ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.TypeEvtPoolExited,
sdk.NewAttribute(types.AttributeKeyPoolId, strconv.FormatUint(msg.PoolId, 10)),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
Expand Down
104 changes: 84 additions & 20 deletions x/gamm/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (

const (
doesNotExistDenom = "nodenom"
// Max positive int64.
int64Max = int64(^uint64(0) >> 1)
)

func TestMsgServerTestSuite(t *testing.T) {
Expand Down Expand Up @@ -111,8 +113,8 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() {
suite.NotNil(response)
}

assertEventEmitted(suite, ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents)
assertEventEmitted(suite, ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents)
suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
})
}
}
Expand All @@ -121,8 +123,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() {
// when calling SwapExactAmountOut.
func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() {
const (
// Max positive int64.
tokenInMaxAmount = int64(^uint64(0) >> 1)
tokenInMaxAmount = int64Max
tokenOut = 5
)

Expand Down Expand Up @@ -211,8 +212,8 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() {
suite.NotNil(response)
}

assertEventEmitted(suite, ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents)
assertEventEmitted(suite, ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
suite.AssertEventEmitted(ctx, types.TypeEvtTokenSwapped, tc.expectedSwapEvents)
suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
})
}
}
Expand All @@ -221,8 +222,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() {
// when calling JoinPool.
func (suite *KeeperTestSuite) TestJoinPool_Events() {
const (
// Max positive int64.
tokenInMaxAmount = int64(^uint64(0) >> 1)
tokenInMaxAmount = int64Max
shareOut = 110
)

Expand Down Expand Up @@ -258,7 +258,6 @@ func (suite *KeeperTestSuite) TestJoinPool_Events() {
suite.Setup()
ctx := suite.Ctx

suite.PrepareBalancerPool()
suite.PrepareBalancerPool()

msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper)
Expand All @@ -279,20 +278,85 @@ func (suite *KeeperTestSuite) TestJoinPool_Events() {
suite.Require().NotNil(response)
}

assertEventEmitted(suite, ctx, types.TypeEvtPoolJoined, tc.expectedAddLiquidityEvents)
assertEventEmitted(suite, ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
suite.AssertEventEmitted(ctx, types.TypeEvtPoolJoined, tc.expectedAddLiquidityEvents)
suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
})
}
}

func assertEventEmitted(suite *KeeperTestSuite, ctx sdk.Context, eventTypeExpected string, numEventsExpected int) {
allEvents := ctx.EventManager().Events()
// filter out other events
actualEvents := make([]sdk.Event, 0, 1)
for _, event := range allEvents {
if event.Type == eventTypeExpected {
actualEvents = append(actualEvents, event)
}
// TestExitPool_Events tests that events are correctly emitted
// when calling ExitPool.
func (suite *KeeperTestSuite) TestExitPool_Events() {
const (
tokenOutMinAmount = 1
shareOut = 110
p0mvn marked this conversation as resolved.
Show resolved Hide resolved
)

testcases := map[string]struct {
poolId uint64
shareInAmount sdk.Int
tokenOutMins sdk.Coins
expectError bool
expectedRemoveLiquidityEvents int
expectedMessageEvents int
}{
"successful exit": {
poolId: 1,
shareInAmount: sdk.NewInt(shareOut),
tokenOutMins: sdk.NewCoins(),
expectedRemoveLiquidityEvents: 1,
expectedMessageEvents: 3, // 1 gamm + 2 tendermint.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just for my learning, why are there two TM messages emitted here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not TM, the comment is wrong, and I'm going to change this. This happens because other keeper methods emit these events. For example, bank send:
https://github.com/cosmos/cosmos-sdk/blob/71035879e4af4551b9bcf16f79bc52785793602e/x/bank/keeper/send.go#L213-L215

I think the bank send is wrong and should instead have its message emitted in the message server so that we don't triple-count it here.

},
"invalid tokenOutMins": {
poolId: 1,
shareInAmount: sdk.NewInt(shareOut),
tokenOutMins: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(tokenOutMinAmount))),
expectError: true,
},
}

for name, tc := range testcases {
suite.Run(name, func() {
suite.Setup()
ctx := suite.Ctx

suite.PrepareBalancerPool()
msgServer := keeper.NewMsgServerImpl(suite.App.GAMMKeeper)

sender := suite.TestAccs[0].String()

// Pre-join pool to be able to ExitPool.
joinPoolResponse, err := msgServer.JoinPool(sdk.WrapSDKContext(ctx), &types.MsgJoinPool{
Sender: sender,
PoolId: tc.poolId,
ShareOutAmount: sdk.NewInt(shareOut),
TokenInMaxs: sdk.NewCoins(
sdk.NewCoin("foo", sdk.NewInt(int64Max)),
sdk.NewCoin("bar", sdk.NewInt(int64Max)),
sdk.NewCoin("baz", sdk.NewInt(int64Max)),
),
})
suite.Require().NoError(err)

// Reset event counts to 0 by creating a new manager.
ctx = ctx.WithEventManager(sdk.NewEventManager())
suite.Require().Equal(0, len(ctx.EventManager().Events()))

// System under test.
response, err := msgServer.ExitPool(sdk.WrapSDKContext(ctx), &types.MsgExitPool{
Sender: sender,
PoolId: tc.poolId,
ShareInAmount: joinPoolResponse.ShareOutAmount,
TokenOutMins: tc.tokenOutMins,
})

if !tc.expectError {
suite.Require().NoError(err)
suite.Require().NotNil(response)
}

suite.AssertEventEmitted(ctx, types.TypeEvtPoolExited, tc.expectedRemoveLiquidityEvents)
suite.AssertEventEmitted(ctx, sdk.EventTypeMessage, tc.expectedMessageEvents)
})
}
suite.Require().Equal(numEventsExpected, len(actualEvents))
}
Loading