Pre-requisite Readings

Synopsis

This document guides developers on integrating their custom modules with the Cosmos SDK Simulations. Simulations are useful for testing edge cases in module implementations.

Simulation Package

The Cosmos SDK suggests organizing your simulation related code in a x/<module>/simulation package.

Simulation App Module

To integrate with the Cosmos SDK SimulationManager, app modules must implement the AppModuleSimulation interface.
package module

import (
    
	"encoding/json"
    "math/rand"
    "sort"
    "time"

	sdkmath "cosmossdk.io/math"
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/types/simulation"
)

/ AppModuleSimulation defines the standard functions that every module should expose
/ for the SDK blockchain simulator
type AppModuleSimulation interface {
	/ randomized genesis states
	GenerateGenesisState(input *SimulationState)

	/ register a func to decode the each module's defined types from their corresponding store key
	RegisterStoreDecoder(simulation.StoreDecoderRegistry)

	/ simulation operations (i.e msgs)

with their respective weight
	WeightedOperations(simState SimulationState) []simulation.WeightedOperation
}

/ HasProposalMsgs defines the messages that can be used to simulate governance (v1)

proposals
type HasProposalMsgs interface {
	/ msg functions used to simulate governance proposals
	ProposalMsgs(simState SimulationState) []simulation.WeightedProposalMsg
}

/ HasProposalContents defines the contents that can be used to simulate legacy governance (v1beta1)

proposals
type HasProposalContents interface {
	/ content functions used to simulate governance proposals
	ProposalContents(simState SimulationState) []simulation.WeightedProposalContent /nolint:staticcheck / legacy v1beta1 governance
}

/ SimulationManager defines a simulation manager that provides the high level utility
/ for managing and executing simulation functionalities for a group of modules
type SimulationManager struct {
    Modules       []AppModuleSimulation           / array of app modules; we use an array for deterministic simulation tests
	StoreDecoders simulation.StoreDecoderRegistry / functions to decode the key-value pairs from each module's store
}

/ NewSimulationManager creates a new SimulationManager object
/
/ CONTRACT: All the modules provided must be also registered on the module Manager
func NewSimulationManager(modules ...AppModuleSimulation) *SimulationManager {
    return &SimulationManager{
    Modules:       modules,
    StoreDecoders: make(simulation.StoreDecoderRegistry),
}
}

/ NewSimulationManagerFromAppModules creates a new SimulationManager object.
/
/ First it sets any SimulationModule provided by overrideModules, and ignores any AppModule
/ with the same moduleName.
/ Then it attempts to cast every provided AppModule into an AppModuleSimulation.
/ If the cast succeeds, its included, otherwise it is excluded.
func NewSimulationManagerFromAppModules(modules map[string]any, overrideModules map[string]AppModuleSimulation) *SimulationManager {
    simModules := []AppModuleSimulation{
}
    appModuleNamesSorted := make([]string, 0, len(modules))
    for moduleName := range modules {
    appModuleNamesSorted = append(appModuleNamesSorted, moduleName)
}

sort.Strings(appModuleNamesSorted)
    for _, moduleName := range appModuleNamesSorted {
		/ for every module, see if we override it. If so, use override.
		/ Else, if we can cast the app module into a simulation module add it.
		/ otherwise no simulation module.
    if simModule, ok := overrideModules[moduleName]; ok {
    simModules = append(simModules, simModule)
}

else {
    appModule := modules[moduleName]
    if simModule, ok := appModule.(AppModuleSimulation); ok {
    simModules = append(simModules, simModule)
}
			/ cannot cast, so we continue
}
	
}

return NewSimulationManager(simModules...)
}

/ Deprecated: Use GetProposalMsgs instead.
/ GetProposalContents returns each module's proposal content generator function
/ with their default operation weight and key.
func (sm *SimulationManager)

GetProposalContents(simState SimulationState) []simulation.WeightedProposalContent {
    wContents := make([]simulation.WeightedProposalContent, 0, len(sm.Modules))
    for _, module := range sm.Modules {
    if module, ok := module.(HasProposalContents); ok {
    wContents = append(wContents, module.ProposalContents(simState)...)
}
	
}

return wContents
}

/ GetProposalMsgs returns each module's proposal msg generator function
/ with their default operation weight and key.
func (sm *SimulationManager)

GetProposalMsgs(simState SimulationState) []simulation.WeightedProposalMsg {
    wContents := make([]simulation.WeightedProposalMsg, 0, len(sm.Modules))
    for _, module := range sm.Modules {
    if module, ok := module.(HasProposalMsgs); ok {
    wContents = append(wContents, module.ProposalMsgs(simState)...)
}
	
}

return wContents
}

/ RegisterStoreDecoders registers each of the modules' store decoders into a map
func (sm *SimulationManager)

RegisterStoreDecoders() {
    for _, module := range sm.Modules {
    module.RegisterStoreDecoder(sm.StoreDecoders)
}
}

/ GenerateGenesisStates generates a randomized GenesisState for each of the
/ registered modules
func (sm *SimulationManager)

GenerateGenesisStates(simState *SimulationState) {
    for _, module := range sm.Modules {
    module.GenerateGenesisState(simState)
}
}

/ WeightedOperations returns all the modules' weighted operations of an application
func (sm *SimulationManager)

WeightedOperations(simState SimulationState) []simulation.WeightedOperation {
    wOps := make([]simulation.WeightedOperation, 0, len(sm.Modules))
    for _, module := range sm.Modules {
    wOps = append(wOps, module.WeightedOperations(simState)...)
}

return wOps
}

/ SimulationState is the input parameters used on each of the module's randomized
/ GenesisState generator function
type SimulationState struct {
    AppParams         simulation.AppParams
	Cdc               codec.JSONCodec                / application codec
	TxConfig          client.TxConfig                / Shared TxConfig; this is expensive to create and stateless, so create it once up front.
	Rand              *rand.Rand                     / random number
	GenState          map[string]json.RawMessage     / genesis state
	Accounts          []simulation.Account           / simulation accounts
	InitialStake      sdkmath.Int                    / initial coins per account
	NumBonded         int64                          / number of initially bonded accounts
	BondDenom         string                         / denom to be used as default
	GenTimestamp      time.Time                      / genesis timestamp
	UnbondTime        time.Duration                  / staking unbond time stored to use it as the slashing maximum evidence duration
	LegacyParamChange []simulation.LegacyParamChange / simulated parameter changes from modules
	/nolint:staticcheck /	legacy used for testing
	LegacyProposalContents []simulation.WeightedProposalContent / proposal content generator functions with their default weight and app sim key
	ProposalMsgs           []simulation.WeightedProposalMsg     / proposal msg generator functions with their default weight and app sim key
}
See an example implementation of these methods from x/distribution here.

SimsX

Cosmos SDK v0.53.0 introduced a new package, simsx, providing improved DevX for writing simulation code. It exposes the following extension interfaces that modules may implement to integrate with the new simsx runner.
package simsx

import (
    
	"encoding/json"
    "fmt"
    "io"
    "math"
    "os"
    "path/filepath"
    "strings"
    "testing"

	dbm "github.com/cosmos/cosmos-db"
    "github.com/stretchr/testify/require"
    "cosmossdk.io/log"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/client/flags"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/runtime"
	servertypes "github.com/cosmos/cosmos-sdk/server/types"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/types/module"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    "github.com/cosmos/cosmos-sdk/x/simulation"
    "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
)

const SimAppChainID = "simulation-app"

/ this list of seeds was imported from the original simulation runner: https://github.com/cosmos/tools/blob/v1.0.0/cmd/runsim/main.go#L32
var defaultSeeds = []int64{
	1, 2, 4, 7,
	32, 123, 124, 582, 1893, 2989,
	3012, 4728, 37827, 981928, 87821, 891823782,
	989182, 89182391, 11, 22, 44, 77, 99, 2020,
	3232, 123123, 124124, 582582, 18931893,
	29892989, 30123012, 47284728, 7601778, 8090485,
	977367484, 491163361, 424254581, 673398983,
}

/ SimStateFactory is a factory type that provides a convenient way to create a simulation state for testing.
/ It contains the following fields:
/ - Codec: a codec used for serializing other objects
/ - AppStateFn: a function that returns the app state JSON bytes and the genesis accounts
/ - BlockedAddr: a map of blocked addresses
/ - AccountSource: an interface for retrieving accounts
/ - BalanceSource: an interface for retrieving balance-related information
type SimStateFactory struct {
    Codec         codec.Codec
	AppStateFn    simtypes.AppStateFn
	BlockedAddr   map[string]bool
	AccountSource AccountSourceX
	BalanceSource BalanceSource
}

/ SimulationApp abstract app that is used by sims
type SimulationApp interface {
    runtime.AppI
	SetNotSigverifyTx()

GetBaseApp() *baseapp.BaseApp
	TxConfig()

client.TxConfig
	Close()

error
}

/ Run is a helper function that runs a simulation test with the given parameters.
/ It calls the RunWithSeeds function with the default seeds and parameters.
/
/ This is the entrypoint to run simulation tests that used to run with the runsim binary.
func Run[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()

RunWithSeeds(t, appFactory, setupStateFactory, defaultSeeds, nil, postRunActions...)
}

/ RunWithSeeds is a helper function that runs a simulation test with the given parameters.
/ It iterates over the provided seeds and runs the simulation test for each seed in parallel.
/
/ It sets up the environment, creates an instance of the simulation app,
/ calls the simulation.SimulateFromSeed function to run the simulation, and performs post-run actions for each seed.
/ The execution is deterministic and can be used for fuzz tests as well.
/
/ The system under test is isolated for each run but unlike the old runsim command, there is no Process separation.
/ This means, global caches may be reused for example. This implementation build upon the vanilla Go stdlib test framework.
func RunWithSeeds[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	seeds []int64,
	fuzzSeed []byte,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()

RunWithSeedsAndRandAcc(t, appFactory, setupStateFactory, seeds, fuzzSeed, simtypes.RandomAccounts, postRunActions...)
}

/ RunWithSeedsAndRandAcc calls RunWithSeeds with randAccFn
func RunWithSeedsAndRandAcc[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	seeds []int64,
	fuzzSeed []byte,
	randAccFn simtypes.RandomAccountFn,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()
    if deprecatedParams := cli.GetDeprecatedFlagUsed(); len(deprecatedParams) != 0 {
    fmt.Printf("Warning: Deprecated flag are used: %s", strings.Join(deprecatedParams, ","))
}
    cfg := cli.NewConfigFromFlags()

cfg.ChainID = SimAppChainID
    for i := range seeds {
    seed := seeds[i]
		t.Run(fmt.Sprintf("seed: %d", seed), func(t *testing.T) {
    t.Parallel()

RunWithSeed(t, cfg, appFactory, setupStateFactory, seed, fuzzSeed, postRunActions...)
})
}
}

/ RunWithSeed is a helper function that runs a simulation test with the given parameters.
/ It iterates over the provided seeds and runs the simulation test for each seed in parallel.
/
/ It sets up the environment, creates an instance of the simulation app,
/ calls the simulation.SimulateFromSeed function to run the simulation, and performs post-run actions for the seed.
/ The execution is deterministic and can be used for fuzz tests as well.
func RunWithSeed[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	cfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
	setupStateFactory func(app T)

SimStateFactory,
	seed int64,
	fuzzSeed []byte,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    tb.Helper()

RunWithSeedAndRandAcc(tb, cfg, appFactory, setupStateFactory, seed, fuzzSeed, simtypes.RandomAccounts, postRunActions...)
}

/ RunWithSeedAndRandAcc calls RunWithSeed with randAccFn
func RunWithSeedAndRandAcc[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	cfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
	setupStateFactory func(app T)

SimStateFactory,
	seed int64,
	fuzzSeed []byte,
	randAccFn simtypes.RandomAccountFn,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    tb.Helper()
	/ setup environment
    tCfg := cfg.With(tb, seed, fuzzSeed)
    testInstance := NewSimulationAppInstance(tb, tCfg, appFactory)

var runLogger log.Logger
    if cli.FlagVerboseValue {
    runLogger = log.NewTestLogger(tb)
}

else {
    runLogger = log.NewTestLoggerInfo(tb)
}

runLogger = runLogger.With("seed", tCfg.Seed)
    app := testInstance.App
    stateFactory := setupStateFactory(app)

ops, reporter := prepareWeightedOps(app.SimulationManager(), stateFactory, tCfg, testInstance.App.TxConfig(), runLogger)

simParams, accs, err := simulation.SimulateFromSeedX(
		tb,
		runLogger,
		WriteToDebugLog(runLogger),
		app.GetBaseApp(),
		stateFactory.AppStateFn,
		randAccFn,
		ops,
		stateFactory.BlockedAddr,
		tCfg,
		stateFactory.Codec,
		testInstance.ExecLogWriter,
	)

require.NoError(tb, err)

err = simtestutil.CheckExportSimulation(app, tCfg, simParams)

require.NoError(tb, err)
    if tCfg.Commit {
    simtestutil.PrintStats(testInstance.DB)
}
	/ not using tb.Log to always print the summary
	fmt.Printf("+++ DONE (seed: %d): \n%s\n", seed, reporter.Summary().String())
    for _, step := range postRunActions {
    step(tb, testInstance, accs)
}

require.NoError(tb, app.Close())
}

type (
	HasWeightedOperationsX interface {
    WeightedOperationsX(weight WeightSource, reg Registry)
}

HasWeightedOperationsXWithProposals interface {
    WeightedOperationsX(weights WeightSource, reg Registry, proposals WeightedProposalMsgIter,
			legacyProposals []simtypes.WeightedProposalContent) /nolint: staticcheck / used for legacy proposal types
}

HasProposalMsgsX interface {
    ProposalMsgsX(weights WeightSource, reg Registry)
}
)

type (
	HasLegacyWeightedOperations interface {
		/ WeightedOperations simulation operations (i.e msgs)

with their respective weight
		WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation
}
	/ HasLegacyProposalMsgs defines the messages that can be used to simulate governance (v1)

proposals
	/ Deprecated replaced by HasProposalMsgsX
	HasLegacyProposalMsgs interface {
		/ ProposalMsgs msg fu	nctions used to simulate governance proposals
		ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg
}

	/ HasLegacyProposalContents defines the contents that can be used to simulate legacy governance (v1beta1)

proposals
	/ Deprecated replaced by HasProposalMsgsX
	HasLegacyProposalContents interface {
		/ ProposalContents content functions used to simulate governance proposals
		ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent /nolint:staticcheck / legacy v1beta1 governance
}
)

