Actor Callbacks Unlock Interchain Composable Apps

IBC Protocol
The Interchain Foundation
5 min readMay 17, 2023

--

Summary

  • ADR-8 actor callbacks introduces a standardized interface that IBC actors (modules/smart contracts) can expose in order to call into apps like ICS-20 transfer or ICS-27 interchain accounts (ICA).
  • Transfer or ICA can implement the optional CallbackPacketData interface to support actor callbacks.
  • The CallbackPacketDatainterface for both ICS-20 and ICS-27 have been developed.
  • ADR-8 supports all use cases where an action is executed programmatically after sending a transfer or ICA message.
  • Osmosis is working on an implementation of ADR-8 middleware for executing contract calls upon RecvPacket (ICS-20 specific). We are currently working with Evmos and Confio to build ADR-8-compliant middleware for EVM and CosmWasm, respectively.

Actor callbacks bring much-needed composability to the Interchain

Composability is defined as the capacity for on-chain modules or smart contracts to interact seamlessly by being able to read/write state to each other. For the Interchain to flourish, it is important that applications can compose with one another to enable novel and compelling use cases.

ADR-8 serves this purpose by allowing on-chain modules/smart contracts to interweave with one another, supporting applications that string together different actions into a single user flow. As part of our efforts to augment interchain composability, we’ve finalized the ADR-8 interfaces and packet data implementations.

This blog post is aimed at application and chain developers who want to learn more about ADR-8 actor callbacks, and why it was necessitated. Additionally, we’ll explore some of the use cases that are unlocked with this development.

The problem

In its initial design, IBC was limited to callbacks between core IBC (also referred to as the transport layer) and application modules. Core IBC executed a callback to the application every time a packet was sent or received.

As shown in Figure 1, when a packet is sent, core IBC executes the callback to the sending module onAcknowledgePacketor onTimeoutPacket. Conversely, upon receiving a packet, the callback onRecvPacket is called.

Figure 1: Callback architecture between core IBC and application modules

While this system of callbacks between core IBC and app modules was adequate for initial IBC applications, we now see the desire to build programs with more complex user flows that require callbacks between modules themselves, and not just with core IBC. Here’s an example use case:

  1. Send token X from chain A to B.
  2. If step 1 was successful, automatically send an ICA tx to stake those tokens.

To achieve both of these steps within a single user flow, the transfer module should be able to pass the ack/timeout message to the ICA controller submodule. Without access to the ack/timeout, the controller submodule has no way of knowing whether the transfer in step 1 was successful or not.

Solution: ADR-8 Callbacks to IBC actors

ADR-8 IBC actor callbacks introduces a standardized callback interface for IBC actors to implement, which will allow them to call into IBC apps. An IBC actor is either an on-chain module or a smart contract.

This allows applications such as transfer and ICA to pass on information regarding the success/failure of a packet lifecycle to an actor, which can then take some action based on this information.

Figure 2: Callback architecture between IBC actor, application modules, and core IBC

Prior to ADR-8, a user had to manually verify the outcome of action 1 to determine whether to proceed with action 2, as the latter was dependent on the former’s result (see Figure 3).

By enabling modules/smart contracts to compose with one another over IBC, ADR-8 automates this flow by allowing application modules to pass on the result of a packet lifecycle, and execute actions programmatically based on the result.

Figure 3: User flows before and after implementing ADR-8 actor callbacks

To do so, IBC actors can implement the IBCActor and PacketActor interfaces as shown below:

IBC apps that implement the base packet data type, such as transfer or ICA, must implement the CallbackPacketData interface to allow PacketActor callbacks. See here for the ICS-20 implementation for CallbackPacketData, and you can find the ICS-27 implementation here.

As shown above, CallbackPacketData contains two methods — GetSourceCallbackAddress and GetDestCallbackAddress, which returns the source address ( onAcknowledgePacket or onTimeoutPacket) and destination address ( onRecvPacket) of the IBC actor, respectively. Once CallbackPacketData has been implemented, middleware can target this interface to retrieve the desired callback addresses on the source and destination chains.

Note that CallbackPacketData specifies a UserDefinedGasLimit method. Middleware targeting the CallbackPacketData interface must cap the amount of gas consumed upon callbacks. This ensures that a custom callback does not prevent the packet lifecycle from completing.

Chains are also expected to define a chainDefinedActorcallbackLimit in order to prevent callbacks from consuming an arbitrary amount of gas, ensuring that a relayer can always complete the packet lifecycle even if the actor callbacks don’t execute successfully.

The implementation of ADR-8 and CallbackPacketData for ICS-20 and ICS-27 was aimed at solving the problem of limited application composability, particularly for developers creating apps using CosmWasm or EVM.

For CosmWasm developers, Osmosis is working on their IBC hooks middleware that will leverage ADR-8, enabling it to parse the memo field in an ICS-20 packet and execute CosmWasm contract calls. Additionally, we are also collaborating with Confio to create an ADR-8-compliant middleware for CosmWasm. And furthermore, we are partnering with Evmos to develop middleware that can be utilized with the EVM. This work will enable smart contracts to execute logic conditionally based on the packet acknowledgment result data, allowing them to compose with other IBC-enabled chains.

Use cases

ADR-8 satisfies all use cases of the form: ‘send X, do Y programmatically’. Below are some examples of this. Note that all of these are executed in a single user flow.

  • Transfer tokens from chain A to B. Upon successful ack, send an ICA tx to swap the tokens on destination and send them back to chain A.
  • Transfer tokens from chain A to B. Upon successful ack, deposit tokens into a liquidity pool, or any other credit instrument (such as a Mars outpost for instance).
  • Execute arbitrary smart contract logic upon receiving an ICS-20 packet.

Conclusion

The implementation of ADR-8 actor callbacks is an important development for the Interchain. It takes composability to the next level which translates into improved UX for users of IBC.

We expect this development to open up exciting new use cases and enable novel applications to be built within the Interchain, unlocking endless possibilities for both developers and users alike.

About the Author

Adi Ravi Raj works at Interchain GmbH and is the Protocol Analyst for the IBC team.

Shoutout to Susannah Evans, Carlos Rodriguez, and Fede Kuellmer for the feedback and review.

--

--

IBC Protocol
The Interchain Foundation

IBC is a blockchain interoperability protocol used by 100+ chains. It enables secure, permissionless, feature-rich cross-chain interactions.