The Wasm Client: Seamless Addition of New Light Clients to Your Chain
The expansion of IBC into new blockchain ecosystems necessitates adding support for new light clients. Historically, adding new light clients has been cumbersome. But with the recent release of the Wasm client module, the process will now become streamlined, enabling seamless addition of new light clients.
This blog post introduces the Wasm client module and provides an overview of how it works. We’ll explore why this feature is essential for developer experience within Cosmos and how the Wasm client is being utilized to scale the interchain. This feature provides flexibility for light client development, facilitating IBC expansion into new ecosystems.
Historical Challenges with Upgrading Consensus and Instantiating New Light Clients
The Wasm client was developed in response to an ongoing challenge: chain developers had a difficult time instantiating a new light client that tracks the consensus of a non-CometBFT chain.
The addition of a new light client comes with substantial overhead for Cosmos SDK developers. They must familiarize themselves with the consensus mechanism of the new chain, write a Go implementation which satisfies the ICS-02 interfaces improved in the 02-client refactor, undergo a governance process, and coordinate a new release.
These pain points exist because of the tight coupling of light client logic within the Cosmos SDK codebase. Therefore, the solution here is simple: decouple light clients from the SDK. And this is precisely what the Wasm client does.
Wasm Client: Seamlessly Add Light Clients
The 08-wasm client module comprises a Wasm VM capable of hosting light client bytecode, offering the flexibility to write new light clients in any language that compiles to Wasm (Rust, C/C++, JS, Go, etc.). With a consistent interface aligned with ICS-02, this module serves as a proxy light client, facilitating interaction with the actual light client contracts deployed as Wasm bytecode.
Enabling the Wasm client module on your chain requires a chain upgrade, but adding new clients does not. Instead, the latter is subject to a governance proposal by default. In practice, chains could authorize a DAO or a multi-sig to approve new client additions.
Wasm Client Implementation
To enable the Wasm client module, chains need to manually add it to their list of allowed clients by updating the AllowedClients
parameter within 02-client.
1
2
3
params := clientKeeper.GetParams(ctx)
params.AllowedClients = append(params.AllowedClients, wasmtypes.Wasm)
clientKeeper.SetParams(ctx, params)
Adding a new light client contract is governance-gated by default. Chains need to submit a governance proposal that contains the sdk.Msg
for storing the Wasm contract’s bytecode. The required message is MsgStoreCode
and the bytecode is provided within the wasm_byte_code
field:
1
2
3
4
5
// MsgStoreCode defines the request type for the StoreCode RPC
message MsgStoreCode {
string signer = 1;
bytes wasm_byte_code = 2;
}
An existing Wasm light client can be upgraded to a new version through the MigrateContract
method. However, this approach is recommended only for emergency scenarios, such as when a contract requires an upgrade due to a critical bug.
Note that the Wasm client module has its own go.mod file and has therefore been released independently of ibc-go. This decoupling allows ibc-go to remain lean without having dependencies on wasmvm or wasmd. Additionally, it provides flexibility to have distinct release cycles for the Wasm client module and ibc-go.
The module was audited by Confio, Ethan Frey, and by Halborn. The GRANDPA contracts have been audited by Oak Security.
To learn more about the details of how the Wasm client works, please refer to ADR-027.
Why is the Wasm client important to me as a light client/chain developer?
The Wasm client improves DevX in the following ways:
- Adding a new light client doesn’t require a coordinated upgrade by validators.
- New light clients can be written in any language that compiles down to Wasm (Rust, C/C++, JS, Go, etc). This allows you to utilize existing dependencies without having to rewrite them in Go and thus avoids hard-to-debug edge cases in a reimplementation.
- Reduces overhead on Cosmos SDK developers as they no longer need to concern themselves with the intricacies of different consensus algorithms.
- Improves maintainability of Cosmos SDK for an app chain, since no change to the codebase is required to add new light clients.
Use Cases
Composable Finance recently launched trustless.zone which connects Cosmos SDK and Substrate-based chains using IBC. They leverage the Wasm client to host light client bytecode for the ICS-10 GRANDPA client. GRANDPA is the finality gadget of the consensus protocol used by Polkadot’s relay chain.
Additionally, Composable Finance also plans to use the Wasm client for NEAR<>Cosmos IBC connections. Here the Wasm client will be used to deploy the Doomslug light client contract. Union is also using the Wasm client to underpin a connection to Ethereum, and the ibc-rs and Rollkit teams are leveraging it for the Rollkit IBC integration.
How to Use the GRANDPA ICS-10 (Wasm) Client
1. Getting the contract binary
a) Precompiled
The version of the GRANDPA contract binary that has been used in the 08-wasm e2e tests can be found here. We are working with Composable Finance to consolidate all the code changes done in the contract and the hyperspace relayer during the upstreaming of the module, and gather what versions of the different components are compatible.
b) From source
To build the latest (potentially unstable) version of the contract, run the following command in the root of Composable Finance’s composable-ibc repository:
1
cargo build -p ics10-grandpa-cw --target=wasm32-unknown-unknown --release --lib
The binary will be placed here: target/wasm32-unknown-unknown/release/ics10_grandpa_cw.wasm
. Afterwards, this binary needs to be optimized by running:
1
wasm-opt -Os target/wasm32-unknown-unknown/release/ics10_grandpa_cw.wasm -o ics10_grandpa_cw.wasm
And the output is the binary that can be uploaded.
2. Deploying the contract
To upload the contract onto the chain using the CLI, for example in the case of Centauri, centaurid
can be used:
1
centaurid tx ibc-wasm store-code ics10_grandpa_cw.wasm
This command should be run by the chain's authority. After that, you can query the chain to get the checksum of the contract:
1
centaurid query ibc-wasm checksums
3. Instantiating the contract
To instantiate the contract, in the Hyperspace relayer’s chain configuration file for the chain with the contract, add the following field:
1
wasm_checksum = "<bytecode-checksum>" # example "cfd2199578332b5fd859f3b76cb0b29757c6b52c5df79566cdc3598039dbe43e"
Governance Proposals
In the context of the chain operating with permissioned CosmWasm, uploading the contract will require you to go through a governance proposal. To add a wasm client, use the MsgStoreCode
and submit a governance proposal with the following message:
1
2
3
4
5
6
7
8
9
10
11
12
{
"messages": [
{
"@type": "/ibc.lightclients.wasm.v1.MsgStoreCode",
"wasm_byte_code": "[your-contract-code]",
"signer": "cosmos1...",
}
],
"metadata": "meta",
"deposit": "10stake"
"title" : "My proposal","summary": "A short summary of my proposal"
}
The "[your-contract-code]" is the base64-encoded bytestring from the grandpa contract file. You can submit the governance proposal by running the following command:
1
centaurid tx ibc-wasm store-code contracts/ics10_grandpa_cw.wasm --from [yourkey] --gas 1000000000 --generate-only | jq '.body.messages[0].code'
Finally, you can create clients by running the Hyperspace relayer.
Conclusion
The introduction of the Wasm client brings significant improvements to DevX within the interchain and accelerates the expansion of IBC beyond Cosmos SDK chains. By decoupling light clients from the Cosmos SDK codebase, the Wasm client enables seamless addition of new light clients without requiring code releases or coordinated upgrades.
The Wasm client is a critical piece of infrastructure that enhances the extensibility of IBC and will play a pivotal role in realizing IBC's vision of serving as the TCP/IP for blockchains.
Thank you to our contributors
We’d like to give a shout out to the teams who made this feature possible.
- Chorus One: For laying the groundwork to connect Cosmos chains with Substrate-based chains by designing the first version of the Wasm client module.
- Composable Finance: Took over the initial Wasm client spec written by Chorus One and updated it to incorporate the new design. Developed the GRANDPA light client for Polkadot, deployed as a Rust contract using the Wasm client module.
- Strangelove: Implemented the Wasm client module based on the new design and developed a Rust contract for the Comet light client.
- Ethan Frey and Confio: Audited the Wasm client module and provided recommendations and issues for the Interchain GmbH team to resolve.
- Interchain GmbH: Upstreamed the feature into ibc-go, merged multiple PRs for code cleanup, performed an internal audit of the codebase, opened several issues based on findings from the internal audit, and worked on PRs addressing these issues.
Thank you to Susannah Evans, Carlos Rodriguez, Mary McGilvray, and the Composable Finance team for reviewing multiple drafts of this post.
About IBC
The Inter-Blockchain Communication Protocol (IBC) is the most widely adopted trust-minimized, permissionless, and general messaging-passing protocol. IBC connects 100+ for cross-chain activities such as token transfers, inter-chain account control, shared security, data queries, and much more. Build using IBC or join us on Discord.