/ TestInstance is a generic type that represents an instance of a SimulationApp used for testing simulations.
/ It contains the following fields:
/   - App: The instance of the SimulationApp under test.
/   - DB: The LevelDB database for the simulation app.
/   - WorkDir: The temporary working directory for the simulation app.
/   - Cfg: The configuration flags for the simulator.
/   - AppLogger: The logger used for logging in the app during the simulation, with seed value attached.
/   - ExecLogWriter: Captures block and operation data coming from the simulation
type TestInstance[T SimulationApp] struct {
    App           T
	DB            dbm.DB
	WorkDir       string
	Cfg           simtypes.Config
	AppLogger     log.Logger
	ExecLogWriter simulation.LogWriter
}

/ included to avoid cyclic dependency in testutils/sims
func prepareWeightedOps(
	sm *module.SimulationManager,
	stateFact SimStateFactory,
	config simtypes.Config,
	txConfig client.TxConfig,
	logger log.Logger,
) (simulation.WeightedOperations, *BasicSimulationReporter) {
    cdc := stateFact.Codec
    simState := module.SimulationState{
    AppParams: make(simtypes.AppParams),
    Cdc:       cdc,
    TxConfig:  txConfig,
    BondDenom: sdk.DefaultBondDenom,
}
    if config.ParamsFile != "" {
    bz, err := os.ReadFile(config.ParamsFile)
    if err != nil {
    panic(err)
}

err = json.Unmarshal(bz, &simState.AppParams)
    if err != nil {
    panic(err)
}
	
}
    weights := ParamWeightSource(simState.AppParams)
    reporter := NewBasicSimulationReporter()
    pReg := make(UniqueTypeRegistry)
    wContent := make([]simtypes.WeightedProposalContent, 0) /nolint:staticcheck / required for legacy type
    legacyPReg := NewWeightedFactoryMethods()
	/ add gov proposals types
    for _, m := range sm.Modules {
    switch xm := m.(type) {
    case HasProposalMsgsX:
			xm.ProposalMsgsX(weights, pReg)
    case HasLegacyProposalMsgs:
    for _, p := range xm.ProposalMsgs(simState) {
    weight := weights.Get(p.AppParamsKey(), safeUint(p.DefaultWeight()))

legacyPReg.Add(weight, legacyToMsgFactoryAdapter(p.MsgSimulatorFn()))
}
    case HasLegacyProposalContents:
			wContent = append(wContent, xm.ProposalContents(simState)...)
}
	
}
    oReg := NewSimsMsgRegistryAdapter(
		reporter,
		stateFact.AccountSource,
		stateFact.BalanceSource,
		txConfig,
		logger,
	)
    wOps := make([]simtypes.WeightedOperation, 0, len(sm.Modules))
    for _, m := range sm.Modules {
		/ add operations
    switch xm := m.(type) {
    case HasWeightedOperationsX:
			xm.WeightedOperationsX(weights, oReg)
    case HasWeightedOperationsXWithProposals:
			xm.WeightedOperationsX(weights, oReg, AppendIterators(legacyPReg.Iterator(), pReg.Iterator()), wContent)
    case HasLegacyWeightedOperations:
			wOps = append(wOps, xm.WeightedOperations(simState)...)
}
	
}

return append(wOps, Collect(oReg.items, func(a weightedOperation)

simtypes.WeightedOperation {
    return a
})...), reporter
}

func safeUint(p int)

uint32 {
    if p < 0 || p > math.MaxUint32 {
    panic(fmt.Sprintf("can not cast to uint32: %d", p))
}

return uint32(p)
}

/ NewSimulationAppInstance initializes and returns a TestInstance of a SimulationApp.
/ The function takes a testing.T instance, a simtypes.Config instance, and an appFactory function as parameters.
/ It creates a temporary working directory and a LevelDB database for the simulation app.
/ The function then initializes a logger based on the verbosity flag and sets the logger's seed to the test configuration's seed.
/ The database is closed and cleaned up on test completion.
func NewSimulationAppInstance[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	tCfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
)

TestInstance[T] {
    tb.Helper()
    workDir := tb.TempDir()

require.NoError(tb, os.Mkdir(filepath.Join(workDir, "data"), 0o750))
    dbDir := filepath.Join(workDir, "leveldb-app-sim")

var logger log.Logger
    if cli.FlagVerboseValue {
    logger = log.NewTestLogger(tb)
}

else {
    logger = log.NewTestLoggerError(tb)
}

logger = logger.With("seed", tCfg.Seed)

db, err := dbm.NewDB("Simulation", dbm.BackendType(tCfg.DBBackend), dbDir)

require.NoError(tb, err)

tb.Cleanup(func() {
		_ = db.Close() / ensure db is closed
})
    appOptions := make(simtestutil.AppOptionsMap)

appOptions[flags.FlagHome] = workDir
    opts := []func(*baseapp.BaseApp) {
    baseapp.SetChainID(tCfg.ChainID)
}
    if tCfg.FauxMerkle {
    opts = append(opts, FauxMerkleModeOpt)
}
    app := appFactory(logger, db, nil, true, appOptions, opts...)
    if !cli.FlagSigverifyTxValue {
    app.SetNotSigverifyTx()
}

return TestInstance[T]{
    App:           app,
    DB:            db,
    WorkDir:       workDir,
    Cfg:           tCfg,
    AppLogger:     logger,
    ExecLogWriter: &simulation.StandardLogWriter{
    Seed: tCfg.Seed
},
}
}

var _ io.Writer = writerFn(nil)

type writerFn func(p []byte) (n int, err error)

func (w writerFn)

Write(p []byte) (n int, err error) {
    return w(p)
}

/ WriteToDebugLog is an adapter to io.Writer interface
func WriteToDebugLog(logger log.Logger)

io.Writer {
    return writerFn(func(p []byte) (n int, err error) {
    logger.Debug(string(p))

return len(p), nil
})
}

/ FauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
/ an IAVLStore for faster simulation speed.
func FauxMerkleModeOpt(bapp *baseapp.BaseApp) {
    bapp.SetFauxMerkleMode()
}
These methods allow constructing randomized messages and/or proposal messages.
Note that modules should not implement both HasWeightedOperationsX and HasWeightedOperationsXWithProposals. See the runner code here for detailsIf the module does not have message handlers or governance proposal handlers, these interface methods do not need to be implemented.

Example Implementations

  • HasWeightedOperationsXWithProposals: x/gov
  • HasWeightedOperationsX: x/bank
  • HasProposalMsgsX: x/bank

Store decoders

Registering the store decoders is required for the AppImportExport simulation. This allows for the key-value pairs from the stores to be decoded to their corresponding types. In particular, it matches the key to a concrete type and then unmarshals the value from the KVPair to the type provided. Modules using collections can use the NewStoreDecoderFuncFromCollectionsSchema function that builds the decoder for you:
package bank

import (
    
	"context"
    "encoding/json"
    "fmt"
    "maps"
    "slices"
    "sort"

	gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "github.com/spf13/cobra"

	modulev1 "cosmossdk.io/api/cosmos/bank/module/v1"
    "cosmossdk.io/core/address"
    "cosmossdk.io/core/appmodule"
	corestore "cosmossdk.io/core/store"
    "cosmossdk.io/depinject"
    "cosmossdk.io/log"
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/codec"
	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    "github.com/cosmos/cosmos-sdk/testutil/simsx"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/types/module"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
    "github.com/cosmos/cosmos-sdk/x/bank/exported"
    "github.com/cosmos/cosmos-sdk/x/bank/keeper"
	v1bank "github.com/cosmos/cosmos-sdk/x/bank/migrations/v1"
    "github.com/cosmos/cosmos-sdk/x/bank/simulation"
    "github.com/cosmos/cosmos-sdk/x/bank/types"
	govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)

/ ConsensusVersion defines the current x/bank module consensus version.
const ConsensusVersion = 4

var (
	_ module.AppModuleBasic      = AppModule{
}
	_ module.AppModuleSimulation = AppModule{
}
	_ module.HasGenesis          = AppModule{
}
	_ module.HasServices         = AppModule{
}

	_ appmodule.AppModule = AppModule{
}
)

/ AppModuleBasic defines the basic application module used by the bank module.
type AppModuleBasic struct {
    cdc codec.Codec
	ac  address.Codec
}

/ Name returns the bank module's name.
func (AppModuleBasic)

Name()

string {
    return types.ModuleName
}

/ RegisterLegacyAminoCodec registers the bank module's types on the LegacyAmino codec.
func (AppModuleBasic)

RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
    types.RegisterLegacyAminoCodec(cdc)
}

/ DefaultGenesis returns default genesis state as raw bytes for the bank
/ module.
func (AppModuleBasic)

DefaultGenesis(cdc codec.JSONCodec)

json.RawMessage {
    return cdc.MustMarshalJSON(types.DefaultGenesisState())
}

/ ValidateGenesis performs genesis state validation for the bank module.
func (AppModuleBasic)

ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage)

error {
    var data types.GenesisState
    if err := cdc.UnmarshalJSON(bz, &data); err != nil {
    return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}

return data.Validate()
}

/ RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the bank module.
func (AppModuleBasic)

RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *gwruntime.ServeMux) {
    if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil {
    panic(err)
}
}

/ GetTxCmd returns the root tx command for the bank module.
func (ab AppModuleBasic)

GetTxCmd() *cobra.Command {
    return cli.NewTxCmd(ab.ac)
}

/ RegisterInterfaces registers interfaces and implementations of the bank module.
func (AppModuleBasic)

RegisterInterfaces(registry codectypes.InterfaceRegistry) {
    types.RegisterInterfaces(registry)

	/ Register legacy interfaces for migration scripts.
	v1bank.RegisterInterfaces(registry)
}

/ AppModule implements an application module for the bank module.
type AppModule struct {
    AppModuleBasic

	keeper        keeper.Keeper
	accountKeeper types.AccountKeeper

	/ legacySubspace is used solely for migration of x/params managed parameters
	legacySubspace exported.Subspace
}

/ IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (am AppModule)

IsOnePerModuleType() {
}

/ IsAppModule implements the appmodule.AppModule interface.
func (am AppModule)

IsAppModule() {
}

/ RegisterServices registers module services.
func (am AppModule)

RegisterServices(cfg module.Configurator) {
    types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))

types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
    m := keeper.NewMigrator(am.keeper.(keeper.BaseKeeper), am.legacySubspace)
    if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil {
    panic(fmt.Sprintf("failed to migrate x/bank from version 1 to 2: %v", err))
}
    if err := cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3); err != nil {
    panic(fmt.Sprintf("failed to migrate x/bank from version 2 to 3: %v", err))
}
    if err := cfg.RegisterMigration(types.ModuleName, 3, m.Migrate3to4); err != nil {
    panic(fmt.Sprintf("failed to migrate x/bank from version 3 to 4: %v", err))
}
}

/ NewAppModule creates a new AppModule object
func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.AccountKeeper, ss exported.Subspace)

AppModule {
    return AppModule{
    AppModuleBasic: AppModuleBasic{
    cdc: cdc, ac: accountKeeper.AddressCodec()
},
		keeper:         keeper,
		accountKeeper:  accountKeeper,
		legacySubspace: ss,
}
}

/ QuerierRoute returns the bank module's querier route name.
func (AppModule)

QuerierRoute()

string {
    return types.RouterKey
}

/ InitGenesis performs genesis initialization for the bank module. It returns
/ no validator updates.
func (am AppModule)

InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) {
    var genesisState types.GenesisState
	cdc.MustUnmarshalJSON(data, &genesisState)

am.keeper.InitGenesis(ctx, &genesisState)
}

/ ExportGenesis returns the exported genesis state as raw bytes for the bank
/ module.
func (am AppModule)

ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec)

json.RawMessage {
    gs := am.keeper.ExportGenesis(ctx)

return cdc.MustMarshalJSON(gs)
}

/ ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule)

ConsensusVersion()

uint64 {
    return ConsensusVersion
}

/ AppModuleSimulation functions

/ GenerateGenesisState creates a randomized GenState of the bank module.
func (AppModule)

GenerateGenesisState(simState *module.SimulationState) {
    simulation.RandomizedGenState(simState)
}

/ ProposalMsgs returns msgs used for governance proposals for simulations.
/ migrate to ProposalMsgsX. This method is ignored when ProposalMsgsX exists and will be removed in the future.
func (AppModule)

ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg {
    return simulation.ProposalMsgs()
}

/ RegisterStoreDecoder registers a decoder for supply module's types
func (am AppModule)

RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) {
    sdr[types.StoreKey] = simtypes.NewStoreDecoderFuncFromCollectionsSchema(am.keeper.(keeper.BaseKeeper).Schema)
}

/ WeightedOperations returns the all the bank module operations with their respective weights.
/ migrate to WeightedOperationsX. This method is ignored when WeightedOperationsX exists and will be removed in the future
func (am AppModule)

WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
    return simulation.WeightedOperations(
		simState.AppParams, simState.Cdc, simState.TxConfig, am.accountKeeper, am.keeper,
	)
}

/ ProposalMsgsX registers governance proposal messages in the simulation registry.
func (AppModule)

ProposalMsgsX(weights simsx.WeightSource, reg simsx.Registry) {
    reg.Add(weights.Get("msg_update_params", 100), simulation.MsgUpdateParamsFactory())
}

/ WeightedOperationsX registers weighted bank module operations for simulation.
func (am AppModule)

WeightedOperationsX(weights simsx.WeightSource, reg simsx.Registry) {
    reg.Add(weights.Get("msg_send", 100), simulation.MsgSendFactory())

reg.Add(weights.Get("msg_multisend", 10), simulation.MsgMultiSendFactory())
}

/ App Wiring Setup

func init() {
    appmodule.Register(
		&modulev1.Module{
},
		appmodule.Provide(ProvideModule),
		appmodule.Invoke(InvokeSetSendRestrictions),
	)
}

type ModuleInputs struct {
    depinject.In

	Config       *modulev1.Module
	Cdc          codec.Codec
	StoreService corestore.KVStoreService
	Logger       log.Logger

	AccountKeeper types.AccountKeeper

	/ LegacySubspace is used solely for migration of x/params managed parameters
	LegacySubspace exported.Subspace `optional:"true"`
}

type ModuleOutputs struct {
    depinject.Out

	BankKeeper keeper.BaseKeeper
	Module     appmodule.AppModule
}

