From d2c452791ee11f033261e05246e2722fab6b6b42 Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Thu, 31 Jul 2025 16:55:18 -0400 Subject: [PATCH 1/4] remove unused invariant checks --- x/bank/keeper/invariants.go | 105 ----------------- x/bank/module.go | 4 +- x/distribution/module.go | 4 +- x/gov/module.go | 4 +- x/staking/keeper/invariants.go | 198 --------------------------------- x/staking/module.go | 4 +- 6 files changed, 4 insertions(+), 315 deletions(-) delete mode 100644 x/bank/keeper/invariants.go delete mode 100644 x/staking/keeper/invariants.go diff --git a/x/bank/keeper/invariants.go b/x/bank/keeper/invariants.go deleted file mode 100644 index 12ebf782a..000000000 --- a/x/bank/keeper/invariants.go +++ /dev/null @@ -1,105 +0,0 @@ -package keeper - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -// RegisterInvariants registers the bank module invariants -func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { - ir.RegisterRoute(types.ModuleName, "nonnegative-outstanding", NonnegativeBalanceInvariant(k)) - ir.RegisterRoute(types.ModuleName, "total-supply", TotalSupply(k)) -} - -// AllInvariants runs all invariants of the X/bank module. -func AllInvariants(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - return TotalSupply(k)(ctx) - } -} - -// NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances -func NonnegativeBalanceInvariant(k ViewKeeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - var ( - msg string - count int - ) - - k.IterateAllBalances(ctx, func(addr sdk.AccAddress, balance sdk.Coin) bool { - if balance.IsNegative() { - count++ - msg += fmt.Sprintf("\t%s has a negative balance of %s\n", addr, balance) - } - - return false - }) - k.IterateAllWeiBalances(ctx, func(addr sdk.AccAddress, balance sdk.Int) bool { - if balance.IsNegative() { - count++ - msg += fmt.Sprintf("\t%s has a negative wei balance of %s\n", addr, balance) - } - - return false - }) - - broken := count != 0 - - return sdk.FormatInvariant( - types.ModuleName, "nonnegative-outstanding", - fmt.Sprintf("amount of negative balances found %d\n%s", count, msg), - ), broken - } -} - -// TotalSupply checks that the total supply reflects all the coins held in accounts -func TotalSupply(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - expectedTotal := sdk.Coins{} - weiTotal := sdk.NewInt(0) - supply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.MaxLimit}) - - if err != nil { - return sdk.FormatInvariant(types.ModuleName, "query supply", - fmt.Sprintf("error querying total supply %v", err)), false - } - - k.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool { - expectedTotal = expectedTotal.Add(balance) - return false - }) - // also iterate over deferred balances - k.IterateDeferredBalances(ctx, func(addr sdk.AccAddress, coin sdk.Coin) bool { - expectedTotal = expectedTotal.Add(coin) - return false - }) - k.IterateAllWeiBalances(ctx, func(addr sdk.AccAddress, balance sdk.Int) bool { - weiTotal = weiTotal.Add(balance) - return false - }) - weiInUsei, weiRemainder := SplitUseiWeiAmount(weiTotal) - if !weiRemainder.IsZero() { - return sdk.FormatInvariant(types.ModuleName, "total supply", - fmt.Sprintf( - "\twei remainder: %v\n", - weiRemainder)), true - } - baseDenom, err := sdk.GetBaseDenom() - if err == nil { - expectedTotal = expectedTotal.Add(sdk.NewCoin(baseDenom, weiInUsei)) - } else if !weiInUsei.IsZero() { - return sdk.FormatInvariant(types.ModuleName, "total supply", "non-zero wei balance without base denom"), true - } - - broken := !expectedTotal.IsEqual(supply) - - return sdk.FormatInvariant(types.ModuleName, "total supply", - fmt.Sprintf( - "\tsum of accounts coins: %v\n"+ - "\tsupply.Total: %v\n", - expectedTotal, supply)), broken - } -} diff --git a/x/bank/module.go b/x/bank/module.go index 4a9aabe50..b1b7fe906 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -134,9 +134,7 @@ func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.Acc func (AppModule) Name() string { return types.ModuleName } // RegisterInvariants registers the bank module invariants. -func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.keeper) -} +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} // Route returns the message routing key for the bank module. func (am AppModule) Route() sdk.Route { diff --git a/x/distribution/module.go b/x/distribution/module.go index 2fcc4601b..33fd2add2 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -127,9 +127,7 @@ func (AppModule) Name() string { } // RegisterInvariants registers the distribution module invariants. -func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.keeper) -} +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} // Route returns the message routing key for the distribution module. func (am AppModule) Route() sdk.Route { diff --git a/x/gov/module.go b/x/gov/module.go index be10664ef..21622b3f6 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -142,9 +142,7 @@ func (AppModule) Name() string { } // RegisterInvariants registers module invariants -func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.keeper, am.bankKeeper) -} +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} // Route returns the message routing key for the gov module. func (am AppModule) Route() sdk.Route { diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go deleted file mode 100644 index 0b412c6a4..000000000 --- a/x/staking/keeper/invariants.go +++ /dev/null @@ -1,198 +0,0 @@ -package keeper - -import ( - "bytes" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -// RegisterInvariants registers all staking invariants -func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { - ir.RegisterRoute(types.ModuleName, "module-accounts", - ModuleAccountInvariants(k)) - ir.RegisterRoute(types.ModuleName, "nonnegative-power", - NonNegativePowerInvariant(k)) - ir.RegisterRoute(types.ModuleName, "positive-delegation", - PositiveDelegationInvariant(k)) - ir.RegisterRoute(types.ModuleName, "delegator-shares", - DelegatorSharesInvariant(k)) -} - -// AllInvariants runs all invariants of the staking module. -func AllInvariants(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - res, stop := ModuleAccountInvariants(k)(ctx) - if stop { - return res, stop - } - - res, stop = NonNegativePowerInvariant(k)(ctx) - if stop { - return res, stop - } - - res, stop = PositiveDelegationInvariant(k)(ctx) - if stop { - return res, stop - } - - return DelegatorSharesInvariant(k)(ctx) - } -} - -// ModuleAccountInvariants checks that the bonded and notBonded ModuleAccounts pools -// reflects the tokens actively bonded and not bonded -func ModuleAccountInvariants(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - bonded := sdk.ZeroInt() - notBonded := sdk.ZeroInt() - bondedPool := k.GetBondedPool(ctx) - notBondedPool := k.GetNotBondedPool(ctx) - bondDenom := k.BondDenom(ctx) - - k.IterateValidators(ctx, func(_ int64, validator types.ValidatorI) bool { - switch validator.GetStatus() { - case types.Bonded: - bonded = bonded.Add(validator.GetTokens()) - case types.Unbonding, types.Unbonded: - notBonded = notBonded.Add(validator.GetTokens()) - default: - panic("invalid validator status") - } - return false - }) - - k.IterateUnbondingDelegations(ctx, func(_ int64, ubd types.UnbondingDelegation) bool { - for _, entry := range ubd.Entries { - notBonded = notBonded.Add(entry.Balance) - } - return false - }) - - poolBonded := k.bankKeeper.GetBalance(ctx, bondedPool.GetAddress(), bondDenom) - poolNotBonded := k.bankKeeper.GetBalance(ctx, notBondedPool.GetAddress(), bondDenom) - broken := !poolBonded.Amount.Equal(bonded) || !poolNotBonded.Amount.Equal(notBonded) - - // Bonded tokens should equal sum of tokens with bonded validators - // Not-bonded tokens should equal unbonding delegations plus tokens on unbonded validators - return sdk.FormatInvariant(types.ModuleName, "bonded and not bonded module account coins", fmt.Sprintf( - "\tPool's bonded tokens: %v\n"+ - "\tsum of bonded tokens: %v\n"+ - "not bonded token invariance:\n"+ - "\tPool's not bonded tokens: %v\n"+ - "\tsum of not bonded tokens: %v\n"+ - "module accounts total (bonded + not bonded):\n"+ - "\tModule Accounts' tokens: %v\n"+ - "\tsum tokens: %v\n", - poolBonded, bonded, poolNotBonded, notBonded, poolBonded.Add(poolNotBonded), bonded.Add(notBonded))), broken - } -} - -// NonNegativePowerInvariant checks that all stored validators have >= 0 power. -func NonNegativePowerInvariant(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - var ( - msg string - broken bool - ) - - iterator := k.ValidatorsPowerStoreIterator(ctx) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - validator, found := k.GetValidator(ctx, iterator.Value()) - if !found { - panic(fmt.Sprintf("validator record not found for address: %X\n", iterator.Value())) - } - - powerKey := types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx)) - - if !bytes.Equal(iterator.Key(), powerKey) { - broken = true - msg += fmt.Sprintf("power store invariance:\n\tvalidator.Power: %v"+ - "\n\tkey should be: %v\n\tkey in store: %v\n", - validator.GetConsensusPower(k.PowerReduction(ctx)), powerKey, iterator.Key()) - } - - if validator.Tokens.IsNegative() { - broken = true - msg += fmt.Sprintf("\tnegative tokens for validator: %v\n", validator) - } - } - - return sdk.FormatInvariant(types.ModuleName, "nonnegative power", fmt.Sprintf("found invalid validator powers\n%s", msg)), broken - } -} - -// PositiveDelegationInvariant checks that all stored delegations have > 0 shares. -func PositiveDelegationInvariant(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - var ( - msg string - count int - ) - - delegations := k.GetAllDelegations(ctx) - for _, delegation := range delegations { - if delegation.Shares.IsNegative() { - count++ - - msg += fmt.Sprintf("\tdelegation with negative shares: %+v\n", delegation) - } - - if delegation.Shares.IsZero() { - count++ - - msg += fmt.Sprintf("\tdelegation with zero shares: %+v\n", delegation) - } - } - - broken := count != 0 - - return sdk.FormatInvariant(types.ModuleName, "positive delegations", fmt.Sprintf( - "%d invalid delegations found\n%s", count, msg)), broken - } -} - -// DelegatorSharesInvariant checks whether all the delegator shares which persist -// in the delegator object add up to the correct total delegator shares -// amount stored in each validator. -func DelegatorSharesInvariant(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - var ( - msg string - broken bool - ) - - validators := k.GetAllValidators(ctx) - validatorsDelegationShares := map[string]sdk.Dec{} - - // initialize a map: validator -> its delegation shares - for _, validator := range validators { - validatorsDelegationShares[validator.GetOperator().String()] = sdk.ZeroDec() - } - - // iterate through all the delegations to calculate the total delegation shares for each validator - delegations := k.GetAllDelegations(ctx) - for _, delegation := range delegations { - delegationValidatorAddr := delegation.GetValidatorAddr().String() - validatorDelegationShares := validatorsDelegationShares[delegationValidatorAddr] - validatorsDelegationShares[delegationValidatorAddr] = validatorDelegationShares.Add(delegation.Shares) - } - - // for each validator, check if its total delegation shares calculated from the step above equals to its expected delegation shares - for _, validator := range validators { - expValTotalDelShares := validator.GetDelegatorShares() - calculatedValTotalDelShares := validatorsDelegationShares[validator.GetOperator().String()] - if !calculatedValTotalDelShares.Equal(expValTotalDelShares) { - broken = true - msg += fmt.Sprintf("broken delegator shares invariance:\n"+ - "\tvalidator.DelegatorShares: %v\n"+ - "\tsum of Delegator.Shares: %v\n", expValTotalDelShares, calculatedValTotalDelShares) - } - } - - return sdk.FormatInvariant(types.ModuleName, "delegator shares", msg), broken - } -} diff --git a/x/staking/module.go b/x/staking/module.go index c5b81823d..4716d5d0f 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -124,9 +124,7 @@ func (AppModule) Name() string { } // RegisterInvariants registers the staking module invariants. -func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.keeper) -} +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} // Route returns the message routing key for the staking module. func (am AppModule) Route() sdk.Route { From 20e4b993e9273456b10e756ef5e90eec080254d4 Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Thu, 31 Jul 2025 16:59:57 -0400 Subject: [PATCH 2/4] remove distr invariants --- x/distribution/keeper/invariants.go | 162 ---------------------------- 1 file changed, 162 deletions(-) delete mode 100644 x/distribution/keeper/invariants.go diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go deleted file mode 100644 index 0a23d36be..000000000 --- a/x/distribution/keeper/invariants.go +++ /dev/null @@ -1,162 +0,0 @@ -package keeper - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/distribution/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -// register all distribution invariants -func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { - ir.RegisterRoute(types.ModuleName, "nonnegative-outstanding", - NonNegativeOutstandingInvariant(k)) - ir.RegisterRoute(types.ModuleName, "can-withdraw", - CanWithdrawInvariant(k)) - ir.RegisterRoute(types.ModuleName, "reference-count", - ReferenceCountInvariant(k)) - ir.RegisterRoute(types.ModuleName, "module-account", - ModuleAccountInvariant(k)) -} - -// AllInvariants runs all invariants of the distribution module -func AllInvariants(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - res, stop := CanWithdrawInvariant(k)(ctx) - if stop { - return res, stop - } - res, stop = NonNegativeOutstandingInvariant(k)(ctx) - if stop { - return res, stop - } - res, stop = ReferenceCountInvariant(k)(ctx) - if stop { - return res, stop - } - return ModuleAccountInvariant(k)(ctx) - } -} - -// NonNegativeOutstandingInvariant checks that outstanding unwithdrawn fees are never negative -func NonNegativeOutstandingInvariant(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - var msg string - var count int - var outstanding sdk.DecCoins - - k.IterateValidatorOutstandingRewards(ctx, func(addr sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { - outstanding = rewards.GetRewards() - if outstanding.IsAnyNegative() { - count++ - msg += fmt.Sprintf("\t%v has negative outstanding coins: %v\n", addr, outstanding) - } - return false - }) - broken := count != 0 - - return sdk.FormatInvariant(types.ModuleName, "nonnegative outstanding", - fmt.Sprintf("found %d validators with negative outstanding rewards\n%s", count, msg)), broken - } -} - -// CanWithdrawInvariant checks that current rewards can be completely withdrawn -func CanWithdrawInvariant(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - - // cache, we don't want to write changes - ctx, _ = ctx.CacheContext() - - var remaining sdk.DecCoins - - valDelegationAddrs := make(map[string][]sdk.AccAddress) - for _, del := range k.stakingKeeper.GetAllSDKDelegations(ctx) { - valAddr := del.GetValidatorAddr().String() - valDelegationAddrs[valAddr] = append(valDelegationAddrs[valAddr], del.GetDelegatorAddr()) - } - - // iterate over all validators - k.stakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - _, _ = k.WithdrawValidatorCommission(ctx, val.GetOperator()) - - delegationAddrs, ok := valDelegationAddrs[val.GetOperator().String()] - if ok { - for _, delAddr := range delegationAddrs { - if _, err := k.WithdrawDelegationRewards(ctx, delAddr, val.GetOperator()); err != nil { - panic(err) - } - } - } - - remaining = k.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator()) - if len(remaining) > 0 && remaining[0].Amount.IsNegative() { - return true - } - - return false - }) - - broken := len(remaining) > 0 && remaining[0].Amount.IsNegative() - return sdk.FormatInvariant(types.ModuleName, "can withdraw", - fmt.Sprintf("remaining coins: %v\n", remaining)), broken - } -} - -// ReferenceCountInvariant checks that the number of historical rewards records is correct -func ReferenceCountInvariant(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - - valCount := uint64(0) - k.stakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - valCount++ - return false - }) - dels := k.stakingKeeper.GetAllSDKDelegations(ctx) - slashCount := uint64(0) - k.IterateValidatorSlashEvents(ctx, - func(_ sdk.ValAddress, _ uint64, _ types.ValidatorSlashEvent) (stop bool) { - slashCount++ - return false - }) - - // one record per validator (last tracked period), one record per - // delegation (previous period), one record per slash (previous period) - expected := valCount + uint64(len(dels)) + slashCount - count := k.GetValidatorHistoricalReferenceCount(ctx) - broken := count != expected - - return sdk.FormatInvariant(types.ModuleName, "reference count", - fmt.Sprintf("expected historical reference count: %d = %v validators + %v delegations + %v slashes\n"+ - "total validator historical reference count: %d\n", - expected, valCount, len(dels), slashCount, count)), broken - } -} - -// ModuleAccountInvariant checks that the coins held by the distr ModuleAccount -// is consistent with the sum of validator outstanding rewards -func ModuleAccountInvariant(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - - var expectedCoins sdk.DecCoins - k.IterateValidatorOutstandingRewards(ctx, func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { - expectedCoins = expectedCoins.Add(rewards.Rewards...) - return false - }) - - communityPool := k.GetFeePoolCommunityCoins(ctx) - expectedInt, _ := expectedCoins.Add(communityPool...).TruncateDecimal() - - macc := k.GetDistributionAccount(ctx) - balances := k.bankKeeper.GetAllBalances(ctx, macc.GetAddress()) - - broken := !balances.IsEqual(expectedInt) - return sdk.FormatInvariant( - types.ModuleName, "ModuleAccount coins", - fmt.Sprintf("\texpected ModuleAccount coins: %s\n"+ - "\tdistribution ModuleAccount coins: %s\n", - expectedInt, balances, - ), - ), broken - } -} From a4fd6aabc1f8a4c4c766ad755c21960257a71361 Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Thu, 31 Jul 2025 17:10:54 -0400 Subject: [PATCH 3/4] add back TotalSupply check --- x/bank/keeper/invariants.go | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 x/bank/keeper/invariants.go diff --git a/x/bank/keeper/invariants.go b/x/bank/keeper/invariants.go new file mode 100644 index 000000000..761084b56 --- /dev/null +++ b/x/bank/keeper/invariants.go @@ -0,0 +1,58 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// TotalSupply checks that the total supply reflects all the coins held in accounts +func TotalSupply(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + expectedTotal := sdk.Coins{} + weiTotal := sdk.NewInt(0) + supply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.MaxLimit}) + + if err != nil { + return sdk.FormatInvariant(types.ModuleName, "query supply", + fmt.Sprintf("error querying total supply %v", err)), false + } + + k.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool { + expectedTotal = expectedTotal.Add(balance) + return false + }) + // also iterate over deferred balances + k.IterateDeferredBalances(ctx, func(addr sdk.AccAddress, coin sdk.Coin) bool { + expectedTotal = expectedTotal.Add(coin) + return false + }) + k.IterateAllWeiBalances(ctx, func(addr sdk.AccAddress, balance sdk.Int) bool { + weiTotal = weiTotal.Add(balance) + return false + }) + weiInUsei, weiRemainder := SplitUseiWeiAmount(weiTotal) + if !weiRemainder.IsZero() { + return sdk.FormatInvariant(types.ModuleName, "total supply", + fmt.Sprintf( + "\twei remainder: %v\n", + weiRemainder)), true + } + baseDenom, err := sdk.GetBaseDenom() + if err == nil { + expectedTotal = expectedTotal.Add(sdk.NewCoin(baseDenom, weiInUsei)) + } else if !weiInUsei.IsZero() { + return sdk.FormatInvariant(types.ModuleName, "total supply", "non-zero wei balance without base denom"), true + } + + broken := !expectedTotal.IsEqual(supply) + + return sdk.FormatInvariant(types.ModuleName, "total supply", + fmt.Sprintf( + "\tsum of accounts coins: %v\n"+ + "\tsupply.Total: %v\n", + expectedTotal, supply)), broken + } +} \ No newline at end of file From 8ede500353cb66e7bc8d1d7dc790b07c206345dd Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Thu, 31 Jul 2025 17:16:16 -0400 Subject: [PATCH 4/4] minor fix --- x/bank/keeper/invariants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/bank/keeper/invariants.go b/x/bank/keeper/invariants.go index 761084b56..3cb88efad 100644 --- a/x/bank/keeper/invariants.go +++ b/x/bank/keeper/invariants.go @@ -55,4 +55,4 @@ func TotalSupply(k Keeper) sdk.Invariant { "\tsupply.Total: %v\n", expectedTotal, supply)), broken } -} \ No newline at end of file +}