repo_description: Ethermint is a Cosmos SDK library for running scalable and interoperable EVM chains
repo_topics: blockchain cosmos-sdk ethereum evm go golang
code: // Copyright 2021 Evmos Foundation
  // This file is part of Evmos' Ethermint library.
  //
  // The Ethermint library is free software: you can redistribute it and/or modify
  // it under the terms of the GNU Lesser General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // The Ethermint library is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU Lesser General Public License for more details.
  //
  // You should have received a copy of the GNU Lesser General Public License
  // along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
  package app
  
  import (
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  	"os"
  	"path/filepath"
  
  	"github.com/gorilla/mux"
  	"github.com/rakyll/statik/fs"
  	"github.com/spf13/cast"
  
  	abci "github.com/tendermint/tendermint/abci/types"
  	"github.com/tendermint/tendermint/libs/log"
  	tmos "github.com/tendermint/tendermint/libs/os"
  	dbm "github.com/tendermint/tm-db"
  
  	"github.com/cosmos/cosmos-sdk/baseapp"
  	"github.com/cosmos/cosmos-sdk/client"
  	"github.com/cosmos/cosmos-sdk/client/grpc/node"
  	"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
  	"github.com/cosmos/cosmos-sdk/codec"
  	"github.com/cosmos/cosmos-sdk/codec/types"
  	"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/simapp"
  	simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
  	"github.com/cosmos/cosmos-sdk/store/streaming"
  	storetypes "github.com/cosmos/cosmos-sdk/store/types"
  	sdk "github.com/cosmos/cosmos-sdk/types"
  	"github.com/cosmos/cosmos-sdk/types/module"
  	"github.com/cosmos/cosmos-sdk/version"
  	"github.com/cosmos/cosmos-sdk/x/auth"
  	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"
  	authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
  	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"
  	"github.com/cosmos/cosmos-sdk/x/capability"
  	capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
  	capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
  	"github.com/cosmos/cosmos-sdk/x/crisis"
  	crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper"
  	crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
  	distr "github.com/cosmos/cosmos-sdk/x/distribution"
  	distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client"
  	distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
  	distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/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"
  	govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
  	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/params"
  	paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
  	paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
  	paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
  	paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal"
  	"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"
  	upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client"
  	upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
  	upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
  
  	"github.com/cosmos/ibc-go/v6/modules/apps/transfer"
  	ibctransferkeeper "github.com/cosmos/ibc-go/v6/modules/apps/transfer/keeper"
  	ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
  	ibc "github.com/cosmos/ibc-go/v6/modules/core"
  	ibcclient "github.com/cosmos/ibc-go/v6/modules/core/02-client"
  	ibcclientclient "github.com/cosmos/ibc-go/v6/modules/core/02-client/client"
  	porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
  	ibchost "github.com/cosmos/ibc-go/v6/modules/core/24-host"
  	ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper"
  
  	// unnamed import of statik for swagger UI support
  	_ "github.com/evmos/ethermint/client/docs/statik"
  
  	"github.com/evmos/ethermint/app/ante"
  	"github.com/evmos/ethermint/ethereum/eip712"
  	srvflags "github.com/evmos/ethermint/server/flags"
  	ethermint "github.com/evmos/ethermint/types"
  	"github.com/evmos/ethermint/x/evm"
  	evmkeeper "github.com/evmos/ethermint/x/evm/keeper"
  	evmtypes "github.com/evmos/ethermint/x/evm/types"
  	"github.com/evmos/ethermint/x/evm/vm/geth"
  	"github.com/evmos/ethermint/x/feemarket"
  	feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper"
  	feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
  
  	// Force-load the tracer engines to trigger registration due to Go-Ethereum v1.10.15 changes
  	_ "github.com/ethereum/go-ethereum/eth/tracers/js"
  	_ "github.com/ethereum/go-ethereum/eth/tracers/native"
  )
  
  func init() {
  	userHomeDir, err := os.UserHomeDir()
  	if err != nil {
  		panic(err)
  	}
  
  	DefaultNodeHome = filepath.Join(userHomeDir, ".ethermintd")
  }
  
  const appName = "ethermintd"
  
  var (
  	// DefaultNodeHome default home directories for the application daemon
  	DefaultNodeHome string
  
  	// ModuleBasics defines the module BasicManager is in charge of setting up basic,
  	// non-dependant module elements, such as codec registration
  	// and genesis verification.
  	ModuleBasics = module.NewBasicManager(
  		auth.AppModuleBasic{},
  		genutil.AppModuleBasic{},
  		bank.AppModuleBasic{},
  		capability.AppModuleBasic{},
  		staking.AppModuleBasic{},
  		mint.AppModuleBasic{},
  		distr.AppModuleBasic{},
  		gov.NewAppModuleBasic([]govclient.ProposalHandler{
  			paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.LegacyProposalHandler, upgradeclient.LegacyCancelProposalHandler,
  			ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler,
  		}),
  		params.AppModuleBasic{},
  		crisis.AppModuleBasic{},
  		slashing.AppModuleBasic{},
  		ibc.AppModuleBasic{},
  		authzmodule.AppModuleBasic{},
  		feegrantmodule.AppModuleBasic{},
  		upgrade.AppModuleBasic{},
  		evidence.AppModuleBasic{},
  		transfer.AppModuleBasic{},
  		vesting.AppModuleBasic{},
  		// Ethermint modules
  		evm.AppModuleBasic{},
  		feemarket.AppModuleBasic{},
  	)
  
  	// 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},
  		ibctransfertypes.ModuleName:    {authtypes.Minter, authtypes.Burner},
  		evmtypes.ModuleName:            {authtypes.Minter, authtypes.Burner}, // used for secure addition and subtraction of balance using module account
  	}
  
  	// module accounts that are allowed to receive tokens
  	allowedReceivingModAcc = map[string]bool{}
  )
  
  // var _ server.Application (*EthermintApp)(nil)
  
  // EthermintApp implements an extended ABCI application. It is an application
  // that may process transactions through Ethereum's EVM running atop of
  // Tendermint consensus.
  type EthermintApp struct {
  	*baseapp.BaseApp
  
  	// encoding
  	cdc               *codec.LegacyAmino
  	appCodec          codec.Codec
  	interfaceRegistry types.InterfaceRegistry
  
  	invCheckPeriod uint
  
  	// keys to access the substores
  	keys    map[string]*storetypes.KVStoreKey
  	tkeys   map[string]*storetypes.TransientStoreKey
  	memKeys map[string]*storetypes.MemoryStoreKey
  
  	// keepers
  	AccountKeeper    authkeeper.AccountKeeper
  	BankKeeper       bankkeeper.Keeper
  	CapabilityKeeper *capabilitykeeper.Keeper
  	StakingKeeper    stakingkeeper.Keeper
  	SlashingKeeper   slashingkeeper.Keeper
  	MintKeeper       mintkeeper.Keeper
  	DistrKeeper      distrkeeper.Keeper
  	GovKeeper        govkeeper.Keeper
  	CrisisKeeper     crisiskeeper.Keeper
  	UpgradeKeeper    upgradekeeper.Keeper
  	ParamsKeeper     paramskeeper.Keeper
  	FeeGrantKeeper   feegrantkeeper.Keeper
  	AuthzKeeper      authzkeeper.Keeper
  	IBCKeeper        *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
  	EvidenceKeeper   evidencekeeper.Keeper
  	TransferKeeper   ibctransferkeeper.Keeper
  
  	// make scoped keepers public for test purposes
  	ScopedIBCKeeper      capabilitykeeper.ScopedKeeper
  	ScopedTransferKeeper capabilitykeeper.ScopedKeeper
  
  	// Ethermint keepers
  	EvmKeeper       *evmkeeper.Keeper
  	FeeMarketKeeper feemarketkeeper.Keeper
  
  	// the module manager
  	mm *module.Manager
  
  	// the configurator
  	configurator module.Configurator
  }
  
  // NewEthermintApp returns a reference to a new initialized Ethermint application.
  func NewEthermintApp(
  	logger log.Logger,
  	db dbm.DB,
  	traceStore io.Writer,
  	loadLatest bool,
  	skipUpgradeHeights map[int64]bool,
  	homePath string,
  	invCheckPeriod uint,
  	encodingConfig simappparams.EncodingConfig,
  	appOpts servertypes.AppOptions,
  	baseAppOptions ...func(*baseapp.BaseApp),
  ) *EthermintApp {
  	appCodec := encodingConfig.Codec
  	cdc := encodingConfig.Amino
  	interfaceRegistry := encodingConfig.InterfaceRegistry
  
  	eip712.SetEncodingConfig(encodingConfig)
  
  	// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
  	bApp := baseapp.NewBaseApp(
  		appName,
  		logger,
  		db,
  		encodingConfig.TxConfig.TxDecoder(),
  		baseAppOptions...,
  	)
  	bApp.SetCommitMultiStoreTracer(traceStore)
  	bApp.SetVersion(version.Version)
  	bApp.SetInterfaceRegistry(interfaceRegistry)
  
  	keys := sdk.NewKVStoreKeys(
  		// SDK keys
  		authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
  		minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
  		govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey,
  		evidencetypes.StoreKey, capabilitytypes.StoreKey,
  		feegrant.StoreKey, authzkeeper.StoreKey,
  		// ibc keys
  		ibchost.StoreKey, ibctransfertypes.StoreKey,
  		// ethermint keys
  		evmtypes.StoreKey, feemarkettypes.StoreKey,
  	)
  
  	// Add the EVM transient store key
  	tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
  	memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
  
  	// load state streaming if enabled
  	if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil {
  		fmt.Printf("failed to load state streaming: %s", err)
  		os.Exit(1)
  	}
  
  	app := &EthermintApp{
  		BaseApp:           bApp,
  		cdc:               cdc,
  		appCodec:          appCodec,
  		interfaceRegistry: interfaceRegistry,
  		invCheckPeriod:    invCheckPeriod,
  		keys:              keys,
  		tkeys:             tkeys,
  		memKeys:           memKeys,
  	}
  
  	// init params keeper and subspaces
  	app.ParamsKeeper = initParamsKeeper(appCodec, cdc, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey])
  	// set the BaseApp's parameter store
  	bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable()))
  
  	// add capability keeper and ScopeToModule for ibc module
  	app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey])
  
  	scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName)
  	scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName)
  
  	// Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating
  	// their scoped modules in `NewApp` with `ScopeToModule`
  	app.CapabilityKeeper.Seal()
  
  	// use custom Ethermint account for contracts
  	app.AccountKeeper = authkeeper.NewAccountKeeper(
  		appCodec, keys[authtypes.StoreKey],
  		app.GetSubspace(authtypes.ModuleName),
  		ethermint.ProtoAccount,
  		maccPerms,
  		sdk.GetConfig().GetBech32AccountAddrPrefix(),
  	)
  	app.BankKeeper = bankkeeper.NewBaseKeeper(
  		appCodec,
  		keys[banktypes.StoreKey],
  		app.AccountKeeper,
  		app.GetSubspace(banktypes.ModuleName),
  		app.BlockedAddrs(),
  	)
  	stakingKeeper := stakingkeeper.NewKeeper(
  		appCodec, keys[stakingtypes.StoreKey],
  		app.AccountKeeper,
  		app.BankKeeper,
  		app.GetSubspace(stakingtypes.ModuleName),
  	)
  	app.MintKeeper = mintkeeper.NewKeeper(
  		appCodec,
  		keys[minttypes.StoreKey],
  		app.GetSubspace(minttypes.ModuleName),
  		&stakingKeeper,
  		app.AccountKeeper,
  		app.BankKeeper,
  		authtypes.FeeCollectorName,
  	)
  	app.DistrKeeper = distrkeeper.NewKeeper(
  		appCodec,
  		keys[distrtypes.StoreKey],
  		app.GetSubspace(distrtypes.ModuleName),
  		app.AccountKeeper,
  		app.BankKeeper,
  		&stakingKeeper,
  		authtypes.FeeCollectorName,
  	)
  	app.SlashingKeeper = slashingkeeper.NewKeeper(
  		appCodec,
  		keys[slashingtypes.StoreKey],
  		&stakingKeeper,
  		app.GetSubspace(slashingtypes.ModuleName),
  	)
  	app.CrisisKeeper = crisiskeeper.NewKeeper(
  		app.GetSubspace(crisistypes.ModuleName),
  		invCheckPeriod,
  		app.BankKeeper,
  		authtypes.FeeCollectorName,
  	)
  	app.FeeGrantKeeper = feegrantkeeper.NewKeeper(
  		appCodec,
  		keys[feegrant.StoreKey],
  		app.AccountKeeper)
  
  	// set the governance module account as the authority for conducting upgrades
  	app.UpgradeKeeper = upgradekeeper.NewKeeper(
  		skipUpgradeHeights,
  		keys[upgradetypes.StoreKey],
  		appCodec,
  		homePath,
  		app.BaseApp,
  		authtypes.NewModuleAddress(govtypes.ModuleName).String())
  
  	// register the staking hooks
  	// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
  	app.StakingKeeper = *stakingKeeper.SetHooks(
  		stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(),
  			app.SlashingKeeper.Hooks()),
  	)
  
  	app.AuthzKeeper = authzkeeper.NewKeeper(
  		keys[authzkeeper.StoreKey],
  		appCodec,
  		app.MsgServiceRouter(),
  		app.AccountKeeper)
  
  	tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer))
  
  	// Create Ethermint keepers
  	feeMarketSs := app.GetSubspace(feemarkettypes.ModuleName)
  	app.FeeMarketKeeper = feemarketkeeper.NewKeeper(
  		appCodec, authtypes.NewModuleAddress(govtypes.ModuleName),
  		keys[feemarkettypes.StoreKey], tkeys[feemarkettypes.TransientKey], feeMarketSs,
  	)
  
  	// Set authority to x/gov module account to only expect the module account to update params
  	evmSs := app.GetSubspace(evmtypes.ModuleName)
  	app.EvmKeeper = evmkeeper.NewKeeper(
  		appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], authtypes.NewModuleAddress(govtypes.ModuleName),
  		app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
  		nil, geth.NewEVM, tracer, evmSs,
  	)
  
  	// Create IBC Keeper
  	app.IBCKeeper = ibckeeper.NewKeeper(
  		appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper,
  	)
  
  	// register the proposal types
  	govRouter := govv1beta1.NewRouter()
  	govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
  		AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
  		AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
  		AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
  		AddRoute(ibchost.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
  	govConfig := govtypes.DefaultConfig()
  	/*
  		Example of setting gov params:
  		govConfig.MaxMetadataLen = 10000
  	*/
  	govKeeper := govkeeper.NewKeeper(
  		appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
  		&stakingKeeper, govRouter, app.MsgServiceRouter(), govConfig,
  	)
  
  	app.GovKeeper = *govKeeper.SetHooks(
  		govtypes.NewMultiGovHooks(
  		// register the governance hooks
  		),
  	)
  
  	// Create Transfer Keepers
  	app.TransferKeeper = ibctransferkeeper.NewKeeper(
  		appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName),
  		app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
  		app.AccountKeeper, app.BankKeeper, scopedTransferKeeper,
  	)
  	transferModule := transfer.NewAppModule(app.TransferKeeper)
  	transferIBCModule := transfer.NewIBCModule(app.TransferKeeper)
  
  	// Create static IBC router, add transfer route, then set and seal it
  	ibcRouter := porttypes.NewRouter()
  	ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule)
  	app.IBCKeeper.SetRouter(ibcRouter)
  
  	// create evidence keeper with router
  	evidenceKeeper := evidencekeeper.NewKeeper(
  		appCodec, keys[evidencetypes.StoreKey], &app.StakingKeeper, app.SlashingKeeper,
  	)
  	// If evidence needs to be handled for the app, set routes in router here and seal
  	app.EvidenceKeeper = *evidenceKeeper
  
  	/****  Module Options ****/
  
  	// NOTE: we may consider parsing `appOpts` inside module constructors. For the moment
  	// we prefer to be more strict in what arguments the modules expect.
  	skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants))
  
  	// NOTE: Any module instantiated in the module manager that is later modified
  	// must be passed by reference here.
  	app.mm = module.NewManager(
  		// SDK app modules
  		genutil.NewAppModule(
  			app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx,
  			encodingConfig.TxConfig,
  		),
  		auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
  		vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
  		bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
  		capability.NewAppModule(appCodec, *app.CapabilityKeeper),
  		crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
  		feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
  		gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
  		mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
  		slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
  		distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
  		staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
  		upgrade.NewAppModule(app.UpgradeKeeper),
  		evidence.NewAppModule(app.EvidenceKeeper),
  		params.NewAppModule(app.ParamsKeeper),
  		authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
  
  		// ibc modules
  		ibc.NewAppModule(app.IBCKeeper),
  		transferModule,
  		// Ethermint app modules
  		feemarket.NewAppModule(app.FeeMarketKeeper, feeMarketSs),
  		evm.NewAppModule(app.EvmKeeper, app.AccountKeeper, evmSs),
  	)
  
  	// 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: upgrade module must go first to handle software upgrades.
  	// NOTE: staking module is required if HistoricalEntries param > 0
  	// NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC)
  	app.mm.SetOrderBeginBlockers(
  		upgradetypes.ModuleName,
  		capabilitytypes.ModuleName,
  		feemarkettypes.ModuleName,
  		evmtypes.ModuleName,
  		minttypes.ModuleName,
  		distrtypes.ModuleName,
  		slashingtypes.ModuleName,
  		evidencetypes.ModuleName,
  		stakingtypes.ModuleName,
  		ibchost.ModuleName,
  		// no-op modules
  		ibctransfertypes.ModuleName,
  		authtypes.ModuleName,
  		banktypes.ModuleName,
  		govtypes.ModuleName,
  		crisistypes.ModuleName,
  		genutiltypes.ModuleName,
  		authz.ModuleName,
  		feegrant.ModuleName,
  		paramstypes.ModuleName,
  		vestingtypes.ModuleName,
  	)
  
  	// NOTE: fee market module must go last in order to retrieve the block gas used.
  	app.mm.SetOrderEndBlockers(
  		crisistypes.ModuleName,
  		govtypes.ModuleName,
  		stakingtypes.ModuleName,
  		evmtypes.ModuleName,
  		feemarkettypes.ModuleName,
  		// no-op modules
  		ibchost.ModuleName,
  		ibctransfertypes.ModuleName,
  		capabilitytypes.ModuleName,
  		authtypes.ModuleName,
  		banktypes.ModuleName,
  		distrtypes.ModuleName,
  		slashingtypes.ModuleName,
  		minttypes.ModuleName,
  		genutiltypes.ModuleName,
  		evidencetypes.ModuleName,
  		authz.ModuleName,
  		feegrant.ModuleName,
  		paramstypes.ModuleName,
  		upgradetypes.ModuleName,
  		vestingtypes.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.
  	// NOTE: Capability module must occur first so that it can initialize any capabilities
  	// so that other modules that want to create or claim capabilities afterwards in InitChain
  	// can do so safely.
  	app.mm.SetOrderInitGenesis(
  		// SDK modules
  		capabilitytypes.ModuleName,
  		authtypes.ModuleName,
  		banktypes.ModuleName,
  		distrtypes.ModuleName,
  		stakingtypes.ModuleName,
  		slashingtypes.ModuleName,
  		govtypes.ModuleName,
  		minttypes.ModuleName,
  		ibchost.ModuleName,
  		// evm module denomination is used by the feemarket module, in AnteHandle
  		evmtypes.ModuleName,
  		// NOTE: feemarket need to be initialized before genutil module:
  		// gentx transactions use MinGasPriceDecorator.AnteHandle
  		feemarkettypes.ModuleName,
  		genutiltypes.ModuleName,
  		evidencetypes.ModuleName,
  		ibctransfertypes.ModuleName,
  		authz.ModuleName,
  		feegrant.ModuleName,
  		paramstypes.ModuleName,
  		upgradetypes.ModuleName,
  		vestingtypes.ModuleName,
  		// NOTE: crisis module must go at the end to check for invariants on each module
  		crisistypes.ModuleName,
  	)
  
  	// Uncomment if you want to set a custom migration order here.
  	// app.mm.SetOrderMigrations(custom order)
  
  	app.mm.RegisterInvariants(&app.CrisisKeeper)
  	app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino)
  	app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())
  	app.mm.RegisterServices(app.configurator)
  
  	// RegisterUpgradeHandlers is used for registering any on-chain upgrades.
  	// Make sure it's called after `app.mm` and `app.configurator` are set.
  	app.RegisterUpgradeHandlers()
  
  	// add test gRPC service for testing gRPC queries in isolation
  	// testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{})
  
  	// initialize stores
  	app.MountKVStores(keys)
  	app.MountTransientStores(tkeys)
  	app.MountMemoryStores(memKeys)
  
  	// initialize BaseApp
  	app.SetInitChainer(app.InitChainer)
  	app.SetBeginBlocker(app.BeginBlocker)
  	app.SetEndBlocker(app.EndBlocker)
  	app.setAnteHandler(encodingConfig.TxConfig, cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)))
  	// 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 empty 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 {
  			tmos.Exit(err.Error())
  		}
  	}
  
  	app.ScopedIBCKeeper = scopedIBCKeeper
  	app.ScopedTransferKeeper = scopedTransferKeeper
  
  	return app
  }
  
  // use Ethermint's custom AnteHandler
  func (app *EthermintApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64) {
  	anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
  		AccountKeeper:          app.AccountKeeper,
  		BankKeeper:             app.BankKeeper,
  		SignModeHandler:        txConfig.SignModeHandler(),
  		FeegrantKeeper:         app.FeeGrantKeeper,
  		SigGasConsumer:         ante.DefaultSigVerificationGasConsumer,
  		IBCKeeper:              app.IBCKeeper,
  		EvmKeeper:              app.EvmKeeper,
  		FeeMarketKeeper:        app.FeeMarketKeeper,
  		MaxTxGasWanted:         maxGasWanted,
  		ExtensionOptionChecker: ethermint.HasDynamicFeeExtensionOption,
  		TxFeeChecker:           ante.NewDynamicFeeChecker(app.EvmKeeper),
  		DisabledAuthzMsgs: []string{
  			sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}),
  			sdk.MsgTypeURL(&vestingtypes.MsgCreateVestingAccount{}),
  		},
  	})
  	if err != nil {
  		panic(err)
  	}
  
  	app.SetAnteHandler(anteHandler)
  }
  
  func (app *EthermintApp) setPostHandler() {
  	postHandler, err := posthandler.NewPostHandler(
  		posthandler.HandlerOptions{},
  	)
  	if err != nil {
  		panic(err)
  	}
  
  	app.SetPostHandler(postHandler)
  }
  
  // Name returns the name of the App
  func (app *EthermintApp) Name() string { return app.BaseApp.Name() }
  
  // BeginBlocker updates every begin block
  func (app *EthermintApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
  	return app.mm.BeginBlock(ctx, req)
  }
  
  // EndBlocker updates every end block
  func (app *EthermintApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
  	return app.mm.EndBlock(ctx, req)
  }
  
  // InitChainer updates at chain initialization
  func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
  	var genesisState simapp.GenesisState
  	if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil {
  		panic(err)
  	}
  	app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap())
  	return app.mm.InitGenesis(ctx, app.appCodec, genesisState)
  }
  
  // LoadHeight loads state at a particular height
  func (app *EthermintApp) LoadHeight(height int64) error {
  	return app.LoadVersion(height)
  }
  
  // ModuleAccountAddrs returns all the app's module account addresses.
  func (app *EthermintApp) ModuleAccountAddrs() map[string]bool {
  	modAccAddrs := make(map[string]bool)
  	for acc := range maccPerms {
  		modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true
  	}
  
  	return modAccAddrs
  }
  
  // BlockedAddrs returns all the app's module account addresses that are not
  // allowed to receive external tokens.
  func (app *EthermintApp) BlockedAddrs() map[string]bool {
  	blockedAddrs := make(map[string]bool)
  	for acc := range maccPerms {
  		blockedAddrs[authtypes.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc]
  	}
  
  	return blockedAddrs
  }
  
  // LegacyAmino returns EthermintApp'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 *EthermintApp) LegacyAmino() *codec.LegacyAmino {
  	return app.cdc
  }
  
  // AppCodec returns EthermintApp'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 *EthermintApp) AppCodec() codec.Codec {
  	return app.appCodec
  }
  
  // InterfaceRegistry returns EthermintApp's InterfaceRegistry
  func (app *EthermintApp) InterfaceRegistry() types.InterfaceRegistry {
  	return app.interfaceRegistry
  }
  
  // GetKey returns the KVStoreKey for the provided store key.
  //
  // NOTE: This is solely to be used for testing purposes.
  func (app *EthermintApp) GetKey(storeKey string) *storetypes.KVStoreKey {
  	return app.keys[storeKey]
  }
  
  // GetTKey returns the TransientStoreKey for the provided store key.
  //
  // NOTE: This is solely to be used for testing purposes.
  func (app *EthermintApp) GetTKey(storeKey string) *storetypes.TransientStoreKey {
  	return app.tkeys[storeKey]
  }
  
  // GetMemKey returns the MemStoreKey for the provided mem key.
  //
  // NOTE: This is solely used for testing purposes.
  func (app *EthermintApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey {
  	return app.memKeys[storeKey]
  }
  
  // GetSubspace returns a param subspace for a given module name.
  //
  // NOTE: This is solely to be used for testing purposes.
  func (app *EthermintApp) GetSubspace(moduleName string) paramstypes.Subspace {
  	subspace, _ := app.ParamsKeeper.GetSubspace(moduleName)
  	return subspace
  }
  
  // RegisterAPIRoutes registers all application module routes with the provided
  // API server.
  func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
  	clientCtx := apiSvr.ClientCtx
  	// Register new tx routes from grpc-gateway.
  	authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
  	// Register new tendermint queries routes from grpc-gateway.
  	tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
  	// Register node gRPC service for grpc-gateway.
  	node.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
  
  	// Register grpc-gateway routes for all modules.
  	ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
  
  	// register swagger API from root so that other applications can override easily
  	if apiConfig.Swagger {
  		RegisterSwaggerAPI(clientCtx, apiSvr.Router)
  	}
  }
  
  // RegisterTxService implements the Application.RegisterTxService method.
  func (app *EthermintApp) RegisterTxService(clientCtx client.Context) {
  	authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
  }
  
  // RegisterTendermintService implements the Application.RegisterTendermintService method.
  func (app *EthermintApp) RegisterTendermintService(clientCtx client.Context) {
  	tmservice.RegisterTendermintService(
  		clientCtx,
  		app.BaseApp.GRPCQueryRouter(),
  		app.interfaceRegistry,
  		app.Query,
  	)
  }
  
  // RegisterNodeService registers the node gRPC service on the provided
  // application gRPC query router.
  func (app *EthermintApp) RegisterNodeService(clientCtx client.Context) {
  	node.RegisterNodeService(clientCtx, app.GRPCQueryRouter())
  }
  
  // RegisterSwaggerAPI registers swagger route with API Server
  func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) {
  	statikFS, err := fs.New()
  	if err != nil {
  		panic(err)
  	}
  
  	staticServer := http.FileServer(statikFS)
  	rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer))
  }
  
  // GetMaccPerms returns a copy of the module account permissions
  func GetMaccPerms() map[string][]string {
  	dupMaccPerms := make(map[string][]string)
  	for k, v := range maccPerms {
  		dupMaccPerms[k] = v
  	}
  	return dupMaccPerms
  }
  
  // initParamsKeeper init params keeper and its subspaces
  func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper {
  	paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
  
  	// SDK subspaces
  	paramsKeeper.Subspace(authtypes.ModuleName)
  	paramsKeeper.Subspace(banktypes.ModuleName)
  	paramsKeeper.Subspace(stakingtypes.ModuleName)
  	paramsKeeper.Subspace(minttypes.ModuleName)
  	paramsKeeper.Subspace(distrtypes.ModuleName)
  	paramsKeeper.Subspace(slashingtypes.ModuleName)
  	paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable())
  	paramsKeeper.Subspace(crisistypes.ModuleName)
  	paramsKeeper.Subspace(ibctransfertypes.ModuleName)
  	paramsKeeper.Subspace(ibchost.ModuleName)
  	// ethermint subspaces
  	paramsKeeper.Subspace(evmtypes.ModuleName).WithKeyTable(evmtypes.ParamKeyTable()) //nolint: staticcheck
  	paramsKeeper.Subspace(feemarkettypes.ModuleName).WithKeyTable(feemarkettypes.ParamKeyTable())
  	return paramsKeeper
  }
  