func ProvideModule(in ModuleInputs)

ModuleOutputs {
	/ Configure blocked module accounts.
	/
	/ Default behavior for blockedAddresses is to regard any module mentioned in
	/ AccountKeeper's module account permissions as blocked.
    blockedAddresses := make(map[string]bool)
    if len(in.Config.BlockedModuleAccountsOverride) > 0 {
    for _, moduleName := range in.Config.BlockedModuleAccountsOverride {
    blockedAddresses[authtypes.NewModuleAddress(moduleName).String()] = true
}
	
}

else {
    for _, permission := range in.AccountKeeper.GetModulePermissions() {
    blockedAddresses[permission.GetAddress().String()] = true
}
	
}

	/ default to governance authority if not provided
    authority := authtypes.NewModuleAddress(govtypes.ModuleName)
    if in.Config.Authority != "" {
    authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority)
}
    bankKeeper := keeper.NewBaseKeeper(
		in.Cdc,
		in.StoreService,
		in.AccountKeeper,
		blockedAddresses,
		authority.String(),
		in.Logger,
	)
    m := NewAppModule(in.Cdc, bankKeeper, in.AccountKeeper, in.LegacySubspace)

return ModuleOutputs{
    BankKeeper: bankKeeper,
    Module: m
}
}

func InvokeSetSendRestrictions(
	config *modulev1.Module,
	keeper keeper.BaseKeeper,
	restrictions map[string]types.SendRestrictionFn,
)

error {
    if config == nil {
    return nil
}
    modules := slices.Collect(maps.Keys(restrictions))
    order := config.RestrictionsOrder
    if len(order) == 0 {
    order = modules
		sort.Strings(order)
}
    if len(order) != len(modules) {
    return fmt.Errorf("len(restrictions order: %v) != len(restriction modules: %v)", order, modules)
}
    if len(modules) == 0 {
    return nil
}
    for _, module := range order {
    restriction, ok := restrictions[module]
    if !ok {
    return fmt.Errorf("can't find send restriction for module %s", module)
}

keeper.AppendSendRestriction(restriction)
}

return nil
}
Modules not using collections must manually build the store decoder. See the implementation here from the distribution module for an example.

Randomized genesis

The simulator tests different scenarios and values for genesis parameters. App modules must implement a GenerateGenesisState method to generate the initial random GenesisState from a given seed.
package module

import (
    
	"encoding/json"
    "math/rand"
    "sort"
    "time"

	sdkmath "cosmossdk.io/math"
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/types/simulation"
)

/ AppModuleSimulation defines the standard functions that every module should expose
/ for the SDK blockchain simulator
type AppModuleSimulation interface {
	/ randomized genesis states
	GenerateGenesisState(input *SimulationState)

	/ register a func to decode the each module's defined types from their corresponding store key
	RegisterStoreDecoder(simulation.StoreDecoderRegistry)

	/ simulation operations (i.e msgs)

with their respective weight
	WeightedOperations(simState SimulationState) []simulation.WeightedOperation
}

/ HasProposalMsgs defines the messages that can be used to simulate governance (v1)

proposals
type HasProposalMsgs interface {
	/ msg functions used to simulate governance proposals
	ProposalMsgs(simState SimulationState) []simulation.WeightedProposalMsg
}

/ HasProposalContents defines the contents that can be used to simulate legacy governance (v1beta1)

proposals
type HasProposalContents interface {
	/ content functions used to simulate governance proposals
	ProposalContents(simState SimulationState) []simulation.WeightedProposalContent /nolint:staticcheck / legacy v1beta1 governance
}

/ SimulationManager defines a simulation manager that provides the high level utility
/ for managing and executing simulation functionalities for a group of modules
type SimulationManager struct {
    Modules       []AppModuleSimulation           / array of app modules; we use an array for deterministic simulation tests
	StoreDecoders simulation.StoreDecoderRegistry / functions to decode the key-value pairs from each module's store
}

/ NewSimulationManager creates a new SimulationManager object
/
/ CONTRACT: All the modules provided must be also registered on the module Manager
func NewSimulationManager(modules ...AppModuleSimulation) *SimulationManager {
    return &SimulationManager{
    Modules:       modules,
    StoreDecoders: make(simulation.StoreDecoderRegistry),
}
}

/ NewSimulationManagerFromAppModules creates a new SimulationManager object.
/
/ First it sets any SimulationModule provided by overrideModules, and ignores any AppModule
/ with the same moduleName.
/ Then it attempts to cast every provided AppModule into an AppModuleSimulation.
/ If the cast succeeds, its included, otherwise it is excluded.
func NewSimulationManagerFromAppModules(modules map[string]any, overrideModules map[string]AppModuleSimulation) *SimulationManager {
    simModules := []AppModuleSimulation{
}
    appModuleNamesSorted := make([]string, 0, len(modules))
    for moduleName := range modules {
    appModuleNamesSorted = append(appModuleNamesSorted, moduleName)
}

sort.Strings(appModuleNamesSorted)
    for _, moduleName := range appModuleNamesSorted {
		/ for every module, see if we override it. If so, use override.
		/ Else, if we can cast the app module into a simulation module add it.
		/ otherwise no simulation module.
    if simModule, ok := overrideModules[moduleName]; ok {
    simModules = append(simModules, simModule)
}

else {
    appModule := modules[moduleName]
    if simModule, ok := appModule.(AppModuleSimulation); ok {
    simModules = append(simModules, simModule)
}
			/ cannot cast, so we continue
}
	
}

return NewSimulationManager(simModules...)
}

/ Deprecated: Use GetProposalMsgs instead.
/ GetProposalContents returns each module's proposal content generator function
/ with their default operation weight and key.
func (sm *SimulationManager)

GetProposalContents(simState SimulationState) []simulation.WeightedProposalContent {
    wContents := make([]simulation.WeightedProposalContent, 0, len(sm.Modules))
    for _, module := range sm.Modules {
    if module, ok := module.(HasProposalContents); ok {
    wContents = append(wContents, module.ProposalContents(simState)...)
}
	
}

return wContents
}

/ GetProposalMsgs returns each module's proposal msg generator function
/ with their default operation weight and key.
func (sm *SimulationManager)

GetProposalMsgs(simState SimulationState) []simulation.WeightedProposalMsg {
    wContents := make([]simulation.WeightedProposalMsg, 0, len(sm.Modules))
    for _, module := range sm.Modules {
    if module, ok := module.(HasProposalMsgs); ok {
    wContents = append(wContents, module.ProposalMsgs(simState)...)
}
	
}

return wContents
}

/ RegisterStoreDecoders registers each of the modules' store decoders into a map
func (sm *SimulationManager)

RegisterStoreDecoders() {
    for _, module := range sm.Modules {
    module.RegisterStoreDecoder(sm.StoreDecoders)
}
}

/ GenerateGenesisStates generates a randomized GenesisState for each of the
/ registered modules
func (sm *SimulationManager)

GenerateGenesisStates(simState *SimulationState) {
    for _, module := range sm.Modules {
    module.GenerateGenesisState(simState)
}
}

/ WeightedOperations returns all the modules' weighted operations of an application
func (sm *SimulationManager)

WeightedOperations(simState SimulationState) []simulation.WeightedOperation {
    wOps := make([]simulation.WeightedOperation, 0, len(sm.Modules))
    for _, module := range sm.Modules {
    wOps = append(wOps, module.WeightedOperations(simState)...)
}

return wOps
}

/ SimulationState is the input parameters used on each of the module's randomized
/ GenesisState generator function
type SimulationState struct {
    AppParams         simulation.AppParams
	Cdc               codec.JSONCodec                / application codec
	TxConfig          client.TxConfig                / Shared TxConfig; this is expensive to create and stateless, so create it once up front.
	Rand              *rand.Rand                     / random number
	GenState          map[string]json.RawMessage     / genesis state
	Accounts          []simulation.Account           / simulation accounts
	InitialStake      sdkmath.Int                    / initial coins per account
	NumBonded         int64                          / number of initially bonded accounts
	BondDenom         string                         / denom to be used as default
	GenTimestamp      time.Time                      / genesis timestamp
	UnbondTime        time.Duration                  / staking unbond time stored to use it as the slashing maximum evidence duration
	LegacyParamChange []simulation.LegacyParamChange / simulated parameter changes from modules
	/nolint:staticcheck /	legacy used for testing
	LegacyProposalContents []simulation.WeightedProposalContent / proposal content generator functions with their default weight and app sim key
	ProposalMsgs           []simulation.WeightedProposalMsg     / proposal msg generator functions with their default weight and app sim key
}
See an example from x/auth here. Once the module’s genesis parameters are generated randomly (or with the key and values defined in a params file), they are marshaled to JSON format and added to the app genesis JSON for the simulation.

Random weighted operations

Operations are one of the crucial parts of the Cosmos SDK simulation. They are the transactions (Msg) that are simulated with random field values. The sender of the operation is also assigned randomly. Operations on the simulation are simulated using the full transaction cycle of a ABCI application that exposes the BaseApp.

Using Simsx

Simsx introduces the ability to define a MsgFactory for each of a module’s messages. These factories are registered in WeightedOperationsX and/or ProposalMsgsX.
package distribution

import (
    
	"context"
    "encoding/json"
    "fmt"

	gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "github.com/spf13/cobra"

	modulev1 "cosmossdk.io/api/cosmos/distribution/module/v1"
    "cosmossdk.io/core/address"
    "cosmossdk.io/core/appmodule"
    "cosmossdk.io/core/store"
    "cosmossdk.io/depinject"

	sdkclient "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/codec"
	cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
    "github.com/cosmos/cosmos-sdk/testutil/simsx"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/types/module"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    "github.com/cosmos/cosmos-sdk/x/distribution/client/cli"
    "github.com/cosmos/cosmos-sdk/x/distribution/exported"
    "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
    "github.com/cosmos/cosmos-sdk/x/distribution/simulation"
    "github.com/cosmos/cosmos-sdk/x/distribution/types"
	govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
	staking "github.com/cosmos/cosmos-sdk/x/staking/types"
)

/ ConsensusVersion defines the current x/distribution module consensus version.
const ConsensusVersion = 3

var (
	_ module.AppModuleBasic      = AppModule{
}
	_ module.AppModuleSimulation = AppModule{
}
	_ module.HasGenesis          = AppModule{
}
	_ module.HasServices         = AppModule{
}

	_ appmodule.AppModule       = AppModule{
}
	_ appmodule.HasBeginBlocker = AppModule{
}
)

/ AppModuleBasic defines the basic application module used by the distribution module.
type AppModuleBasic struct {
    cdc codec.Codec
	ac  address.Codec
}

/ Name returns the distribution module's name.
func (AppModuleBasic)

Name()

string {
    return types.ModuleName
}

/ RegisterLegacyAminoCodec registers the distribution module's types for the given codec.
func (AppModuleBasic)

RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
    types.RegisterLegacyAminoCodec(cdc)
}

/ DefaultGenesis returns default genesis state as raw bytes for the distribution
/ module.
func (AppModuleBasic)

DefaultGenesis(cdc codec.JSONCodec)

json.RawMessage {
    return cdc.MustMarshalJSON(types.DefaultGenesisState())
}

/ ValidateGenesis performs genesis state validation for the distribution module.
func (AppModuleBasic)

ValidateGenesis(cdc codec.JSONCodec, _ sdkclient.TxEncodingConfig, bz json.RawMessage)

error {
    var data types.GenesisState
    if err := cdc.UnmarshalJSON(bz, &data); err != nil {
    return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}

return types.ValidateGenesis(&data)
}

/ RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the distribution module.
func (AppModuleBasic)

RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *gwruntime.ServeMux) {
    if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil {
    panic(err)
}
}

/ GetTxCmd returns the root tx command for the distribution module.
func (ab AppModuleBasic)

GetTxCmd() *cobra.Command {
    return cli.NewTxCmd(ab.cdc.InterfaceRegistry().SigningContext().ValidatorAddressCodec(), ab.cdc.InterfaceRegistry().SigningContext().AddressCodec())
}

/ RegisterInterfaces implements InterfaceModule
func (AppModuleBasic)

RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
    types.RegisterInterfaces(registry)
}

/ AppModule implements an application module for the distribution module.
type AppModule struct {
    AppModuleBasic

	keeper        keeper.Keeper
	accountKeeper types.AccountKeeper
	bankKeeper    types.BankKeeper
	stakingKeeper types.StakingKeeper

	/ legacySubspace is used solely for migration of x/params managed parameters
	legacySubspace exported.Subspace
}

/ NewAppModule creates a new AppModule object
func NewAppModule(
	cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.AccountKeeper,
	bankKeeper types.BankKeeper, stakingKeeper types.StakingKeeper, ss exported.Subspace,
)

AppModule {
    return AppModule{
    AppModuleBasic: AppModuleBasic{
    cdc: cdc, ac: accountKeeper.AddressCodec()
},
		keeper:         keeper,
		accountKeeper:  accountKeeper,
		bankKeeper:     bankKeeper,
		stakingKeeper:  stakingKeeper,
		legacySubspace: ss,
}
}

/ IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (am AppModule)

IsOnePerModuleType() {
}

/ IsAppModule implements the appmodule.AppModule interface.
func (am AppModule)

IsAppModule() {
}

/ RegisterServices registers module services.
func (am AppModule)

RegisterServices(cfg module.Configurator) {
    types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))

types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper))
    m := keeper.NewMigrator(am.keeper, am.legacySubspace)
    if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil {
    panic(fmt.Sprintf("failed to migrate x/%s from version 1 to 2: %v", types.ModuleName, err))
}
    if err := cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3); err != nil {
    panic(fmt.Sprintf("failed to migrate x/%s from version 2 to 3: %v", types.ModuleName, err))
}
}

/ InitGenesis performs genesis initialization for the distribution module. It returns
/ no validator updates.
func (am AppModule)

InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) {
    var genesisState types.GenesisState
	cdc.MustUnmarshalJSON(data, &genesisState)

am.keeper.InitGenesis(ctx, genesisState)
}

/ ExportGenesis returns the exported genesis state as raw bytes for the distribution
/ module.
func (am AppModule)

ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec)

json.RawMessage {
    gs := am.keeper.ExportGenesis(ctx)

return cdc.MustMarshalJSON(gs)
}

/ ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule)

ConsensusVersion()

uint64 {
    return ConsensusVersion
}

/ BeginBlock returns the begin blocker for the distribution module.
func (am AppModule)

