Learn how to integrate IBC to your applicationThis document outlines the required steps to integrate and configure the IBC
module to your Cosmos SDK application and enable sending fungible token transfers to other chains. An example app using ibc-go v10 is linked.
We need to register the core ibc and transferKeepers. To support the use of IBC v2, transferv2 and callbacksv2 must also be registered as follows:
app.go
Copy
Ask AI
import ( / other imports / ... ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" ibctransferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" / ibc v2 imports transferv2 "github.com/cosmos/ibc-go/v10/modules/apps/transfer/v2" ibccallbacksv2 "github.com/cosmos/ibc-go/v10/modules/apps/callbacks/v2")type App struct { / baseapp, keys and subspaces definitions / other keepers / ... IBCKeeper *ibckeeper.Keeper / IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly TransferKeeper ibctransferkeeper.Keeper / for cross-chain fungible token transfers / ... / module and simulation manager definitions}
Middleware stacks in IBC allow you to wrap an IBCModule with additional logic for packets and acknowledgements. This is a chain of handlers that execute in order. The transfer stack below shows how to wire up transfer to use packet forward middleware, and the callbacks middleware. Note that the order is important.
Copy
Ask AI
/ Create Transfer Stack for IBC Classic maxCallbackGas := uint64(10_000_000) wasmStackIBCHandler := wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper)var transferStack porttypes.IBCModuletransferStack = transfer.NewIBCModule(app.TransferKeeper)/ callbacks wraps the transfer stack as its base app, and uses PacketForwardKeeper as the ICS4Wrapper/ i.e. packet-forward-middleware is higher on the stack and sits between callbacks and the ibc channel keeper/ Since this is the lowest level middleware of the transfer stack, it should be the first entrypoint for transfer keeper's/ WriteAcknowledgement. cbStack := ibccallbacks.NewIBCMiddleware(transferStack, app.PacketForwardKeeper, wasmStackIBCHandler, maxCallbackGas)transferStack = packetforward.NewIBCMiddleware( cbStack, app.PacketForwardKeeper, 0, / retries on timeout packetforwardkeeper.DefaultForwardTransferPacketTimeoutTimestamp,)
For IBC v2, an example transfer stack is shown below. In this case the transfer stack is using the callbacks middleware.
Copy
Ask AI
/ Create IBC v2 transfer middleware stack/ the callbacks gas limit is recommended to be 10M for use with wasm contracts maxCallbackGas := uint64(10_000_000) wasmStackIBCHandler := wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper)var ibcv2TransferStack ibcapi.IBCModule ibcv2TransferStack = transferv2.NewIBCModule(app.TransferKeeper)ibcv2TransferStack = ibccallbacksv2.NewIBCMiddleware(transferv2.NewIBCModule(app.TransferKeeper), app.IBCKeeper.ChannelKeeperV2, wasmStackIBCHandler, app.IBCKeeper.ChannelKeeperV2, maxCallbackGas)
IBC needs to know which module is bound to which port so that it can route packets to the
appropriate module and call the appropriate callbacks. The port to module name mapping is handled by
IBC’s port Keeper. However, the mapping from module name to the relevant callbacks is accomplished
by the port
Router on the
ibc module.Adding the module routes allows the IBC handler to call the appropriate callback when processing a channel handshake or a packet.Currently, a Router is static so it must be initialized and set correctly on app initialization.
Once the Router has been set, no new routes can be added.
app.go
Copy
Ask AI
import ( / other imports / ... porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types")func NewApp(...args) *App { / .. continuation from above / Create static IBC router, add transfer module route, then set and seal it ibcRouter := porttypes.NewRouter()ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) / Setting Router will finalize all routes by sealing router / No more routes can be added app.IBCKeeper.SetRouter(ibcRouter) / ... continues
With IBC v2, there is a new router that needs to register the routes for a portID to a given IBCModule. It supports two kinds of routes: direct routes and prefix-based routes. The direct routes match one specific port ID to a module, while the prefix-based routes match any port ID with a specific prefix to a module.
For example, if a direct route named someModule exists, only messages addressed to exactly that port ID will be passed to the corresponding module.
However, if instead, someModule is a prefix-based route, port IDs like someModuleRandomPort1, someModuleRandomPort2, etc., will be passed to the module.
Note that the router will panic when you add a route that conflicts with an already existing route. This is also the case if you add a prefix-based route that conflicts with an existing direct route or vice versa.
Copy
Ask AI
/ IBC v2 router creation ibcRouterV2 := ibcapi.NewRouter()ibcRouterV2.AddRoute(ibctransfertypes.PortID, ibcv2TransferStack) / Setting Router will finalize all routes by sealing router / No more routes can be added app.IBCKeeper.SetRouterV2(ibcRouterV2)
Note that from v10 onwards, all light clients are expected to implement the LightClientInterface interface defined by core IBC, and have to be explicitly registered in a chain’s app.go. This is in contrast to earlier versions of ibc-go when 07-tendermint and 06-solomachine were added out of the box. Follow the steps below to integrate the 07-tendermint light client.
All light clients must be registered with module.Manager in a chain’s app.go file. The following code example shows how to instantiate 07-tendermint light client module and register its ibctm.AppModule.
The allowed clients parameter defines an allow list of client types supported by the chain. The
default value is a single-element list containing the AllowedClients wildcard ("*"). Alternatively, the parameter
may be set with a list of client types (e.g. "06-solomachine","07-tendermint","09-localhost").
A client type that is not registered on this list will fail upon creation or on genesis validation.
Note that, since the client type is an arbitrary string, chains must not register two light clients
which return the same value for the ClientType() function, otherwise the allow list check can be
bypassed.
One addition from IBC is the concept of HistoricalInfo which is stored in the Cosmos SDK x/staking module. The number of records stored by x/staking is controlled by the HistoricalEntries parameter which stores HistoricalInfo on a per-height basis.
Each entry contains the historical information for the Header and ValidatorSet of this chain which is stored
at each height during the BeginBlock call. The HistoricalInfo is required to introspect a blockchain’s prior state at a given height in order to verify the light client ConsensusState during the
connection handshake.
app.go
Copy
Ask AI
import ( / other imports / ... stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ibcexported "github.com/cosmos/ibc-go/v10/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types")func NewApp(...args) *App { / ... continuation from above / add x/staking, ibc and transfer modules to BeginBlockers app.ModuleManager.SetOrderBeginBlockers( / other modules ... stakingtypes.ModuleName, ibcexported.ModuleName, ibctransfertypes.ModuleName, )app.ModuleManager.SetOrderEndBlockers( / other modules ... stakingtypes.ModuleName, ibcexported.ModuleName, ibctransfertypes.ModuleName, ) / ... genesisModuleOrder := []string{ / other modules / ... ibcexported.ModuleName, ibctransfertypes.ModuleName,}app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) / ... continues
That’s it! You have now wired up the IBC module and the transfer module, and are now able to send fungible tokens across
different chains. If you want to have a broader view of the changes take a look into the SDK’s
SimApp.