ICON’s IBC integration required protocol behavior to work across different execution environments. On the CosmWasm side, the IBC host ran as contracts, with explicit interfaces for storage, light-client operations, and application messages. That made the contract boundaries central to the implementation. The project documentation describes this arrangement and its implications for the relayer.

My responsibility was the Rust/CosmWasm side of that design: deciding how the contracts would divide protocol and application responsibilities, then carrying those boundaries into the implementation. The work began with the repository and contract foundations and continued through client lifecycle handling, xCall, and the tools needed to test them together.

Establish the contract boundaries

The early work introduced the repository structure and CosmWasm contract foundations, followed by the IBC core contract structure.

The core and xCall serve different responsibilities. The core maintains protocol state and coordinates operations with client implementations. xCall carries application requests and responses over that infrastructure. Separating them gives each interface a defined responsibility, while making the messages exchanged between contracts part of the architecture.

Build a persistent client lifecycle

I implemented client storage, a reader context, and the corresponding storage operations. These cover client identifiers, implementation registration, counters, and access to protocol state.

That foundation supports a lifecycle rather than an isolated verification call. The subsequent handlers implement creation, updates, upgrades, and misbehaviour processing.

The handlers dispatch operations to the appropriate light-client contract and process the reply. Successful replies supply information for state updates; errors must propagate through the core’s contract interface. The implementation therefore has to connect the operation being requested, the client responsible for it, and the state recorded after its result.

Carry application calls through completion and failure

My xCall work began with storage for messages, requests, and responses, then added outbound call handling.

The request carries more than its payload. It needs identifiers that connect later responses to the original operation, along with rollback information when the application supplies it. The call-service implementation, callbacks, and error handling develop that flow through reply processing, acknowledgements, and rollback execution.

This makes failure behavior part of the messaging interface. An application needs to distinguish a submitted request from a completed operation and retain the information required to handle a failed call.

Connect execution, administration, and fees

The entry-point and fee work brought dispatch, initialization, ownership checks, reply routing, and fee handling together across the core and xCall contracts. Related changes added host paths and identifiers.

I also addressed concrete administrative failure cases. A query against an empty administrator list was changed to return an error instead of panicking, and address validation was tightened. These details determine how the contract behaves when its callers provide unexpected input or query incomplete state.

What shipped

The merged work spans contract foundations, client storage and lifecycle handlers, xCall requests and callbacks, execution and fee interfaces, and administrative fixes. I added a mock IBC core, unit tests across the core and xCall, and contract documentation.

The later DIVE setup guide connected the implementation to a local development workflow. Together, these contributions cover the contract behavior and the supporting work needed to exercise and understand it.

Explore ICON IBC Integration · Back to projects