BeginBlock(ctx context.Context)

error {
    c := sdk.UnwrapSDKContext(ctx)

return BeginBlocker(c, am.keeper)
}

/ AppModuleSimulation functions

/ GenerateGenesisState creates a randomized GenState of the distribution module.
func (AppModule)

GenerateGenesisState(simState *module.SimulationState) {
    simulation.RandomizedGenState(simState)
}

/ ProposalMsgs returns msgs used for governance proposals for simulations.
/ migrate to ProposalMsgsX. This method is ignored when ProposalMsgsX exists and will be removed in the future.
func (AppModule)

ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg {
    return simulation.ProposalMsgs()
}

/ RegisterStoreDecoder registers a decoder for distribution module's types
func (am AppModule)

RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) {
    sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
}

/ WeightedOperations returns the all the gov module operations with their respective weights.
/ migrate to WeightedOperationsX. This method is ignored when WeightedOperationsX exists and will be removed in the future
func (am AppModule)

WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
    return simulation.WeightedOperations(
		simState.AppParams, simState.Cdc, simState.TxConfig,
		am.accountKeeper, am.bankKeeper, am.keeper, am.stakingKeeper,
	)
}

/ ProposalMsgsX registers governance proposal messages in the simulation registry.
func (AppModule)

ProposalMsgsX(weights simsx.WeightSource, reg simsx.Registry) {
    reg.Add(weights.Get("msg_update_params", 100), simulation.MsgUpdateParamsFactory())
}

/ WeightedOperationsX registers weighted distribution module operations for simulation.
func (am AppModule)

WeightedOperationsX(weights simsx.WeightSource, reg simsx.Registry) {
    reg.Add(weights.Get("msg_set_withdraw_address", 50), simulation.MsgSetWithdrawAddressFactory(am.keeper))

reg.Add(weights.Get("msg_withdraw_delegation_reward", 50), simulation.MsgWithdrawDelegatorRewardFactory(am.keeper, am.stakingKeeper))

reg.Add(weights.Get("msg_withdraw_validator_commission", 50), simulation.MsgWithdrawValidatorCommissionFactory(am.keeper, am.stakingKeeper))
}

/
/ App Wiring Setup
/

func init() {
    appmodule.Register(&modulev1.Module{
},
		appmodule.Provide(ProvideModule),
	)
}

type ModuleInputs struct {
    depinject.In

	Config       *modulev1.Module
	StoreService store.KVStoreService
	Cdc          codec.Codec

	AccountKeeper      types.AccountKeeper
	BankKeeper         types.BankKeeper
	StakingKeeper      types.StakingKeeper
	ExternalPoolKeeper types.ExternalCommunityPoolKeeper `optional:"true"`

	/ LegacySubspace is used solely for migration of x/params managed parameters
	LegacySubspace exported.Subspace `optional:"true"`
}

type ModuleOutputs struct {
    depinject.Out

	DistrKeeper keeper.Keeper
	Module      appmodule.AppModule
	Hooks       staking.StakingHooksWrapper
}

func ProvideModule(in ModuleInputs)

ModuleOutputs {
    feeCollectorName := in.Config.FeeCollectorName
    if feeCollectorName == "" {
    feeCollectorName = authtypes.FeeCollectorName
}

	/ default to governance authority if not provided
    authority := authtypes.NewModuleAddress(govtypes.ModuleName)
    if in.Config.Authority != "" {
    authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority)
}

var opts []keeper.InitOption
    if in.ExternalPoolKeeper != nil {
    opts = append(opts, keeper.WithExternalCommunityPool(in.ExternalPoolKeeper))
}
    k := keeper.NewKeeper(
		in.Cdc,
		in.StoreService,
		in.AccountKeeper,
		in.BankKeeper,
		in.StakingKeeper,
		feeCollectorName,
		authority.String(),
		opts...,
	)
    m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.BankKeeper, in.StakingKeeper, in.LegacySubspace)

return ModuleOutputs{
    DistrKeeper: k,
    Module:      m,
    Hooks:       staking.StakingHooksWrapper{
    StakingHooks: k.Hooks()
},
}
}
Note that the name passed in to weights.Get must match the name of the operation set in the WeightedOperations. For example, if the module contains an operation op_weight_msg_set_withdraw_address, the name passed to weights.Get should be msg_set_withdraw_address. See the x/distribution for an example of implementing message factories here

App Simulator manager

The following step is setting up the SimulatorManager at the app level. This is required for the simulation test files in the next step.
type CoolApp struct {
...
sm *module.SimulationManager
}
Within the constructor of the application, construct the simulation manager using the modules from ModuleManager and call the RegisterStoreDecoders method.
/go:build app_v1

package simapp

import (
    
	"encoding/json"
    "fmt"
    "io"
    "maps"

	abci "github.com/cometbft/cometbft/abci/types"
	dbm "github.com/cosmos/cosmos-db"
    "github.com/cosmos/gogoproto/proto"
    "github.com/spf13/cast"

	autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
	reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
    "cosmossdk.io/client/v2/autocli"
	clienthelpers "cosmossdk.io/client/v2/helpers"
    "cosmossdk.io/core/appmodule"
    "cosmossdk.io/log"
	storetypes "cosmossdk.io/store/types"
    "cosmossdk.io/x/tx/signing"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/client/flags"
    "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
	nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/codec/address"
    "github.com/cosmos/cosmos-sdk/codec/types"
    "github.com/cosmos/cosmos-sdk/runtime"
	runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services"
    "github.com/cosmos/cosmos-sdk/server"
    "github.com/cosmos/cosmos-sdk/server/api"
    "github.com/cosmos/cosmos-sdk/server/config"
	servertypes "github.com/cosmos/cosmos-sdk/server/types"
    "github.com/cosmos/cosmos-sdk/std"
	testdata_pulsar "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/types/module"
	sigtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
    "github.com/cosmos/cosmos-sdk/version"
    "github.com/cosmos/cosmos-sdk/x/auth"
    "github.com/cosmos/cosmos-sdk/x/auth/ante"
	authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec"
	authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
    "github.com/cosmos/cosmos-sdk/x/auth/posthandler"
	authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
    "github.com/cosmos/cosmos-sdk/x/auth/tx"
	authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
	txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    "github.com/cosmos/cosmos-sdk/x/auth/vesting"
	vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
    "github.com/cosmos/cosmos-sdk/x/authz"
	authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
	authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module"
    "github.com/cosmos/cosmos-sdk/x/bank"
	bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
	consensus "github.com/cosmos/cosmos-sdk/x/consensus"
	consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper"
	consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types"
	distr "github.com/cosmos/cosmos-sdk/x/distribution"
	distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
	distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
    "github.com/cosmos/cosmos-sdk/x/epochs"
	epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
	epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
    "github.com/cosmos/cosmos-sdk/x/evidence"
	evidencekeeper "github.com/cosmos/cosmos-sdk/x/evidence/keeper"
	evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
    "github.com/cosmos/cosmos-sdk/x/feegrant"
	feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper"
	feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module"
    "github.com/cosmos/cosmos-sdk/x/genutil"
	genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
    "github.com/cosmos/cosmos-sdk/x/gov"
	govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
	govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
	govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
	govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
    "github.com/cosmos/cosmos-sdk/x/mint"
	mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
    "github.com/cosmos/cosmos-sdk/x/protocolpool"
	protocolpoolkeeper "github.com/cosmos/cosmos-sdk/x/protocolpool/keeper"
	protocolpooltypes "github.com/cosmos/cosmos-sdk/x/protocolpool/types"
    "github.com/cosmos/cosmos-sdk/x/slashing"
	slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper"
	slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
    "github.com/cosmos/cosmos-sdk/x/staking"
	stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
    "github.com/cosmos/cosmos-sdk/x/upgrade"
	upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
	upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)

const appName = "SimApp"

var (
	/ DefaultNodeHome default home directories for the application daemon
	DefaultNodeHome string

	/ module account permissions
	maccPerms = map[string][]string{
    authtypes.FeeCollectorName:                  nil,
		distrtypes.ModuleName:                       nil,
		minttypes.ModuleName:                        {
    authtypes.Minter
},
		stakingtypes.BondedPoolName:                 {
    authtypes.Burner, authtypes.Staking
},
		stakingtypes.NotBondedPoolName:              {
    authtypes.Burner, authtypes.Staking
},
		govtypes.ModuleName:                         {
    authtypes.Burner
},
		protocolpooltypes.ModuleName:                nil,
		protocolpooltypes.ProtocolPoolEscrowAccount: nil
}
)

var (
	_ runtime.AppI            = (*SimApp)(nil)
	_ servertypes.Application = (*SimApp)(nil)
)

/ SimApp extends an ABCI application, but with most of its parameters exported.
/ They are exported for convenience in creating helper functions, as object
/ capabilities aren't needed for testing.
type SimApp struct {
	*baseapp.BaseApp
	legacyAmino       *codec.LegacyAmino
	appCodec          codec.Codec
	txConfig          client.TxConfig
	interfaceRegistry types.InterfaceRegistry

	/ keys to access the substores
	keys map[string]*storetypes.KVStoreKey

	/ essential keepers
	AccountKeeper         authkeeper.AccountKeeper
	BankKeeper            bankkeeper.BaseKeeper
	StakingKeeper         *stakingkeeper.Keeper
	SlashingKeeper        slashingkeeper.Keeper
	MintKeeper            mintkeeper.Keeper
	DistrKeeper           distrkeeper.Keeper
	GovKeeper             govkeeper.Keeper
	UpgradeKeeper         *upgradekeeper.Keeper
	EvidenceKeeper        evidencekeeper.Keeper
	ConsensusParamsKeeper consensusparamkeeper.Keeper

	/ supplementary keepers
	FeeGrantKeeper     feegrantkeeper.Keeper
	AuthzKeeper        authzkeeper.Keeper
	EpochsKeeper       epochskeeper.Keeper
	ProtocolPoolKeeper protocolpoolkeeper.Keeper

	/ the module manager
	ModuleManager      *module.Manager
	BasicModuleManager module.BasicManager

	/ simulation manager
	sm *module.SimulationManager

	/ module configurator
	configurator module.Configurator
}

func init() {
    var err error
	DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".simapp")
    if err != nil {
    panic(err)
}
}

/ NewSimApp returns a reference to an initialized SimApp.
func NewSimApp(
	logger log.Logger,
	db dbm.DB,
	traceStore io.Writer,
	loadLatest bool,
	appOpts servertypes.AppOptions,
	baseAppOptions ...func(*baseapp.BaseApp),
) *SimApp {
    interfaceRegistry, _ := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{
    ProtoFiles: proto.HybridResolver,
    SigningOptions: signing.Options{
    AddressCodec: address.Bech32Codec{
    Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(),
},
    ValidatorAddressCodec: address.Bech32Codec{
    Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(),
},
},
})
    appCodec := codec.NewProtoCodec(interfaceRegistry)
    legacyAmino := codec.NewLegacyAmino()
    txConfig := tx.NewTxConfig(appCodec, tx.DefaultSignModes)
    if err := interfaceRegistry.SigningContext().Validate(); err != nil {
    panic(err)
}

std.RegisterLegacyAminoCodec(legacyAmino)

std.RegisterInterfaces(interfaceRegistry)

	/ Below we could construct and set an application specific mempool and
	/ ABCI 1.0 PrepareProposal and ProcessProposal handlers. These defaults are
	/ already set in the SDK's BaseApp, this shows an example of how to override
	/ them.
	/
	/ Example:
	/
	/ bApp := baseapp.NewBaseApp(...)
	/ nonceMempool := mempool.NewSenderNonceMempool()
	/ abciPropHandler := NewDefaultProposalHandler(nonceMempool, bApp)
	/
	/ bApp.SetMempool(nonceMempool)
	/ bApp.SetPrepareProposal(abciPropHandler.PrepareProposalHandler())
	/ bApp.SetProcessProposal(abciPropHandler.ProcessProposalHandler())
	/
	/ Alternatively, you can construct BaseApp options, append those to
	/ baseAppOptions and pass them to NewBaseApp.
	/
	/ Example:
	/
	/ prepareOpt = func(app *baseapp.BaseApp) {
	/ 	abciPropHandler := baseapp.NewDefaultProposalHandler(nonceMempool, app)
	/ 	app.SetPrepareProposal(abciPropHandler.PrepareProposalHandler())
	/
}
	/ baseAppOptions = append(baseAppOptions, prepareOpt)

	/ create and set dummy vote extension handler
    voteExtOp := func(bApp *baseapp.BaseApp) {
    voteExtHandler := NewVoteExtensionHandler()

voteExtHandler.SetHandlers(bApp)
}

baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution())
    bApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), baseAppOptions...)

bApp.SetCommitMultiStoreTracer(traceStore)

bApp.SetVersion(version.Version)

bApp.SetInterfaceRegistry(interfaceRegistry)

bApp.SetTxEncoder(txConfig.TxEncoder())
    keys := storetypes.NewKVStoreKeys(
		authtypes.StoreKey,
		banktypes.StoreKey,
		stakingtypes.StoreKey,
		minttypes.StoreKey,
		distrtypes.StoreKey,
		slashingtypes.StoreKey,
		govtypes.StoreKey,
		consensusparamtypes.StoreKey,
		upgradetypes.StoreKey,
		feegrant.StoreKey,
		evidencetypes.StoreKey,
		authzkeeper.StoreKey,
		epochstypes.StoreKey,
		protocolpooltypes.StoreKey,
	)

	/ register streaming services
    if err := bApp.RegisterStreamingServices(appOpts, keys); err != nil {
    panic(err)
}
    app := &SimApp{
    BaseApp:           bApp,
		legacyAmino:       legacyAmino,
		appCodec:          appCodec,
		txConfig:          txConfig,
		interfaceRegistry: interfaceRegistry,
		keys:              keys,
}

	/ set the BaseApp's parameter store
	app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]),
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
		runtime.EventService{
},
	)

bApp.SetParamStore(app.ConsensusParamsKeeper.ParamsStore)

	/ add keepers
	app.AccountKeeper = authkeeper.NewAccountKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[authtypes.StoreKey]),
		authtypes.ProtoBaseAccount,
		maccPerms,
		authcodec.NewBech32Codec(sdk.Bech32MainPrefix),
		sdk.Bech32MainPrefix,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
		authkeeper.WithUnorderedTransactions(true),
	)

