Skip to main content
Version: v0.50

Upgrading Cosmos SDK

This guide provides instructions for upgrading to specific versions of Cosmos SDK. Note, always read the SimApp section for more information on application wiring updates.


Migration to CometBFT (Part 2)

The Cosmos SDK has migrated in its previous versions, to CometBFT. Some functions have been renamed to reflect the naming change.

Following an exhaustive list:

  • client.TendermintRPC -> client.CometRPC
  • clitestutil.MockTendermintRPC -> clitestutil.MockCometRPC
  • clitestutilgenutil.CreateDefaultTendermintConfig -> clitestutilgenutil.CreateDefaultCometConfig
  • Package client/grpc/tmservice -> client/grpc/cmtservice

Additionally, the commands and flags mentioning tendermint have been renamed to comet. These commands and flags are still supported for backward compatibility.

For backward compatibility, the **/tendermint/** gRPC services are still supported.

Additionally, the SDK is starting its abstraction from CometBFT Go types through the codebase:

  • The usage of the CometBFT logger has been replaced by the Cosmos SDK logger interface (
  • The usage of has been replaced by []byte.
  • Usage of an application genesis (see genutil).

Enable Vote Extensions


This is an optional feature that is disabled by default.

Once all the code changes required to implement Vote Extensions are in place, they can be enabled by setting the consensus param Abci.VoteExtensionsEnableHeight to a value greater than zero.

In a new chain, this can be done in the genesis.json file.

For existing chains this can be done in two ways:

  • During an upgrade the value is set in an upgrade handler.
  • A governance proposal that changes the consensus param after a coordinated upgrade has taken place.


All ABCI methods now accept a pointer to the request and response types defined by CometBFT. In addition, they also return errors. An ABCI method should only return errors in cases where a catastrophic failure has occurred and the application should halt. However, this is abstracted away from the application developer. Any handler that an application can define or set that returns an error, will gracefully by handled by BaseApp on behalf of the application.

BaseApp calls of BeginBlock & Endblock are now private but are still exposed to the application to define via the Manager type. FinalizeBlock is public and should be used in order to test and run operations. This means that although BeginBlock & Endblock no longer exist in the ABCI interface, they are automatically called by BaseApp during FinalizeBlock. Specifically, the order of operations is BeginBlock -> DeliverTx (for all txs) -> EndBlock.

ABCI++ 2.0 also brings ExtendVote and VerifyVoteExtension ABCI methods. These methods allow applications to extend and verify pre-commit votes. The Cosmos SDK allows an application to define handlers for these methods via ExtendVoteHandler and VerifyVoteExtensionHandler respectively. Please see here for more info.

Set PreBlocker

A SetPreBlocker method has been added to BaseApp. This is essential for BaseApp to run PreBlock which runs before begin blocker other modules, and allows to modify consensus parameters, and the changes are visible to the following state machine logics. Read more about other use cases here.

depinject / app v2 users need to add x/upgrade in their app_config.go / app.yml:

+ PreBlockers: []string{
+ upgradetypes.ModuleName,
+ },
BeginBlockers: []string{
- upgradetypes.ModuleName,

When using (legacy) application wiring, the following must be added to app.go:

+ upgradetypes.ModuleName,

- upgradetypes.ModuleName,

+ app.SetPreBlocker(app.PreBlocker)

// ... //

+func (app *SimApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
+ return app.ModuleManager.PreBlock(ctx, req)


The log section of abci.TxResult is not populated in the case of successful msg(s) execution. Instead a new attribute is added to all messages indicating the msg_index which identifies which events and attributes relate the same transaction.

BeginBlock & EndBlock Events are now emitted through FinalizeBlock but have an added attribute, mode=BeginBlock|EndBlock, to identify if the event belongs to BeginBlock or EndBlock.

Config files

Confix is a new SDK tool for modifying and migrating configuration of the SDK. It is the replacement of the config.Cmd command from the client/config package.

Use the following command to migrate your configuration:

simd config migrate v0.50

If you were using <appd> config [key] or <appd> config [key] [value] to set and get values from the client.toml, replace it with <appd> config get client [key] and <appd> config set client [key] [value]. The extra verbosity is due to the extra functionalities added in config.

More information about confix and how to add it in your application binary in the documentation.


gRPC-Web is now listening to the same address and port as the gRPC Gateway API server (default: localhost:1317). The possibility to listen to a different address has been removed, as well as its settings. Use confix to clean-up your app.toml. A nginx (or alike) reverse-proxy can be set to keep the previous behavior.

Database Support

ClevelDB, BoltDB and BadgerDB are not supported anymore. To migrate from a unsupported database to a supported database please use a database migration tool.


With the deprecation of the Amino JSON codec defined in cosmos/gogoproto in favor of the protoreflect powered x/tx/aminojson codec, module developers are encouraged verify that their messages have the correct protobuf annotations to deterministically produce identical output from both codecs.

For core SDK types equivalence is asserted by generative testing of SignableTypes in TestAminoJSON_Equivalence.

TODO: summarize proto annotation requirements.


The gogoproto.goproto_stringer = false annotation has been removed from most proto files. This means that the String() method is being generated for types that previously had this annotation. The generated String() method uses proto.CompactTextString for stringifying structs. Verify the usage of the modified String() methods and double-check that they are not used in state-machine code.


In this section we describe the changes made in Cosmos SDK' SimApp. These changes are directly applicable to your application wiring.

Module Assertions

Previously, all modules were required to be set in OrderBeginBlockers, OrderEndBlockers and OrderInitGenesis / OrderExportGenesis in app.go / app_config.go. This is no longer the case, the assertion has been loosened to only require modules implementing, respectively, the appmodule.HasBeginBlocker, appmodule.HasEndBlocker and appmodule.HasGenesis / module.HasGenesis interfaces.

Module wiring

The following modules NewKeeper function now take a KVStoreService instead of a StoreKey:

  • x/auth
  • x/authz
  • x/bank
  • x/consensus
  • x/crisis
  • x/distribution
  • x/evidence
  • x/feegrant
  • x/gov
  • x/mint
  • x/nft
  • x/slashing
  • x/upgrade

Users using depinject / app v2 do not need any changes, this is abstracted for them.

Users manually wiring their chain need to use the runtime.NewKVStoreService method to create a KVStoreService from a StoreKey:

app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(
- keys[consensusparamtypes.StoreKey]
+ runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]),


Replace all your CometBFT logger imports by

Additionally, depinject / app v2 users must now supply a logger through the main depinject.Supply function instead of passing it to appBuilder.Build.

appConfig = depinject.Configs(
// supply the application options
+ logger,
- app.App = appBuilder.Build(logger, db, traceStore, baseAppOptions...)
+ app.App = appBuilder.Build(db, traceStore, baseAppOptions...)

User manually wiring their chain need to add the logger argument when creating the x/bank keeper.

Module Basics

Previously, the ModuleBasics was a global variable that was used to register all modules' AppModuleBasic implementation. The global variable has been removed and the basic module manager can be now created from the module manager.

This is automatically done for depinject / app v2 users, however for supplying different app module implementation, pass them via depinject.Supply in the main AppConfig (app_config.go):

// supply custom module basics
genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
govtypes.ModuleName: gov.NewAppModuleBasic(

Users manually wiring their chain need to use the new module.NewBasicManagerFromManager function, after the module manager creation, and pass a map[string]module.AppModuleBasic as argument for optionally overriding some module's AppModuleBasic.


AutoCLI has been implemented by the SDK for all its module CLI queries. This means chains must add the following in their root.go to enable AutoCLI in their application:

if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {

Where autoCliOpts is the autocli options of the app, containing all modules and codecs. That value can injected by depinject (see root_v2.go) or manually provided by the app (see legacy app.go).


Not doing this will result in all core SDK modules queries not to be included in the binary.

Additionally AutoCLI automatically adds the custom modules commands to the root command for all modules implementing the appmodule.AppModule interface. This means, after ensuring all the used modules implement this interface, the following can be removed from your root.go:

func txCommand() *cobra.Command {
- appd.ModuleBasics.AddTxCommands(cmd)
func queryCommand() *cobra.Command {
- appd.ModuleBasics.AddQueryCommands(cmd)



References to types/math.go which contained aliases for math types aliasing the package have been removed. Import directly the package instead.


References to types/store.go which contained aliases for store types have been remapped to point to appropriate store/types, hence the types/store.go file is no longer needed and has been removed.

Extract Store to a standalone module

The store module is extracted to have a separate go.mod file which allows it be a standalone module. All the store imports are now renamed to use instead of across the SDK.


ADR-38 has been implemented in the SDK.

To continue using state streaming, replace streaming.LoadStreamingServices by the following in your app.go:

if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil {


The return type of the interface method TxConfig.SignModeHandler() has been changed from x/auth/signing.SignModeHandler to x/tx/signing.HandlerMap. This change is transparent to most users as the TxConfig interface is typically implemented by private x/auth/tx.config struct (as returned by auth.NewTxConfig) which has been updated to return the new type. If users have implemented their own TxConfig interface, they will need to update their implementation to return the new type.

Textual sign mode

A new sign mode is available in the SDK that produces more human readable output, currently only available on Ledger devices but soon to be implemented in other UIs.


This sign mode does not allow offline signing

When using (legacy) application wiring, the following must be added to app.go after setting the app's 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(
if err != nil {
log.Fatalf("Failed to create new TxConfig with options: %v", err)
app.txConfig = txConfig

When using depinject / app v2, it's enabled by default if there's a bank keeper present.

And in the application client (usually root.go):

    if !clientCtx.Offline {
txConfigOpts.EnabledSignModes = append(txConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL)
txConfigOpts.TextualCoinMetadataQueryFn = txmodule.NewGRPCCoinMetadataQueryFn(clientCtx)
txConfigWithTextual, err := tx.NewTxConfigWithOptions(
if err != nil {
return err
clientCtx = clientCtx.WithTxConfig(txConfigWithTextual)

When using depinject / app v2, the a tx config should be recreated from the txConfigOpts to use NewGRPCCoinMetadataQueryFn instead of depending on the bank keeper (that is used in the server).

To learn more see the docs and the ADR-050.



  • RFC 001 has defined a simplification of the message validation process for modules. The sdk.Msg interface has been updated to not require the implementation of the ValidateBasic method. It is now recommended to validate message directly in the message server. When the validation is performed in the message server, the ValidateBasic method on a message is no longer required and can be removed.

  • Messages no longer need to implement the LegacyMsg interface and implementations of GetSignBytes can be deleted. Because of this change, global legacy Amino codec definitions and their registration in init() can safely be removed as well.

  • The AppModuleBasic interface has been simplified. Defining GetTxCmd() *cobra.Command and GetQueryCmd() *cobra.Command is no longer required. The module manager detects when module commands are defined. If AutoCLI is enabled, EnhanceRootCommand() will add the auto-generated commands to the root command, unless a custom module command is defined and register that one instead.

  • The following modules' Keeper methods now take in a context.Context instead of sdk.Context. Any module that has an interfaces for them (like "expected keepers") will need to update and re-generate mocks if needed:

    • x/authz
    • x/bank
    • x/mint
    • x/crisis
    • x/distribution
    • x/evidence
    • x/gov
    • x/slashing
    • x/upgrade
  • BeginBlock and EndBlock have changed their signature, so it is important that any module implementing them are updated accordingly.

- BeginBlock(sdk.Context, abci.RequestBeginBlock)
+ BeginBlock(context.Context) error
- EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate
+ EndBlock(context.Context) error

In case a module requires to return abci.ValidatorUpdate from EndBlock, it can use the HasABCIEndBlock interface instead.

- EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate
+ EndBlock(context.Context) ([]abci.ValidatorUpdate, error)

It is possible to ensure that a module implements the correct interfaces by using compiler assertions in your x/{moduleName}/module.go:

var (
_ module.AppModuleBasic = (*AppModule)(nil)
_ module.AppModuleSimulation = (*AppModule)(nil)
_ module.HasGenesis = (*AppModule)(nil)

_ appmodule.AppModule = (*AppModule)(nil)
_ appmodule.HasBeginBlocker = (*AppModule)(nil)
_ appmodule.HasEndBlocker = (*AppModule)(nil)

Read more on those interfaces here.

  • GetSigners() is no longer required to be implemented on Msg types. The SDK will automatically infer the signers from the Signer field on the message. The signer field is required on all messages unless using a custom signer function.

To find out more please read the signer field & here documentation.


For ante handler construction via ante.NewAnteHandler, the field ante.HandlerOptions.SignModeHandler has been updated to x/tx/signing/HandlerMap from x/auth/signing/SignModeHandler. Callers typically fetch this value from client.TxConfig.SignModeHandler() (which is also changed) so this change should be transparent to most users.


Capability has been moved to IBC Go. IBC v8 will contain the necessary changes to incorporate the new module location.


The Cosmos SDK has migrated from a CometBFT genesis to a application managed genesis file. The genesis is now fully handled by x/genutil. This has no consequences for running chains:

  • Importing a CometBFT genesis is still supported.
  • Exporting a genesis now exports the genesis as an application genesis.

When needing to read an application genesis, use the following helpers from the x/genutil/types package:

// AppGenesisFromReader reads the AppGenesis from the reader.
func AppGenesisFromReader(reader io.Reader) (*AppGenesis, error)

// AppGenesisFromFile reads the AppGenesis from the provided file.
func AppGenesisFromFile(genFile string) (*AppGenesis, error)


Expedited Proposals

The gov v1 module now supports expedited governance proposals. When a proposal is expedited, the voting period will be shortened to ExpeditedVotingPeriod parameter. An expedited proposal must have an higher voting threshold than a classic proposal, that threshold is defined with the ExpeditedThreshold parameter.

Cancelling Proposals

The gov module now supports cancelling governance proposals. When a proposal is canceled, all the deposits of the proposal are either burnt or sent to ProposalCancelDest address. The deposits burn rate will be determined by a new parameter called ProposalCancelRatio parameter.

1. deposits * proposal_cancel_ratio will be burned or sent to `ProposalCancelDest` address , if `ProposalCancelDest` is empty then deposits will be burned.
2. deposits * (1 - proposal_cancel_ratio) will be sent to depositors.

By default, the new ProposalCancelRatio parameter is set to 0.5 during migration and ProposalCancelDest is set to empty string (i.e. burnt).


Extract evidence to a standalone module

The x/evidence module is extracted to have a separate go.mod file which allows it be a standalone module. All the evidence imports are now renamed to use instead of across the SDK.


Extract nft to a standalone module

The x/nft module is extracted to have a separate go.mod file which allows it to be a standalone module. All the evidence imports are now renamed to use instead of across the SDK.


Extract feegrant to a standalone module

The x/feegrant module is extracted to have a separate go.mod file which allows it to be a standalone module. All the feegrant imports are now renamed to use instead of across the SDK.


Extract upgrade to a standalone module

The x/upgrade module is extracted to have a separate go.mod file which allows it to be a standalone module. All the upgrade imports are now renamed to use instead of across the SDK.



Rosetta has moved to it's own repo and not imported by the Cosmos SDK SimApp by default. Any user who is interested on using the tool can connect it standalone to any node without the need to add it as part of the node binary.

The rosetta tool also allows multi chain connections.