github.com/Finschia/finschia-sdk@v0.48.1/x/bank/keeper/invariants.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sdk "github.com/Finschia/finschia-sdk/types"
     7  	"github.com/Finschia/finschia-sdk/types/query"
     8  	"github.com/Finschia/finschia-sdk/x/bank/types"
     9  )
    10  
    11  // RegisterInvariants registers the bank module invariants
    12  func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
    13  	ir.RegisterRoute(types.ModuleName, "nonnegative-outstanding", NonnegativeBalanceInvariant(k))
    14  	ir.RegisterRoute(types.ModuleName, "total-supply", TotalSupply(k))
    15  }
    16  
    17  // AllInvariants runs all invariants of the X/bank module.
    18  func AllInvariants(k Keeper) sdk.Invariant {
    19  	return func(ctx sdk.Context) (string, bool) {
    20  		return TotalSupply(k)(ctx)
    21  	}
    22  }
    23  
    24  // NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances
    25  func NonnegativeBalanceInvariant(k ViewKeeper) sdk.Invariant {
    26  	return func(ctx sdk.Context) (string, bool) {
    27  		var (
    28  			msg   string
    29  			count int
    30  		)
    31  
    32  		k.IterateAllBalances(ctx, func(addr sdk.AccAddress, balance sdk.Coin) bool {
    33  			if balance.IsNegative() {
    34  				count++
    35  				msg += fmt.Sprintf("\t%s has a negative balance of %s\n", addr, balance)
    36  			}
    37  
    38  			return false
    39  		})
    40  
    41  		broken := count != 0
    42  
    43  		return sdk.FormatInvariant(
    44  			types.ModuleName, "nonnegative-outstanding",
    45  			fmt.Sprintf("amount of negative balances found %d\n%s", count, msg),
    46  		), broken
    47  	}
    48  }
    49  
    50  // TotalSupply checks that the total supply reflects all the coins held in accounts
    51  func TotalSupply(k Keeper) sdk.Invariant {
    52  	return func(ctx sdk.Context) (string, bool) {
    53  		expectedTotal := sdk.Coins{}
    54  		supply, _, err := k.GetPaginatedTotalSupply(ctx, &query.PageRequest{Limit: query.MaxLimit})
    55  		if err != nil {
    56  			return sdk.FormatInvariant(types.ModuleName, "query supply",
    57  				fmt.Sprintf("error querying total supply %v", err)), false
    58  		}
    59  
    60  		k.IterateAllBalances(ctx, func(_ sdk.AccAddress, balance sdk.Coin) bool {
    61  			expectedTotal = expectedTotal.Add(balance)
    62  			return false
    63  		})
    64  
    65  		broken := !expectedTotal.IsEqual(supply)
    66  
    67  		return sdk.FormatInvariant(types.ModuleName, "total supply",
    68  			fmt.Sprintf(
    69  				"\tsum of accounts coins: %v\n"+
    70  					"\tsupply.Total:          %v\n",
    71  				expectedTotal, supply)), broken
    72  	}
    73  }