app.BankKeeper = bankkeeper.NewBaseKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[banktypes.StoreKey]),
		app.AccountKeeper,
		BlockedAddresses(),
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
		logger,
	)

	/ optional: enable sign mode textual by overwriting the default tx config (after setting the bank keeper)
    enabledSignModes := append(tx.DefaultSignModes, sigtypes.SignMode_SIGN_MODE_TEXTUAL)
    txConfigOpts := tx.ConfigOptions{
    EnabledSignModes:           enabledSignModes,
    TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(app.BankKeeper),
}

txConfig, err := tx.NewTxConfigWithOptions(
		appCodec,
		txConfigOpts,
	)
    if err != nil {
    panic(err)
}

app.txConfig = txConfig

	app.StakingKeeper = stakingkeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[stakingtypes.StoreKey]),
		app.AccountKeeper,
		app.BankKeeper,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
		authcodec.NewBech32Codec(sdk.Bech32PrefixValAddr),
		authcodec.NewBech32Codec(sdk.Bech32PrefixConsAddr),
	)

app.MintKeeper = mintkeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[minttypes.StoreKey]),
		app.StakingKeeper,
		app.AccountKeeper,
		app.BankKeeper,
		authtypes.FeeCollectorName,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
		/ mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(minttypes.DefaultInflationCalculationFn)), custom mintFn can be added here
	)

app.ProtocolPoolKeeper = protocolpoolkeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[protocolpooltypes.StoreKey]),
		app.AccountKeeper,
		app.BankKeeper,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
	)

app.DistrKeeper = distrkeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[distrtypes.StoreKey]),
		app.AccountKeeper,
		app.BankKeeper,
		app.StakingKeeper,
		authtypes.FeeCollectorName,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
		distrkeeper.WithExternalCommunityPool(app.ProtocolPoolKeeper),
	)

app.SlashingKeeper = slashingkeeper.NewKeeper(
		appCodec,
		legacyAmino,
		runtime.NewKVStoreService(keys[slashingtypes.StoreKey]),
		app.StakingKeeper,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
	)

app.FeeGrantKeeper = feegrantkeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[feegrant.StoreKey]),
		app.AccountKeeper,
	)

	/ register the staking hooks
	/ NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
	app.StakingKeeper.SetHooks(
		stakingtypes.NewMultiStakingHooks(
			app.DistrKeeper.Hooks(),
			app.SlashingKeeper.Hooks(),
		),
	)

app.AuthzKeeper = authzkeeper.NewKeeper(
		runtime.NewKVStoreService(keys[authzkeeper.StoreKey]),
		appCodec,
		app.MsgServiceRouter(),
		app.AccountKeeper,
	)

	/ get skipUpgradeHeights from the app options
    skipUpgradeHeights := map[int64]bool{
}
    for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) {
    skipUpgradeHeights[int64(h)] = true
}
    homePath := cast.ToString(appOpts.Get(flags.FlagHome))
	/ set the governance module account as the authority for conducting upgrades
	app.UpgradeKeeper = upgradekeeper.NewKeeper(
		skipUpgradeHeights,
		runtime.NewKVStoreService(keys[upgradetypes.StoreKey]),
		appCodec,
		homePath,
		app.BaseApp,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
	)

	/ Register the proposal types
	/ Deprecated: Avoid adding new handlers, instead use the new proposal flow
	/ by granting the governance module the right to execute the message.
	/ See: https://docs.cosmos.network/main/modules/gov#proposal-messages
    govRouter := govv1beta1.NewRouter()

govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler)
    govConfig := govtypes.DefaultConfig()
	/*
		Example of setting gov params:
		govConfig.MaxMetadataLen = 10000
	*/
    govKeeper := govkeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[govtypes.StoreKey]),
		app.AccountKeeper,
		app.BankKeeper,
		app.StakingKeeper,
		app.DistrKeeper,
		app.MsgServiceRouter(),
		govConfig,
		authtypes.NewModuleAddress(govtypes.ModuleName).String(),
		/ govkeeper.WithCustomCalculateVoteResultsAndVotingPowerFn(...), / Add if you want to use a custom vote calculation function.
	)

	/ Set legacy router for backwards compatibility with gov v1beta1
	govKeeper.SetLegacyRouter(govRouter)

app.GovKeeper = *govKeeper.SetHooks(
		govtypes.NewMultiGovHooks(
		/ register the governance hooks
		),
	)

	/ create evidence keeper with router
    evidenceKeeper := evidencekeeper.NewKeeper(
		appCodec,
		runtime.NewKVStoreService(keys[evidencetypes.StoreKey]),
		app.StakingKeeper,
		app.SlashingKeeper,
		app.AccountKeeper.AddressCodec(),
		runtime.ProvideCometInfoService(),
	)
	/ If evidence needs to be handled for the app, set routes in router here and seal
	app.EvidenceKeeper = *evidenceKeeper

	app.EpochsKeeper = epochskeeper.NewKeeper(
		runtime.NewKVStoreService(keys[epochstypes.StoreKey]),
		appCodec,
	)

app.EpochsKeeper.SetHooks(
		epochstypes.NewMultiEpochHooks(
		/ insert epoch hooks receivers here
		),
	)

	/****  Module Options ****/

	/ NOTE: Any module instantiated in the module manager that is later modified
	/ must be passed by reference here.
	app.ModuleManager = module.NewManager(
		genutil.NewAppModule(
			app.AccountKeeper, app.StakingKeeper, app,
			txConfig,
		),
		auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, nil),
		vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
		bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, nil),
		feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
		gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, nil),
		mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, nil),
		slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil, app.interfaceRegistry),
		distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil),
		staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, nil),
		upgrade.NewAppModule(app.UpgradeKeeper, app.AccountKeeper.AddressCodec()),
		evidence.NewAppModule(app.EvidenceKeeper),
		authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
		consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper),
		epochs.NewAppModule(app.EpochsKeeper),
		protocolpool.NewAppModule(app.ProtocolPoolKeeper, app.AccountKeeper, app.BankKeeper),
	)

	/ BasicModuleManager defines the module BasicManager is in charge of setting up basic,
	/ non-dependent module elements, such as codec registration and genesis verification.
	/ By default it is composed of all the module from the module manager.
	/ Additionally, app module basics can be overwritten by passing them as argument.
	app.BasicModuleManager = module.NewBasicManagerFromManager(
		app.ModuleManager,
		map[string]module.AppModuleBasic{
    genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
			govtypes.ModuleName: gov.NewAppModuleBasic(
				[]govclient.ProposalHandler{
},
			),
})

app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino)

app.BasicModuleManager.RegisterInterfaces(interfaceRegistry)

	/ NOTE: upgrade module is required to be prioritized
	app.ModuleManager.SetOrderPreBlockers(
		upgradetypes.ModuleName,
		authtypes.ModuleName,
	)
	/ During begin block slashing happens after distr.BeginBlocker so that
	/ there is nothing left over in the validator fee pool, so as to keep the
	/ CanWithdrawInvariant invariant.
	/ NOTE: staking module is required if HistoricalEntries param > 0
	app.ModuleManager.SetOrderBeginBlockers(
		minttypes.ModuleName,
		distrtypes.ModuleName,
		protocolpooltypes.ModuleName,
		slashingtypes.ModuleName,
		evidencetypes.ModuleName,
		stakingtypes.ModuleName,
		genutiltypes.ModuleName,
		authz.ModuleName,
		epochstypes.ModuleName,
	)

app.ModuleManager.SetOrderEndBlockers(
		govtypes.ModuleName,
		stakingtypes.ModuleName,
		genutiltypes.ModuleName,
		feegrant.ModuleName,
		protocolpooltypes.ModuleName,
	)

	/ NOTE: The genutils module must occur after staking so that pools are
	/ properly initialized with tokens from genesis accounts.
	/ NOTE: The genutils module must also occur after auth so that it can access the params from auth.
    genesisModuleOrder := []string{
    authtypes.ModuleName,
		banktypes.ModuleName,
		distrtypes.ModuleName,
		stakingtypes.ModuleName,
		slashingtypes.ModuleName,
		govtypes.ModuleName,
		minttypes.ModuleName,
		genutiltypes.ModuleName,
		evidencetypes.ModuleName,
		authz.ModuleName,
		feegrant.ModuleName,
		upgradetypes.ModuleName,
		vestingtypes.ModuleName,
		consensusparamtypes.ModuleName,
		epochstypes.ModuleName,
		protocolpooltypes.ModuleName,
}
    exportModuleOrder := []string{
    consensusparamtypes.ModuleName,
		authtypes.ModuleName,
		protocolpooltypes.ModuleName, / Must be exported before bank
		banktypes.ModuleName,
		distrtypes.ModuleName,
		stakingtypes.ModuleName,
		slashingtypes.ModuleName,
		govtypes.ModuleName,
		minttypes.ModuleName,
		genutiltypes.ModuleName,
		evidencetypes.ModuleName,
		authz.ModuleName,
		feegrant.ModuleName,
		upgradetypes.ModuleName,
		vestingtypes.ModuleName,
		epochstypes.ModuleName,
}

app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...)

app.ModuleManager.SetOrderExportGenesis(exportModuleOrder...)

	/ Uncomment if you want to set a custom migration order here.
	/ app.ModuleManager.SetOrderMigrations(custom order)

app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())

err = app.ModuleManager.RegisterServices(app.configurator)
    if err != nil {
    panic(err)
}

	/ RegisterUpgradeHandlers is used for registering any on-chain upgrades.
	/ Make sure it's called after `app.ModuleManager` and `app.configurator` are set.
	app.RegisterUpgradeHandlers()

autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.ModuleManager.Modules))

reflectionSvc, err := runtimeservices.NewReflectionService()
    if err != nil {
    panic(err)
}

reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc)

	/ add test gRPC service for testing gRPC queries in isolation
	testdata_pulsar.RegisterQueryServer(app.GRPCQueryRouter(), testdata_pulsar.QueryImpl{
})

	/ create the simulation manager and define the order of the modules for deterministic simulations
	/
	/ NOTE: this is not required apps that don't use the simulator for fuzz testing
	/ transactions
    overrideModules := map[string]module.AppModuleSimulation{
    authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, nil),
}

app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules)

app.sm.RegisterStoreDecoders()

	/ initialize stores
	app.MountKVStores(keys)

	/ initialize BaseApp
	app.SetInitChainer(app.InitChainer)

app.SetPreBlocker(app.PreBlocker)

app.SetBeginBlocker(app.BeginBlocker)

app.SetEndBlocker(app.EndBlocker)

app.setAnteHandler(txConfig)

	/ In v0.46, the SDK introduces _postHandlers_. PostHandlers are like
	/ antehandlers, but are run _after_ the `runMsgs` execution. They are also
	/ defined as a chain, and have the same signature as antehandlers.
	/
	/ In baseapp, postHandlers are run in the same store branch as `runMsgs`,
	/ meaning that both `runMsgs` and `postHandler` state will be committed if
	/ both are successful, and both will be reverted if any of the two fails.
	/
	/ The SDK exposes a default postHandlers chain
	/
	/ Please note that changing any of the anteHandler or postHandler chain is
	/ likely to be a state-machine breaking change, which needs a coordinated
	/ upgrade.
	app.setPostHandler()
    if loadLatest {
    if err := app.LoadLatestVersion(); err != nil {
    panic(fmt.Errorf("error loading last version: %w", err))
}
	
}

return app
}

func (app *SimApp)

setAnteHandler(txConfig client.TxConfig) {
    anteHandler, err := ante.NewAnteHandler(
		ante.HandlerOptions{
    AccountKeeper:   app.AccountKeeper,
    BankKeeper:      app.BankKeeper,
    SignModeHandler: txConfig.SignModeHandler(),
    FeegrantKeeper:  app.FeeGrantKeeper,
    SigGasConsumer:  ante.DefaultSigVerificationGasConsumer,
    SigVerifyOptions: []ante.SigVerificationDecoratorOption{
				/ change below as needed.
				ante.WithUnorderedTxGasCost(ante.DefaultUnorderedTxGasCost),
				ante.WithMaxUnorderedTxTimeoutDuration(ante.DefaultMaxTimeoutDuration),
},
},
	)
    if err != nil {
    panic(err)
}

	/ Set the AnteHandler for the app
	app.SetAnteHandler(anteHandler)
}

func (app *SimApp)

setPostHandler() {
    postHandler, err := posthandler.NewPostHandler(
		posthandler.HandlerOptions{
},
	)
    if err != nil {
    panic(err)
}

app.SetPostHandler(postHandler)
}

/ Name returns the name of the App
func (app *SimApp)

Name()

string {
    return app.BaseApp.Name()
}

/ PreBlocker application updates every pre block
func (app *SimApp)

PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
    return app.ModuleManager.PreBlock(ctx)
}

/ BeginBlocker application updates every begin block
func (app *SimApp)

BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) {
    return app.ModuleManager.BeginBlock(ctx)
}

/ EndBlocker application updates every end block
func (app *SimApp)

EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) {
    return app.ModuleManager.EndBlock(ctx)
}

func (a *SimApp)

Configurator()

module.Configurator {
    return a.configurator
}

/ InitChainer application update at chain initialization
func (app *SimApp)

InitChainer(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) {
    var genesisState GenesisState
    if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil {
    panic(err)
}

app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap())

return app.ModuleManager.InitGenesis(ctx, app.appCodec, genesisState)
}

/ LoadHeight loads a particular height
func (app *SimApp)

LoadHeight(height int64)

error {
    return app.LoadVersion(height)
}

/ LegacyAmino returns SimApp's amino codec.
/
/ NOTE: This is solely to be used for testing purposes as it may be desirable
/ for modules to register their own custom testing types.
func (app *SimApp)

LegacyAmino() *codec.LegacyAmino {
    return app.legacyAmino
}

/ AppCodec returns SimApp's app codec.
/
/ NOTE: This is solely to be used for testing purposes as it may be desirable
/ for modules to register their own custom testing types.
func (app *SimApp)

AppCodec()

codec.Codec {
    return app.appCodec
}

/ InterfaceRegistry returns SimApp's InterfaceRegistry
func (app *SimApp)

InterfaceRegistry()

types.InterfaceRegistry {
    return app.interfaceRegistry
}

/ TxConfig returns SimApp's TxConfig
func (app *SimApp)

TxConfig()

client.TxConfig {
    return app.txConfig
}

/ AutoCliOpts returns the autocli options for the app.
func (app *SimApp)

AutoCliOpts()

