Skip to main content

Synopsis

Learn how to implement IBC v2 applications To build an IBC v2 application the following steps are required:
  1. Implement the IBCModule interface
  2. Bind Ports
  3. Implement the IBCModule Keeper
  4. Implement application payload and success acknowledgement
  5. Set and Seal the IBC Router
Highlighted improvements for app developers with IBC v2:
  • No need to support channel handshake callbacks
  • Flexibility on upgrading application versioning, no need to use channel upgradability to renegotiate an application version, simply support the application version on both sides of the connection.
  • Flexibility to choose your desired encoding type.

Implement the IBCModule interface

The Cosmos SDK expects all IBC modules to implement the IBCModule interface. This interface contains all of the callbacks IBC expects modules to implement. Note that for IBC v2, an application developer no longer needs to implement callbacks for the channel handshake. Note that this interface is distinct from the porttypes.IBCModule interface used for IBC Classic.
Additionally, in the module.go file, add the following line:

Packet callbacks

IBC expects modules to implement callbacks for handling the packet lifecycle, as defined in the IBCModule interface. With IBC v2, modules are not directly connected. Instead a pair of clients are connected and register the counterparty clientID. Packets are routed to the relevant application module by the portID registered in the Router. Relayers send packets between the routers/packet handlers on each chain. IBC packet flow diagram Briefly, a successful packet flow works as follows:
  1. A user sends a message to the IBC packet handler
  2. The IBC packet handler validates the message, creates the packet and stores the commitment and returns the packet sequence number. The Payload, which contains application specific data, is routed to the relevant application.
  3. If the counterparty writes an acknowledgement of the packet then the sending chain will process the acknowledgement.
  4. If the packet is not successfully received before the timeout, then the sending chain processes the packet’s timeout.

Sending packets

MsgSendPacket is sent by a user to the channel v2 message server, which calls ChannelKeeperV2.SendPacket. This validates the message, creates the packet, stores the commitment and returns the packet sequence number. The application must specify its own payload which is used by the application and sent with MsgSendPacket. An application developer needs to implement the custom logic the application executes when a packet is sent.

Receiving packets

To handle receiving packets, the module must implement the OnRecvPacket callback. An application module should validate and confirm support for the given version and encoding method used as there is greater flexibility in IBC v2 to support a range of versions and encoding methods. The OnRecvPacket callback is invoked by the IBC module after the packet has been proven to be valid and correctly processed by the IBC keepers. Thus, the OnRecvPacket callback only needs to worry about making the appropriate state changes given the packet data without worrying about whether the packet is valid or not. Modules may return to the IBC handler an acknowledgement which implements the Acknowledgement interface. The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the acknowledgement back to the sender module. The state changes that occurr during this callback could be:
  • the packet processing was successful as indicated by the PacketStatus_Success and an Acknowledgement() will be written
  • if the packet processing was unsuccessful as indicated by the PacketStatus_Failure and an ackErr will be written
Note that with IBC v2 the error acknowledgements are standardised and cannot be customised.

Acknowledging packets

After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can then process the acknowledgement using the OnAcknowledgementPacket callback. The contents of the acknowledgement is entirely up to the application developer. IBC will pass in the acknowledgements as []byte to this callback. The callback is responsible for decoding the acknowledgement and processing it. The acknowledgement is serialised and deserialised using JSON.

Timeout packets

If the timeout for a packet is reached before the packet is successfully received or the receiving chain can no longer process the packet the sending chain must process the timeout using OnTimeoutPacket. Again the IBC module will verify that the timeout is valid, so our module only needs to implement the state machine logic for what to do once a timeout is reached and the packet can no longer be received.

PacketDataUnmarshaler

The PacketDataUnmarshaler interface is required for IBC v2 applications to implement because the encoding type is specified by the Payload and multiple encoding types are supported.

Bind Ports

Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented:
Note that portID does not refer to a certain numerical ID, like localhost:8080 with a portID 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module’s name and for Cosmwasm contracts it defaults to the contract address.
Add port ID to the GenesisState proto definition:
You can see an example for transfer here. Add port ID as a key to the module store:
Note that with IBC v2, the version does not need to be added as a key (as required with IBC classic) because versioning of applications is now contained within the packet Payload. Add port ID to x/<moduleName>/types/genesis.go:
Set the port in the module keeper’s for InitGenesis:
The module is set to the desired port. The setting and sealing happens during creation of the IBC router.

Implement the IBCModule Keeper

More information on implementing the IBCModule Keepers can be found in the keepers section

Packets and Payloads

Applications developers need to define the Payload contained within an IBC packet. Note that in IBC v2 the timeoutHeight has been removed and only timeoutTimestamp is used. A packet can contain multiple payloads in a list. Each Payload includes:
Note that compared to IBC classic, where the applications version and encoding is negotiated during the channel handshake, IBC v2 provides enhanced flexibility. The application version and encoding used by the Payload is defined in the Payload. An example Payload is illustrated below:
It is also possible to define your own custom success acknowledgement which will be returned to the sender if the packet is successfully recieved and is returned in the RecvPacketResult. Note that if the packet processing fails, it is not possible to define a custom error acknowledgment, a constant ackErr is returned.

Routing

More information on implementing the IBC Router can be found in the routing section.