Skip to main content
Version: Next

Modules depinject-ready

Pre-requisite Readings

depinject is used to wire any module in app.go. All core modules are already configured to support dependency injection.

To work with depinject a module must define its configuration and requirements so that depinject can provide the right dependencies.

In brief, as a module developer, the following steps are required:

  1. Define the module configuration using Protobuf
  2. Define the module dependencies in x/{moduleName}/module.go

A chain developer can then use the module by following these two steps:

  1. Configure the module in app_config.go or app.yaml
  2. Inject the module in app.go

Module Configuration

The module available configuration is defined in a Protobuf file, located at {moduleName}/module/v1/module.proto.

proto/cosmos/group/module/v1/module.proto
loading...
  • go_import must point to the Go package of the custom module.

  • Message fields define the module configuration. That configuration can be set in the app_config.go / app.yaml file for a chain developer to configure the module.
    Taking group as example, a chain developer is able to decide, thanks to uint64 max_metadata_len, what the maximum metadata length allowed for a group proposal is.

    simapp/app_config.go
    loading...

That message is generated using pulsar (by running make proto-gen). In the case of the group module, this file is generated here: https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/api/cosmos/group/module/v1/module.pulsar.go.

The part that is relevant for the module configuration is:

api/cosmos/group/module/v1/module.pulsar.go
loading...
note

Pulsar is optional. The official protoc-gen-go can be used as well.

Dependency Definition

Once the configuration proto is defined, the module's module.go must define what dependencies are required by the module. The boilerplate is similar for all modules.

danger

All methods, structs and their fields must be public for depinject.

  1. Import the module configuration generated package:

    x/group/module/module.go
    loading...

    Define an init() function for defining the providers of the module configuration:
    This registers the module configuration message and the wiring of the module.

    x/group/module/module.go
    loading...
  2. Ensure that the module implements the appmodule.AppModule interface:

    x/group/module/module.go
    loading...
  3. Define a struct that inherits depinject.In and define the module inputs (i.e. module dependencies):

    • depinject provides the right dependencies to the module.

    • depinject also checks that all dependencies are provided.

      tip

      For making a dependency optional, add the optional:"true" struct tag.

      x/group/module/module.go
      loading...
  4. Define the module outputs with a public struct that inherits depinject.Out: The module outputs are the dependencies that the module provides to other modules. It is usually the module itself and its keeper.

    x/group/module/module.go
    loading...
  5. Create a function named ProvideModule (as called in 1.) and use the inputs for instantiating the module outputs.

    x/group/module/module.go
    loading...

    The ProvideModule function should return an instance of cosmossdk.io/core/appmodule.AppModule which implements one or more app module extension interfaces for initializing the module.

    Following is the complete app wiring configuration for group:

    x/group/module/module.go
    loading...
  6. All modules must implement depinject.OnePerModuleType interface. This is used in order to tell the dependency injection framework that the module can only be instantiated once.

    x/group/module/module.go
    loading...

The module is now ready to be used with depinject by a chain developer.

Integrate in an application

The App Wiring is done in app_config.go / app.yaml and app_di.go and is explained in detail in the overview of app_di.go.