autocli.AppOptions {
    modules := make(map[string]appmodule.AppModule, 0)
    for _, m := range app.ModuleManager.Modules {
    if moduleWithName, ok := m.(module.HasName); ok {
    moduleName := moduleWithName.Name()
    if appModule, ok := moduleWithName.(appmodule.AppModule); ok {
    modules[moduleName] = appModule
}
	
}
	
}

return autocli.AppOptions{
    Modules:               modules,
    ModuleOptions:         runtimeservices.ExtractAutoCLIOptions(app.ModuleManager.Modules),
    AddressCodec:          authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
    ValidatorAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
    ConsensusAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
}
}

/ DefaultGenesis returns a default genesis from the registered AppModuleBasic's.
func (a *SimApp)

DefaultGenesis()

map[string]json.RawMessage {
    return a.BasicModuleManager.DefaultGenesis(a.appCodec)
}

/ GetKey returns the KVStoreKey for the provided store key.
/
/ NOTE: This is solely to be used for testing purposes.
func (app *SimApp)

GetKey(storeKey string) *storetypes.KVStoreKey {
    return app.keys[storeKey]
}

/ GetStoreKeys returns all the stored store keys.
func (app *SimApp)

GetStoreKeys() []storetypes.StoreKey {
    keys := make([]storetypes.StoreKey, 0, len(app.keys))
    for _, key := range app.keys {
    keys = append(keys, key)
}

return keys
}

/ SimulationManager implements the SimulationApp interface
func (app *SimApp)

SimulationManager() *module.SimulationManager {
    return app.sm
}

/ RegisterAPIRoutes registers all application module routes with the provided
/ API server.
func (app *SimApp)

RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
    clientCtx := apiSvr.ClientCtx
	/ Register new tx routes from grpc-gateway.
	authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)

	/ Register new CometBFT queries routes from grpc-gateway.
	cmtservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)

	/ Register node gRPC service for grpc-gateway.
	nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)

	/ Register grpc-gateway routes for all modules.
	app.BasicModuleManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)

	/ register swagger API from root so that other applications can override easily
    if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {
    panic(err)
}
}

/ RegisterTxService implements the Application.RegisterTxService method.
func (app *SimApp)

RegisterTxService(clientCtx client.Context) {
    authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
}

/ RegisterTendermintService implements the Application.RegisterTendermintService method.
func (app *SimApp)

RegisterTendermintService(clientCtx client.Context) {
    cmtApp := server.NewCometABCIWrapper(app)

cmtservice.RegisterTendermintService(
		clientCtx,
		app.BaseApp.GRPCQueryRouter(),
		app.interfaceRegistry,
		cmtApp.Query,
	)
}

func (app *SimApp)

RegisterNodeService(clientCtx client.Context, cfg config.Config) {
    nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter(), cfg)
}

/ GetMaccPerms returns a copy of the module account permissions
/
/ NOTE: This is solely to be used for testing purposes.
func GetMaccPerms()

map[string][]string {
    return maps.Clone(maccPerms)
}

/ BlockedAddresses returns all the app's blocked account addresses.
func BlockedAddresses()

map[string]bool {
    modAccAddrs := make(map[string]bool)
    for acc := range GetMaccPerms() {
    modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true
}

	/ allow the following addresses to receive funds
	delete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String())

return modAccAddrs
}
Note that you may override some modules. This is useful if the existing module configuration in the ModuleManager should be different in the SimulationManager. Finally, the application should expose the SimulationManager via the following method defined in the Runtime interface:
/ SimulationManager implements the SimulationApp interface
func (app *SimApp)

SimulationManager() *module.SimulationManager {
    return app.sm
}

Running Simulations

To run the simulation, use the simsx runner. Call the following function from the simsx package to begin simulating with a default seed:
package simsx

import (
    
	"encoding/json"
    "fmt"
    "io"
    "math"
    "os"
    "path/filepath"
    "strings"
    "testing"

	dbm "github.com/cosmos/cosmos-db"
    "github.com/stretchr/testify/require"
    "cosmossdk.io/log"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/client/flags"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/runtime"
	servertypes "github.com/cosmos/cosmos-sdk/server/types"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/types/module"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    "github.com/cosmos/cosmos-sdk/x/simulation"
    "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
)

const SimAppChainID = "simulation-app"

/ this list of seeds was imported from the original simulation runner: https://github.com/cosmos/tools/blob/v1.0.0/cmd/runsim/main.go#L32
var defaultSeeds = []int64{
	1, 2, 4, 7,
	32, 123, 124, 582, 1893, 2989,
	3012, 4728, 37827, 981928, 87821, 891823782,
	989182, 89182391, 11, 22, 44, 77, 99, 2020,
	3232, 123123, 124124, 582582, 18931893,
	29892989, 30123012, 47284728, 7601778, 8090485,
	977367484, 491163361, 424254581, 673398983,
}

/ SimStateFactory is a factory type that provides a convenient way to create a simulation state for testing.
/ It contains the following fields:
/ - Codec: a codec used for serializing other objects
/ - AppStateFn: a function that returns the app state JSON bytes and the genesis accounts
/ - BlockedAddr: a map of blocked addresses
/ - AccountSource: an interface for retrieving accounts
/ - BalanceSource: an interface for retrieving balance-related information
type SimStateFactory struct {
    Codec         codec.Codec
	AppStateFn    simtypes.AppStateFn
	BlockedAddr   map[string]bool
	AccountSource AccountSourceX
	BalanceSource BalanceSource
}

/ SimulationApp abstract app that is used by sims
type SimulationApp interface {
    runtime.AppI
	SetNotSigverifyTx()

GetBaseApp() *baseapp.BaseApp
	TxConfig()

client.TxConfig
	Close()

error
}

/ Run is a helper function that runs a simulation test with the given parameters.
/ It calls the RunWithSeeds function with the default seeds and parameters.
/
/ This is the entrypoint to run simulation tests that used to run with the runsim binary.
func Run[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()

RunWithSeeds(t, appFactory, setupStateFactory, defaultSeeds, nil, postRunActions...)
}

/ RunWithSeeds is a helper function that runs a simulation test with the given parameters.
/ It iterates over the provided seeds and runs the simulation test for each seed in parallel.
/
/ It sets up the environment, creates an instance of the simulation app,
/ calls the simulation.SimulateFromSeed function to run the simulation, and performs post-run actions for each seed.
/ The execution is deterministic and can be used for fuzz tests as well.
/
/ The system under test is isolated for each run but unlike the old runsim command, there is no Process separation.
/ This means, global caches may be reused for example. This implementation build upon the vanilla Go stdlib test framework.
func RunWithSeeds[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	seeds []int64,
	fuzzSeed []byte,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()

RunWithSeedsAndRandAcc(t, appFactory, setupStateFactory, seeds, fuzzSeed, simtypes.RandomAccounts, postRunActions...)
}

/ RunWithSeedsAndRandAcc calls RunWithSeeds with randAccFn
func RunWithSeedsAndRandAcc[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	seeds []int64,
	fuzzSeed []byte,
	randAccFn simtypes.RandomAccountFn,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()
    if deprecatedParams := cli.GetDeprecatedFlagUsed(); len(deprecatedParams) != 0 {
    fmt.Printf("Warning: Deprecated flag are used: %s", strings.Join(deprecatedParams, ","))
}
    cfg := cli.NewConfigFromFlags()

cfg.ChainID = SimAppChainID
    for i := range seeds {
    seed := seeds[i]
		t.Run(fmt.Sprintf("seed: %d", seed), func(t *testing.T) {
    t.Parallel()

RunWithSeed(t, cfg, appFactory, setupStateFactory, seed, fuzzSeed, postRunActions...)
})
}
}

/ RunWithSeed is a helper function that runs a simulation test with the given parameters.
/ It iterates over the provided seeds and runs the simulation test for each seed in parallel.
/
/ It sets up the environment, creates an instance of the simulation app,
/ calls the simulation.SimulateFromSeed function to run the simulation, and performs post-run actions for the seed.
/ The execution is deterministic and can be used for fuzz tests as well.
func RunWithSeed[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	cfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
	setupStateFactory func(app T)

SimStateFactory,
	seed int64,
	fuzzSeed []byte,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    tb.Helper()

RunWithSeedAndRandAcc(tb, cfg, appFactory, setupStateFactory, seed, fuzzSeed, simtypes.RandomAccounts, postRunActions...)
}

/ RunWithSeedAndRandAcc calls RunWithSeed with randAccFn
func RunWithSeedAndRandAcc[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	cfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
	setupStateFactory func(app T)

SimStateFactory,
	seed int64,
	fuzzSeed []byte,
	randAccFn simtypes.RandomAccountFn,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    tb.Helper()
	/ setup environment
    tCfg := cfg.With(tb, seed, fuzzSeed)
    testInstance := NewSimulationAppInstance(tb, tCfg, appFactory)

var runLogger log.Logger
    if cli.FlagVerboseValue {
    runLogger = log.NewTestLogger(tb)
}

else {
    runLogger = log.NewTestLoggerInfo(tb)
}

runLogger = runLogger.With("seed", tCfg.Seed)
    app := testInstance.App
    stateFactory := setupStateFactory(app)

ops, reporter := prepareWeightedOps(app.SimulationManager(), stateFactory, tCfg, testInstance.App.TxConfig(), runLogger)

simParams, accs, err := simulation.SimulateFromSeedX(
		tb,
		runLogger,
		WriteToDebugLog(runLogger),
		app.GetBaseApp(),
		stateFactory.AppStateFn,
		randAccFn,
		ops,
		stateFactory.BlockedAddr,
		tCfg,
		stateFactory.Codec,
		testInstance.ExecLogWriter,
	)

require.NoError(tb, err)

err = simtestutil.CheckExportSimulation(app, tCfg, simParams)

require.NoError(tb, err)
    if tCfg.Commit {
    simtestutil.PrintStats(testInstance.DB)
}
	/ not using tb.Log to always print the summary
	fmt.Printf("+++ DONE (seed: %d): \n%s\n", seed, reporter.Summary().String())
    for _, step := range postRunActions {
    step(tb, testInstance, accs)
}

require.NoError(tb, app.Close())
}

type (
	HasWeightedOperationsX interface {
    WeightedOperationsX(weight WeightSource, reg Registry)
}

HasWeightedOperationsXWithProposals interface {
    WeightedOperationsX(weights WeightSource, reg Registry, proposals WeightedProposalMsgIter,
			legacyProposals []simtypes.WeightedProposalContent) /nolint: staticcheck / used for legacy proposal types
}

HasProposalMsgsX interface {
    ProposalMsgsX(weights WeightSource, reg Registry)
}
)

type (
	HasLegacyWeightedOperations interface {
		/ WeightedOperations simulation operations (i.e msgs)

with their respective weight
		WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation
}
	/ HasLegacyProposalMsgs defines the messages that can be used to simulate governance (v1)

proposals
	/ Deprecated replaced by HasProposalMsgsX
	HasLegacyProposalMsgs interface {
		/ ProposalMsgs msg fu	nctions used to simulate governance proposals
		ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg
}

	/ HasLegacyProposalContents defines the contents that can be used to simulate legacy governance (v1beta1)

proposals
	/ Deprecated replaced by HasProposalMsgsX
	HasLegacyProposalContents interface {
		/ ProposalContents content functions used to simulate governance proposals
		ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent /nolint:staticcheck / legacy v1beta1 governance
}
)

/ TestInstance is a generic type that represents an instance of a SimulationApp used for testing simulations.
/ It contains the following fields:
/   - App: The instance of the SimulationApp under test.
/   - DB: The LevelDB database for the simulation app.
/   - WorkDir: The temporary working directory for the simulation app.
/   - Cfg: The configuration flags for the simulator.
/   - AppLogger: The logger used for logging in the app during the simulation, with seed value attached.
/   - ExecLogWriter: Captures block and operation data coming from the simulation
type TestInstance[T SimulationApp] struct {
    App           T
	DB            dbm.DB
	WorkDir       string
	Cfg           simtypes.Config
	AppLogger     log.Logger
	ExecLogWriter simulation.LogWriter
}

/ included to avoid cyclic dependency in testutils/sims
func prepareWeightedOps(
	sm *module.SimulationManager,
	stateFact SimStateFactory,
	config simtypes.Config,
	txConfig client.TxConfig,
	logger log.Logger,
) (simulation.WeightedOperations, *BasicSimulationReporter) {
    cdc := stateFact.Codec
    simState := module.SimulationState{
    AppParams: make(simtypes.AppParams),
    Cdc:       cdc,
    TxConfig:  txConfig,
    BondDenom: sdk.DefaultBondDenom,
}
    if config.ParamsFile != "" {
    bz, err := os.ReadFile(config.ParamsFile)
    if err != nil {
    panic(err)
}

err = json.Unmarshal(bz, &simState.AppParams)
    if err != nil {
    panic(err)
}
	
}
    weights := ParamWeightSource(simState.AppParams)
    reporter := NewBasicSimulationReporter()
    pReg := make(UniqueTypeRegistry)
    wContent := make([]simtypes.WeightedProposalContent, 0) /nolint:staticcheck / required for legacy type
    legacyPReg := NewWeightedFactoryMethods()
	/ add gov proposals types
    for _, m := range sm.Modules {
    switch xm := m.(type) {
    case HasProposalMsgsX:
			xm.ProposalMsgsX(weights, pReg)
    case HasLegacyProposalMsgs:
    for _, p := range xm.ProposalMsgs(simState) {
    weight := weights.Get(p.AppParamsKey(), safeUint(p.DefaultWeight()))

legacyPReg.Add(weight, legacyToMsgFactoryAdapter(p.MsgSimulatorFn()))
}
    case HasLegacyProposalContents:
			wContent = append(wContent, xm.ProposalContents(simState)...)
}
	
}
    oReg := NewSimsMsgRegistryAdapter(
		reporter,
		stateFact.AccountSource,
		stateFact.BalanceSource,
		txConfig,
		logger,
	)
    wOps := make([]simtypes.WeightedOperation, 0, len(sm.Modules))
    for _, m := range sm.Modules {
		/ add operations
    switch xm := m.(type) {
    case HasWeightedOperationsX:
			xm.WeightedOperationsX(weights, oReg)
    case HasWeightedOperationsXWithProposals:
			xm.WeightedOperationsX(weights, oReg, AppendIterators(legacyPReg.Iterator(), pReg.Iterator()), wContent)
    case HasLegacyWeightedOperations:
			wOps = append(wOps, xm.WeightedOperations(simState)...)
}
	
}

return append(wOps, Collect(oReg.items, func(a weightedOperation)

simtypes.WeightedOperation {
    return a
})...), reporter
}

