From ae4cb15d7369fe0967f69854fcfdc086e22c58bb Mon Sep 17 00:00:00 2001 From: drklee3 Date: Tue, 3 Oct 2023 15:10:22 -0700 Subject: [PATCH] Emit events for inflation disable and staking rewards (#1743) * Emit events for staking rewards * Update test to check disable inflation check * Only emit staking rewards event when non-zero value * use existing transfer amount for event * add assertion that no events are emitted for zero rewards; refactor event assertions to be a little cleaner --------- Co-authored-by: Nick DeLuca --- app/test_common.go | 29 ++++++++++++++ x/community/keeper/disable_inflation.go | 6 +++ x/community/keeper/staking.go | 11 +++++- x/community/testutil/disable_inflation.go | 2 + x/community/testutil/staking_rewards.go | 46 +++++++++++++++++++++++ x/community/types/events.go | 5 +++ 6 files changed, 97 insertions(+), 2 deletions(-) diff --git a/app/test_common.go b/app/test_common.go index e969743b..8c36545b 100644 --- a/app/test_common.go +++ b/app/test_common.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "math/rand" + "reflect" "testing" "time" @@ -536,3 +537,31 @@ func NewFundedGenStateWithSameCoinsWithModuleAccount(cdc codec.JSONCodec, coins return builder.BuildMarshalled(cdc) } + +// EventsContains returns an error if the expected event is not in the provided events +func EventsContains(events sdk.Events, expectedEvent sdk.Event) error { + foundMatch := false + for _, event := range events { + if event.Type == expectedEvent.Type { + if reflect.DeepEqual(attrsToMap(expectedEvent.Attributes), attrsToMap(event.Attributes)) { + foundMatch = true + } + } + } + + if !foundMatch { + return fmt.Errorf("event of type %s not found or did not match", expectedEvent.Type) + } + + return nil +} + +func attrsToMap(attrs []abci.EventAttribute) []sdk.Attribute { // new cosmos changed the event attribute type + out := []sdk.Attribute{} + + for _, attr := range attrs { + out = append(out, sdk.NewAttribute(string(attr.Key), string(attr.Value))) + } + + return out +} diff --git a/x/community/keeper/disable_inflation.go b/x/community/keeper/disable_inflation.go index 85e77d3f..86ceff6c 100644 --- a/x/community/keeper/disable_inflation.go +++ b/x/community/keeper/disable_inflation.go @@ -4,6 +4,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/kava-labs/kava/x/community/types" ) // CheckAndDisableMintAndKavaDistInflation compares the disable inflation time and block time, @@ -27,6 +28,11 @@ func (k Keeper) CheckAndDisableMintAndKavaDistInflation(ctx sdk.Context) { params.StakingRewardsPerSecond = params.UpgradeTimeSetStakingRewardsPerSecond k.SetParams(ctx, params) + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeInflationStop, + ), + ) } // TODO: double check this is correct method for disabling inflation in kavadist without diff --git a/x/community/keeper/staking.go b/x/community/keeper/staking.go index 716ee492..c645faa5 100644 --- a/x/community/keeper/staking.go +++ b/x/community/keeper/staking.go @@ -51,6 +51,15 @@ func (k Keeper) PayoutAccumulatedStakingRewards(ctx sdk.Context) { // occur in cases where the chain is running in an invalid state panic(err) } + + // emit event with amount transferred + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeStakingRewardsPaid, + sdk.NewAttribute(types.AttributeKeyStakingRewardAmount, transferAmount.String()), + ), + ) + } // update accumulation state @@ -60,8 +69,6 @@ func (k Keeper) PayoutAccumulatedStakingRewards(ctx sdk.Context) { // save state k.SetStakingRewardsState(ctx, state) - - return } // calculateStakingRewards takees the currentBlockTime, state of last accumulation, rewards per second, and the community pool balance diff --git a/x/community/testutil/disable_inflation.go b/x/community/testutil/disable_inflation.go index 50646290..9edff7d4 100644 --- a/x/community/testutil/disable_inflation.go +++ b/x/community/testutil/disable_inflation.go @@ -93,6 +93,8 @@ func (suite *disableInflationTestSuite) TestDisableInflation() { expectedKavadistState.Params.Active = false msgSuffix = "after upgrade" + + suite.Require().NoError(app.EventsContains(suite.Ctx.EventManager().Events(), sdk.NewEvent(types.EventTypeInflationStop))) } suite.Require().Equal(expectedMintState.Params.InflationMin, mintParams.InflationMin, msg+": expected mint inflation min to match state "+msgSuffix) diff --git a/x/community/testutil/staking_rewards.go b/x/community/testutil/staking_rewards.go index 4e1efc27..429e24ec 100644 --- a/x/community/testutil/staking_rewards.go +++ b/x/community/testutil/staking_rewards.go @@ -258,10 +258,15 @@ func (suite *stakingRewardsTestSuite) TestStakingRewards() { params.StakingRewardsPerSecond = tc.rewardsPerSecond keeper.SetParams(ctx, params) + stakingRewardEvents := sdk.Events{} + for { // run community begin blocker logic suite.testFunc(ctx, keeper) + // accumulate event rewards from events + stakingRewardEvents = append(stakingRewardEvents, filterStakingRewardEvents(ctx.EventManager().Events())...) + // exit loop if we are at last block if blockTime.Equal(tc.periodEnd) { break @@ -287,6 +292,20 @@ func (suite *stakingRewardsTestSuite) TestStakingRewards() { // assert fee pool was payed the correct rewards suite.Equal(tc.expectedRewardsTotal.String(), feeCollectorBalanceAdded.String(), "expected fee collector balance to match") + if tc.expectedRewardsTotal.IsZero() { + suite.Equal(0, len(stakingRewardEvents), "expected no events to be emitted") + } else { + // we add up all reward coin events + eventCoins := getRewardCoinsFromEvents(stakingRewardEvents) + + // assert events emitted match expected rewards + suite.Equal( + tc.expectedRewardsTotal.String(), + eventCoins.AmountOf("ukava").String(), + "expected event coins to match", + ) + } + // assert the community pool deducted the same amount expectedCommunityPoolBalance := tc.communityPoolFunds.Sub(tc.expectedRewardsTotal) actualCommunityPoolBalance := bankKeeper.GetBalance(ctx, poolAcc.GetAddress(), "ukava").Amount @@ -373,3 +392,30 @@ func newIntFromString(str string) sdkmath.Int { } return num } + +func filterStakingRewardEvents(events sdk.Events) (rewardEvents sdk.Events) { + for _, event := range events { + if event.Type == types.EventTypeStakingRewardsPaid { + rewardEvents = append(rewardEvents, event) + } + } + + return +} + +func getRewardCoinsFromEvents(events sdk.Events) sdk.Coins { + coins := sdk.NewCoins() + + for _, event := range events { + if event.Type == types.EventTypeStakingRewardsPaid { + rewards, err := sdk.ParseCoinNormalized(string(event.Attributes[0].Value)) + if err != nil { + panic(err) + } + + coins = coins.Add(rewards) + } + } + + return coins +} diff --git a/x/community/types/events.go b/x/community/types/events.go index 92852bce..75b1db5d 100644 --- a/x/community/types/events.go +++ b/x/community/types/events.go @@ -2,6 +2,11 @@ package types // Community module event types const ( + EventTypeInflationStop = "inflation_stop" + EventTypeStakingRewardsPaid = "staking_rewards_paid" + + AttributeKeyStakingRewardAmount = "staking_reward_amount" + AttributeValueFundCommunityPool = "fund_community_pool" AttributeValueCategory = ModuleName )