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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [1698](https://github.com/osmosis-labs/osmosis/pull/1698) Register wasm snapshotter extension.
* [1931](https://github.com/osmosis-labs/osmosis/pull/1931) Add explicit check for input denoms to `CalcJoinPoolShares`
* [2011](https://github.com/osmosis-labs/osmosis/pull/2011) Fix bug in TokenFactory initGenesis, relating to denom creation fee param.
* [2186](https://github.com/osmosis-labs/osmosis/pull/2186) Remove liquidity event that was emitted twice per message.

### Improvements
* [#2214](https://github.com/osmosis-labs/osmosis/pull/2214) Speedup epoch distribution, superfluid component
Expand Down
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))
}
11 changes: 11 additions & 0 deletions x/gamm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,17 @@ It consists of the following attributes:
This event is emitted after `ExitPool` completes exiting
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.AttributeKeyTokensOut`
* The value is the string representation of the tokens being swapped out.

### `types.TypeEvtPoolCreated`

This event is emitted after `CreatePool` completes creating
Expand Down
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 out": {
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
114 changes: 89 additions & 25 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 @@ -50,7 +52,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() {
tokenIn: sdk.NewCoin("foo", sdk.NewInt(tokenIn)),
tokenOutMinAmount: sdk.NewInt(tokenInMinAmount),
expectedSwapEvents: 1,
expectedMessageEvents: 3, // 1 gamm + 2 tendermint.
expectedMessageEvents: 3, // 1 gamm + 2 events emitted by other keeper methods.
},
"two hops": {
routes: []types.SwapAmountInRoute{
Expand All @@ -66,7 +68,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn_Events() {
tokenIn: sdk.NewCoin("foo", sdk.NewInt(tokenIn)),
tokenOutMinAmount: sdk.NewInt(tokenInMinAmount),
expectedSwapEvents: 2,
expectedMessageEvents: 5, // 1 gamm + 4 tendermint.
expectedMessageEvents: 5, // 1 gamm + 4 events emitted by other keeper methods.
},
"invalid - two hops, denom does not exist": {
routes: []types.SwapAmountInRoute{
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 @@ -150,7 +151,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() {
tokenOut: sdk.NewCoin("foo", sdk.NewInt(tokenOut)),
tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount),
expectedSwapEvents: 1,
expectedMessageEvents: 3, // 1 gamm + 2 tendermint.
expectedMessageEvents: 3, // 1 gamm + 2 events emitted by other keeper methods.
},
"two hops": {
routes: []types.SwapAmountOutRoute{
Expand All @@ -166,7 +167,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountOut_Events() {
tokenOut: sdk.NewCoin("foo", sdk.NewInt(tokenOut)),
tokenInMaxAmount: sdk.NewInt(tokenInMaxAmount),
expectedSwapEvents: 2,
expectedMessageEvents: 5, // 1 gamm + 4 tendermint.
expectedMessageEvents: 5, // 1 gamm + 4 events emitted by other keeper methods.
},
"invalid - two hops, denom does not exist": {
routes: []types.SwapAmountOutRoute{
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 All @@ -243,7 +243,7 @@ func (suite *KeeperTestSuite) TestJoinPool_Events() {
sdk.NewCoin("baz", sdk.NewInt(tokenInMaxAmount)),
),
expectedAddLiquidityEvents: 1,
expectedMessageEvents: 3, // 1 gamm + 2 tendermint.
expectedMessageEvents: 3, // 1 gamm + 2 events emitted by other keeper methods.
},
"tokenInMaxs do not match all tokens in pool - invalid join": {
poolId: 1,
Expand All @@ -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
shareIn = 110
)

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(shareIn),
tokenOutMins: sdk.NewCoins(),
expectedRemoveLiquidityEvents: 1,
expectedMessageEvents: 3, // 1 gamm + 2 events emitted by other keeper methods.
},
"invalid tokenOutMins": {
poolId: 1,
shareInAmount: sdk.NewInt(shareIn),
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(shareIn),
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