func safeUint(p int)

uint32 {
    if p < 0 || p > math.MaxUint32 {
    panic(fmt.Sprintf("can not cast to uint32: %d", p))
}

return uint32(p)
}

/ NewSimulationAppInstance initializes and returns a TestInstance of a SimulationApp.
/ The function takes a testing.T instance, a simtypes.Config instance, and an appFactory function as parameters.
/ It creates a temporary working directory and a LevelDB database for the simulation app.
/ The function then initializes a logger based on the verbosity flag and sets the logger's seed to the test configuration's seed.
/ The database is closed and cleaned up on test completion.
func NewSimulationAppInstance[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	tCfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
)

TestInstance[T] {
    tb.Helper()
    workDir := tb.TempDir()

require.NoError(tb, os.Mkdir(filepath.Join(workDir, "data"), 0o750))
    dbDir := filepath.Join(workDir, "leveldb-app-sim")

var logger log.Logger
    if cli.FlagVerboseValue {
    logger = log.NewTestLogger(tb)
}

else {
    logger = log.NewTestLoggerError(tb)
}

logger = logger.With("seed", tCfg.Seed)

db, err := dbm.NewDB("Simulation", dbm.BackendType(tCfg.DBBackend), dbDir)

require.NoError(tb, err)

tb.Cleanup(func() {
		_ = db.Close() / ensure db is closed
})
    appOptions := make(simtestutil.AppOptionsMap)

appOptions[flags.FlagHome] = workDir
    opts := []func(*baseapp.BaseApp) {
    baseapp.SetChainID(tCfg.ChainID)
}
    if tCfg.FauxMerkle {
    opts = append(opts, FauxMerkleModeOpt)
}
    app := appFactory(logger, db, nil, true, appOptions, opts...)
    if !cli.FlagSigverifyTxValue {
    app.SetNotSigverifyTx()
}

return TestInstance[T]{
    App:           app,
    DB:            db,
    WorkDir:       workDir,
    Cfg:           tCfg,
    AppLogger:     logger,
    ExecLogWriter: &simulation.StandardLogWriter{
    Seed: tCfg.Seed
},
}
}

var _ io.Writer = writerFn(nil)

type writerFn func(p []byte) (n int, err error)

func (w writerFn)

Write(p []byte) (n int, err error) {
    return w(p)
}

/ WriteToDebugLog is an adapter to io.Writer interface
func WriteToDebugLog(logger log.Logger)

io.Writer {
    return writerFn(func(p []byte) (n int, err error) {
    logger.Debug(string(p))

return len(p), nil
})
}

/ FauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
/ an IAVLStore for faster simulation speed.
func FauxMerkleModeOpt(bapp *baseapp.BaseApp) {
    bapp.SetFauxMerkleMode()
}
If a custom seed is desired, tests should use RunWithSeed:
package simsx

import (
    
	"encoding/json"
    "fmt"
    "io"
    "math"
    "os"
    "path/filepath"
    "strings"
    "testing"

	dbm "github.com/cosmos/cosmos-db"
    "github.com/stretchr/testify/require"
    "cosmossdk.io/log"
    "github.com/cosmos/cosmos-sdk/baseapp"
    "github.com/cosmos/cosmos-sdk/client"
    "github.com/cosmos/cosmos-sdk/client/flags"
    "github.com/cosmos/cosmos-sdk/codec"
    "github.com/cosmos/cosmos-sdk/runtime"
	servertypes "github.com/cosmos/cosmos-sdk/server/types"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sdk "github.com/cosmos/cosmos-sdk/types"
    "github.com/cosmos/cosmos-sdk/types/module"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    "github.com/cosmos/cosmos-sdk/x/simulation"
    "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
)

const SimAppChainID = "simulation-app"

/ this list of seeds was imported from the original simulation runner: https://github.com/cosmos/tools/blob/v1.0.0/cmd/runsim/main.go#L32
var defaultSeeds = []int64{
	1, 2, 4, 7,
	32, 123, 124, 582, 1893, 2989,
	3012, 4728, 37827, 981928, 87821, 891823782,
	989182, 89182391, 11, 22, 44, 77, 99, 2020,
	3232, 123123, 124124, 582582, 18931893,
	29892989, 30123012, 47284728, 7601778, 8090485,
	977367484, 491163361, 424254581, 673398983,
}

/ SimStateFactory is a factory type that provides a convenient way to create a simulation state for testing.
/ It contains the following fields:
/ - Codec: a codec used for serializing other objects
/ - AppStateFn: a function that returns the app state JSON bytes and the genesis accounts
/ - BlockedAddr: a map of blocked addresses
/ - AccountSource: an interface for retrieving accounts
/ - BalanceSource: an interface for retrieving balance-related information
type SimStateFactory struct {
    Codec         codec.Codec
	AppStateFn    simtypes.AppStateFn
	BlockedAddr   map[string]bool
	AccountSource AccountSourceX
	BalanceSource BalanceSource
}

/ SimulationApp abstract app that is used by sims
type SimulationApp interface {
    runtime.AppI
	SetNotSigverifyTx()

GetBaseApp() *baseapp.BaseApp
	TxConfig()

client.TxConfig
	Close()

error
}

/ Run is a helper function that runs a simulation test with the given parameters.
/ It calls the RunWithSeeds function with the default seeds and parameters.
/
/ This is the entrypoint to run simulation tests that used to run with the runsim binary.
func Run[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()

RunWithSeeds(t, appFactory, setupStateFactory, defaultSeeds, nil, postRunActions...)
}

/ RunWithSeeds is a helper function that runs a simulation test with the given parameters.
/ It iterates over the provided seeds and runs the simulation test for each seed in parallel.
/
/ It sets up the environment, creates an instance of the simulation app,
/ calls the simulation.SimulateFromSeed function to run the simulation, and performs post-run actions for each seed.
/ The execution is deterministic and can be used for fuzz tests as well.
/
/ The system under test is isolated for each run but unlike the old runsim command, there is no Process separation.
/ This means, global caches may be reused for example. This implementation build upon the vanilla Go stdlib test framework.
func RunWithSeeds[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	seeds []int64,
	fuzzSeed []byte,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()

RunWithSeedsAndRandAcc(t, appFactory, setupStateFactory, seeds, fuzzSeed, simtypes.RandomAccounts, postRunActions...)
}

/ RunWithSeedsAndRandAcc calls RunWithSeeds with randAccFn
func RunWithSeedsAndRandAcc[T SimulationApp](/docs/sdk/next/documentation/operations/
	t *testing.T,
	appFactory func(
		logger log.Logger,
		db dbm.DB,
		traceStore io.Writer,
		loadLatest bool,
		appOpts servertypes.AppOptions,
		baseAppOptions ...func(*baseapp.BaseApp),
	)

T,
	setupStateFactory func(app T)

SimStateFactory,
	seeds []int64,
	fuzzSeed []byte,
	randAccFn simtypes.RandomAccountFn,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    t.Helper()
    if deprecatedParams := cli.GetDeprecatedFlagUsed(); len(deprecatedParams) != 0 {
    fmt.Printf("Warning: Deprecated flag are used: %s", strings.Join(deprecatedParams, ","))
}
    cfg := cli.NewConfigFromFlags()

cfg.ChainID = SimAppChainID
    for i := range seeds {
    seed := seeds[i]
		t.Run(fmt.Sprintf("seed: %d", seed), func(t *testing.T) {
    t.Parallel()

RunWithSeed(t, cfg, appFactory, setupStateFactory, seed, fuzzSeed, postRunActions...)
})
}
}

/ RunWithSeed is a helper function that runs a simulation test with the given parameters.
/ It iterates over the provided seeds and runs the simulation test for each seed in parallel.
/
/ It sets up the environment, creates an instance of the simulation app,
/ calls the simulation.SimulateFromSeed function to run the simulation, and performs post-run actions for the seed.
/ The execution is deterministic and can be used for fuzz tests as well.
func RunWithSeed[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	cfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
	setupStateFactory func(app T)

SimStateFactory,
	seed int64,
	fuzzSeed []byte,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    tb.Helper()

RunWithSeedAndRandAcc(tb, cfg, appFactory, setupStateFactory, seed, fuzzSeed, simtypes.RandomAccounts, postRunActions...)
}

/ RunWithSeedAndRandAcc calls RunWithSeed with randAccFn
func RunWithSeedAndRandAcc[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	cfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
	setupStateFactory func(app T)

SimStateFactory,
	seed int64,
	fuzzSeed []byte,
	randAccFn simtypes.RandomAccountFn,
	postRunActions ...func(t testing.TB, app TestInstance[T], accs []simtypes.Account),
) {
    tb.Helper()
	/ setup environment
    tCfg := cfg.With(tb, seed, fuzzSeed)
    testInstance := NewSimulationAppInstance(tb, tCfg, appFactory)

var runLogger log.Logger
    if cli.FlagVerboseValue {
    runLogger = log.NewTestLogger(tb)
}

else {
    runLogger = log.NewTestLoggerInfo(tb)
}

runLogger = runLogger.With("seed", tCfg.Seed)
    app := testInstance.App
    stateFactory := setupStateFactory(app)

ops, reporter := prepareWeightedOps(app.SimulationManager(), stateFactory, tCfg, testInstance.App.TxConfig(), runLogger)

simParams, accs, err := simulation.SimulateFromSeedX(
		tb,
		runLogger,
		WriteToDebugLog(runLogger),
		app.GetBaseApp(),
		stateFactory.AppStateFn,
		randAccFn,
		ops,
		stateFactory.BlockedAddr,
		tCfg,
		stateFactory.Codec,
		testInstance.ExecLogWriter,
	)

require.NoError(tb, err)

err = simtestutil.CheckExportSimulation(app, tCfg, simParams)

require.NoError(tb, err)
    if tCfg.Commit {
    simtestutil.PrintStats(testInstance.DB)
}
	/ not using tb.Log to always print the summary
	fmt.Printf("+++ DONE (seed: %d): \n%s\n", seed, reporter.Summary().String())
    for _, step := range postRunActions {
    step(tb, testInstance, accs)
}

require.NoError(tb, app.Close())
}

type (
	HasWeightedOperationsX interface {
    WeightedOperationsX(weight WeightSource, reg Registry)
}

HasWeightedOperationsXWithProposals interface {
    WeightedOperationsX(weights WeightSource, reg Registry, proposals WeightedProposalMsgIter,
			legacyProposals []simtypes.WeightedProposalContent) /nolint: staticcheck / used for legacy proposal types
}

HasProposalMsgsX interface {
    ProposalMsgsX(weights WeightSource, reg Registry)
}
)

type (
	HasLegacyWeightedOperations interface {
		/ WeightedOperations simulation operations (i.e msgs)

with their respective weight
		WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation
}
	/ HasLegacyProposalMsgs defines the messages that can be used to simulate governance (v1)

proposals
	/ Deprecated replaced by HasProposalMsgsX
	HasLegacyProposalMsgs interface {
		/ ProposalMsgs msg fu	nctions used to simulate governance proposals
		ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg
}

	/ HasLegacyProposalContents defines the contents that can be used to simulate legacy governance (v1beta1)

proposals
	/ Deprecated replaced by HasProposalMsgsX
	HasLegacyProposalContents interface {
		/ ProposalContents content functions used to simulate governance proposals
		ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent /nolint:staticcheck / legacy v1beta1 governance
}
)

/ TestInstance is a generic type that represents an instance of a SimulationApp used for testing simulations.
/ It contains the following fields:
/   - App: The instance of the SimulationApp under test.
/   - DB: The LevelDB database for the simulation app.
/   - WorkDir: The temporary working directory for the simulation app.
/   - Cfg: The configuration flags for the simulator.
/   - AppLogger: The logger used for logging in the app during the simulation, with seed value attached.
/   - ExecLogWriter: Captures block and operation data coming from the simulation
type TestInstance[T SimulationApp] struct {
    App           T
	DB            dbm.DB
	WorkDir       string
	Cfg           simtypes.Config
	AppLogger     log.Logger
	ExecLogWriter simulation.LogWriter
}

/ included to avoid cyclic dependency in testutils/sims
func prepareWeightedOps(
	sm *module.SimulationManager,
	stateFact SimStateFactory,
	config simtypes.Config,
	txConfig client.TxConfig,
	logger log.Logger,
) (simulation.WeightedOperations, *BasicSimulationReporter) {
    cdc := stateFact.Codec
    simState := module.SimulationState{
    AppParams: make(simtypes.AppParams),
    Cdc:       cdc,
    TxConfig:  txConfig,
    BondDenom: sdk.DefaultBondDenom,
}
    if config.ParamsFile != "" {
    bz, err := os.ReadFile(config.ParamsFile)
    if err != nil {
    panic(err)
}

err = json.Unmarshal(bz, &simState.AppParams)
    if err != nil {
    panic(err)
}
	
}
    weights := ParamWeightSource(simState.AppParams)
    reporter := NewBasicSimulationReporter()
    pReg := make(UniqueTypeRegistry)
    wContent := make([]simtypes.WeightedProposalContent, 0) /nolint:staticcheck / required for legacy type
    legacyPReg := NewWeightedFactoryMethods()
	/ add gov proposals types
    for _, m := range sm.Modules {
    switch xm := m.(type) {
    case HasProposalMsgsX:
			xm.ProposalMsgsX(weights, pReg)
    case HasLegacyProposalMsgs:
    for _, p := range xm.ProposalMsgs(simState) {
    weight := weights.Get(p.AppParamsKey(), safeUint(p.DefaultWeight()))

legacyPReg.Add(weight, legacyToMsgFactoryAdapter(p.MsgSimulatorFn()))
}
    case HasLegacyProposalContents:
			wContent = append(wContent, xm.ProposalContents(simState)...)
}
	
}
    oReg := NewSimsMsgRegistryAdapter(
		reporter,
		stateFact.AccountSource,
		stateFact.BalanceSource,
		txConfig,
		logger,
	)
    wOps := make([]simtypes.WeightedOperation, 0, len(sm.Modules))
    for _, m := range sm.Modules {
		/ add operations
    switch xm := m.(type) {
    case HasWeightedOperationsX:
			xm.WeightedOperationsX(weights, oReg)
    case HasWeightedOperationsXWithProposals:
			xm.WeightedOperationsX(weights, oReg, AppendIterators(legacyPReg.Iterator(), pReg.Iterator()), wContent)
    case HasLegacyWeightedOperations:
			wOps = append(wOps, xm.WeightedOperations(simState)...)
}
	
}

return append(wOps, Collect(oReg.items, func(a weightedOperation)

simtypes.WeightedOperation {
    return a
})...), reporter
}

func safeUint(p int)

uint32 {
    if p < 0 || p > math.MaxUint32 {
    panic(fmt.Sprintf("can not cast to uint32: %d", p))
}

return uint32(p)
}

/ NewSimulationAppInstance initializes and returns a TestInstance of a SimulationApp.
/ The function takes a testing.T instance, a simtypes.Config instance, and an appFactory function as parameters.
/ It creates a temporary working directory and a LevelDB database for the simulation app.
/ The function then initializes a logger based on the verbosity flag and sets the logger's seed to the test configuration's seed.
/ The database is closed and cleaned up on test completion.
func NewSimulationAppInstance[T SimulationApp](/docs/sdk/next/documentation/operations/
	tb testing.TB,
	tCfg simtypes.Config,
	appFactory func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp))

T,
)

TestInstance[T] {
    tb.Helper()
    workDir := tb.TempDir()

require.NoError(tb, os.Mkdir(filepath.Join(workDir, "data"), 0o750))
    dbDir := filepath.Join(workDir, "leveldb-app-sim")

var logger log.Logger
    if cli.FlagVerboseValue {
    logger = log.NewTestLogger(tb)
}

else {
    logger = log.NewTestLoggerError(tb)
}

logger = logger.With("seed", tCfg.Seed)

db, err := dbm.NewDB("Simulation", dbm.BackendType(tCfg.DBBackend), dbDir)

require.NoError(tb, err)

tb.Cleanup(func() {
		_ = db.Close() / ensure db is closed
})
    appOptions := make(simtestutil.AppOptionsMap)

appOptions[flags.FlagHome] = workDir
    opts := []func(*baseapp.BaseApp) {
    baseapp.SetChainID(tCfg.ChainID)
}
    if tCfg.FauxMerkle {
    opts = append(opts, FauxMerkleModeOpt)
}
    app := appFactory(logger, db, nil, true, appOptions, opts...)
    if !cli.FlagSigverifyTxValue {
    app.SetNotSigverifyTx()
}

return TestInstance[T]{
    App:           app,
    DB:            db,
    WorkDir:       workDir,
    Cfg:           tCfg,
    AppLogger:     logger,
    ExecLogWriter: &simulation.StandardLogWriter{
    Seed: tCfg.Seed
},
}
}

var _ io.Writer = writerFn(nil)

type writerFn func(p []byte) (n int, err error)

func (w writerFn)

Write(p []byte) (n int, err error) {
    return w(p)
}

/ WriteToDebugLog is an adapter to io.Writer interface
func WriteToDebugLog(logger log.Logger)

io.Writer {
    return writerFn(func(p []byte) (n int, err error) {
    logger.Debug(string(p))

return len(p), nil
})
}

/ FauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
/ an IAVLStore for faster simulation speed.
func FauxMerkleModeOpt(bapp *baseapp.BaseApp) {
    bapp.SetFauxMerkleMode()
}
These functions should be called in tests (i.e., app_test.go, app_sim_test.go, etc.) Example:
/go:build sims

package simapp

import (
    
	"encoding/binary"
    "encoding/json"
    "flag"
    "io"
    "math/rand"
    "strings"
    "sync"
    "testing"

	abci "github.com/cometbft/cometbft/abci/types"
	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
	dbm "github.com/cosmos/cosmos-db"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
    "cosmossdk.io/log"
    "cosmossdk.io/store"
	storetypes "cosmossdk.io/store/types"
    "github.com/cosmos/cosmos-sdk/baseapp"
	servertypes "github.com/cosmos/cosmos-sdk/server/types"
	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
	sims "github.com/cosmos/cosmos-sdk/testutil/simsx"
	sdk "github.com/cosmos/cosmos-sdk/types"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
	authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
    "github.com/cosmos/cosmos-sdk/x/feegrant"
    "github.com/cosmos/cosmos-sdk/x/simulation"
	simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
	slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

var FlagEnableStreamingValue bool

/ Get flags every time the simulator is run
func init() {
    simcli.GetSimulatorFlags()

flag.BoolVar(&FlagEnableStreamingValue, "EnableStreaming", false, "Enable streaming service")
}

/ interBlockCacheOpt returns a BaseApp option function that sets the persistent
/ inter-block write-through cache.
func interBlockCacheOpt()

func(*baseapp.BaseApp) {
    return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
}

func TestFullAppSimulation(t *testing.T) {
    sims.Run(t, NewSimApp, setupStateFactory)
}

func setupStateFactory(app *SimApp)

sims.SimStateFactory {
    return sims.SimStateFactory{
    Codec:         app.AppCodec(),
    AppStateFn:    simtestutil.AppStateFn(app.AppCodec(), app.SimulationManager(), app.DefaultGenesis()),
    BlockedAddr:   BlockedAddresses(),
    AccountSource: app.AccountKeeper,
    BalanceSource: app.BankKeeper,
}
}

var (
	exportAllModules       = []string{
}

exportWithValidatorSet = []string{
}
)

func TestAppImportExport(t *testing.T) {
    sims.Run(t, NewSimApp, setupStateFactory, func(tb testing.TB, ti sims.TestInstance[*SimApp], accs []simtypes.Account) {
    tb.Helper()
    app := ti.App
		tb.Log("exporting genesis...\n")

exported, err := app.ExportAppStateAndValidators(false, exportWithValidatorSet, exportAllModules)

require.NoError(tb, err)

tb.Log("importing genesis...\n")
    newTestInstance := sims.NewSimulationAppInstance(tb, ti.Cfg, NewSimApp)
    newApp := newTestInstance.App
		var genesisState GenesisState
		require.NoError(tb, json.Unmarshal(exported.AppState, &genesisState))
    ctxB := newApp.NewContextLegacy(true, cmtproto.Header{
    Height: app.LastBlockHeight()
})
		_, err = newApp.ModuleManager.InitGenesis(ctxB, newApp.appCodec, genesisState)
    if IsEmptyValidatorSetErr(err) {
    tb.Skip("Skipping simulation as all validators have been unbonded")

return
}

require.NoError(tb, err)

err = newApp.StoreConsensusParams(ctxB, exported.ConsensusParams)

require.NoError(tb, err)

tb.Log("comparing stores...")
		/ skip certain prefixes
    skipPrefixes := map[string][][]byte{
    stakingtypes.StoreKey: {
    stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey,
				stakingtypes.HistoricalInfoKey, stakingtypes.UnbondingIDKey, stakingtypes.UnbondingIndexKey,
				stakingtypes.UnbondingTypeKey,
				stakingtypes.ValidatorUpdatesKey, / todo (Alex): double check why there is a diff with test-sim-import-export
},
			authzkeeper.StoreKey:   {
    authzkeeper.GrantQueuePrefix
},
			feegrant.StoreKey:      {
    feegrant.FeeAllowanceQueueKeyPrefix
},
			slashingtypes.StoreKey: {
    slashingtypes.ValidatorMissedBlockBitmapKeyPrefix
},
}

AssertEqualStores(tb, app, newApp, app.SimulationManager().StoreDecoders, skipPrefixes)
})
}

/ Scenario:
/
/	Start a fresh node and run n blocks, export state
/	set up a new node instance, Init chain from exported genesis
/	run new instance for n blocks
func TestAppSimulationAfterImport(t *testing.T) {
    sims.Run(t, NewSimApp, setupStateFactory, func(tb testing.TB, ti sims.TestInstance[*SimApp], accs []simtypes.Account) {
    tb.Helper()
    app := ti.App
		tb.Log("exporting genesis...\n")

exported, err := app.ExportAppStateAndValidators(false, exportWithValidatorSet, exportAllModules)

require.NoError(tb, err)

tb.Log("importing genesis...\n")
    newTestInstance := sims.NewSimulationAppInstance(tb, ti.Cfg, NewSimApp)
    newApp := newTestInstance.App
		_, err = newApp.InitChain(&abci.RequestInitChain{
    AppStateBytes: exported.AppState,
    ChainId:       sims.SimAppChainID,
})
    if IsEmptyValidatorSetErr(err) {
    tb.Skip("Skipping simulation as all validators have been unbonded")

return
}

require.NoError(tb, err)
    newStateFactory := setupStateFactory(newApp)
		_, _, err = simulation.SimulateFromSeedX(
			tb,
			newTestInstance.AppLogger,
			sims.WriteToDebugLog(newTestInstance.AppLogger),
			newApp.BaseApp,
			newStateFactory.AppStateFn,
			simtypes.RandomAccounts,
			simtestutil.BuildSimulationOperations(newApp, newApp.AppCodec(), newTestInstance.Cfg, newApp.TxConfig()),
			newStateFactory.BlockedAddr,
			newTestInstance.Cfg,
			newStateFactory.Codec,
			ti.ExecLogWriter,
		)

require.NoError(tb, err)
})
}

func IsEmptyValidatorSetErr(err error)

bool {
    return err != nil && strings.Contains(err.Error(), "validator set is empty after InitGenesis")
}

func TestAppStateDeterminism(t *testing.T) {
    const numTimesToRunPerSeed = 3
	var seeds []int64
    if s := simcli.NewConfigFromFlags().Seed; s != simcli.DefaultSeedValue {
		/ We will be overriding the random seed and just run a single simulation on the provided seed value
    for j := 0; j < numTimesToRunPerSeed; j++ { / multiple rounds
			seeds = append(seeds, s)
}
	
}

else {
		/ setup with 3 random seeds
    for i := 0; i < 3; i++ {
    seed := rand.Int63()
    for j := 0; j < numTimesToRunPerSeed; j++ { / multiple rounds
				seeds = append(seeds, seed)
}
	
}
	
}
	/ overwrite default app config
    interBlockCachingAppFactory := func(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) *SimApp {
    if FlagEnableStreamingValue {
    m := map[string]any{
				"streaming.abci.keys":             []string{"*"
},
				"streaming.abci.plugin":           "abci_v1",
				"streaming.abci.stop-node-on-err": true,
}
    others := appOpts
			appOpts = appOptionsFn(func(k string)

any {
    if v, ok := m[k]; ok {
    return v
}

return others.Get(k)
})
}

return NewSimApp(logger, db, nil, true, appOpts, append(baseAppOptions, interBlockCacheOpt())...)
}

var mx sync.Mutex
    appHashResults := make(map[int64][][]byte)
    appSimLogger := make(map[int64][]simulation.LogWriter)
    captureAndCheckHash := func(tb testing.TB, ti sims.TestInstance[*SimApp], _ []simtypes.Account) {
    tb.Helper()

seed, appHash := ti.Cfg.Seed, ti.App.LastCommitID().Hash
		mx.Lock()

otherHashes, execWriters := appHashResults[seed], appSimLogger[seed]
    if len(otherHashes) < numTimesToRunPerSeed-1 {
    appHashResults[seed], appSimLogger[seed] = append(otherHashes, appHash), append(execWriters, ti.ExecLogWriter)
}

else { / cleanup
			delete(appHashResults, seed)

delete(appSimLogger, seed)
}

mx.Unlock()

var failNow bool
		/ and check that all app hashes per seed are equal for each iteration
    for i := 0; i < len(otherHashes); i++ {
    if !assert.Equal(tb, otherHashes[i], appHash) {
    execWriters[i].PrintLogs()

failNow = true
}
	
}
    if failNow {
    ti.ExecLogWriter.PrintLogs()

tb.Fatalf("non-determinism in seed %d", seed)
}
	
}
	/ run simulations
	sims.RunWithSeeds(t, interBlockCachingAppFactory, setupStateFactory, seeds, []byte{
}, captureAndCheckHash)
}

type ComparableStoreApp interface {
    LastBlockHeight()

int64
	NewContextLegacy(isCheckTx bool, header cmtproto.Header)

sdk.Context
	GetKey(storeKey string) *storetypes.KVStoreKey
	GetStoreKeys() []storetypes.StoreKey
}

func AssertEqualStores(
	tb testing.TB,
	app, newApp ComparableStoreApp,
	storeDecoders simtypes.StoreDecoderRegistry,
	skipPrefixes map[string][][]byte,
) {
    tb.Helper()
    ctxA := app.NewContextLegacy(true, cmtproto.Header{
    Height: app.LastBlockHeight()
})
    ctxB := newApp.NewContextLegacy(true, cmtproto.Header{
    Height: app.LastBlockHeight()
})
    storeKeys := app.GetStoreKeys()

require.NotEmpty(tb, storeKeys)
    for _, appKeyA := range storeKeys {
		/ only compare kvstores
    if _, ok := appKeyA.(*storetypes.KVStoreKey); !ok {
    continue
}
    keyName := appKeyA.Name()
    appKeyB := newApp.GetKey(keyName)
    storeA := ctxA.KVStore(appKeyA)
    storeB := ctxB.KVStore(appKeyB)

failedKVAs, failedKVBs := simtestutil.DiffKVStores(storeA, storeB, skipPrefixes[keyName])

require.Equal(tb, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare %s, key stores %s and %s", keyName, appKeyA, appKeyB)

tb.Logf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), appKeyA, appKeyB)
    if !assert.Equal(tb, 0, len(failedKVAs), simtestutil.GetSimulationLog(keyName, storeDecoders, failedKVAs, failedKVBs)) {
    for _, v := range failedKVAs {
    tb.Logf("store mismatch: %q\n", v)
}

tb.FailNow()
}
	
}
}

/ appOptionsFn is an adapter to the single method AppOptions interface
type appOptionsFn func(string)

any

func (f appOptionsFn)

Get(k string)

any {
    return f(k)
}

/ FauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
/ an IAVLStore for faster simulation speed.
func FauxMerkleModeOpt(bapp *baseapp.BaseApp) {
    bapp.SetFauxMerkleMode()
}

func FuzzFullAppSimulation(f *testing.F) {
    f.Fuzz(func(t *testing.T, rawSeed []byte) {
    if len(rawSeed) < 8 {
    t.Skip()

return
}

sims.RunWithSeeds(
			t,
			NewSimApp,
			setupStateFactory,
			[]int64{
    int64(binary.BigEndian.Uint64(rawSeed))
},
			rawSeed[8:],
		)
})
}