# Create Custom CosmJS Interfaces
In this section, you will:
- Create custom CosmJS interfaces to connect to custom Cosmos SDK modules.
- Define custom interfaces with Protobuf.
- Define custom types and messages.
- Integrate with Ignite - previously known as Starport.
CosmJS comes out of the box with interfaces that connect with the standard Cosmos SDK modules such as bank
and gov
and understand the way their messages are serialized. Since your own blockchain's modules are unique, they need custom CosmJS interfaces. That process consists of several steps:
- Creating the Protobuf objects and clients in TypeScript.
- Creating extensions that facilitate the use of the above clients.
- Any further level of abstraction that you deem useful for integration.
This section assumes that you have a working Cosmos blockchain with its own modules. It is based on CosmJS version v0.28.3
(opens new window).
# Compiling the Protobuf objects and clients
You can choose which library you use to compile your Protobuf objects into TypeScript or JavaScript. Reproducing what Stargate (opens new window) or cosmjs-types
(opens new window) do is a good choice.
# Preparation
This exercise assumes that:
- Your Protobuf definition files are in
./proto/myChain
. - You want to compile them into TypeScript in
./client/src/types/generated
.
Install protoc
on your computer and its Typescript plugin in your project, possibly with the help of a Dockerfile:
You can confirm the version you received. The executable is located in ./node_modules/protoc/protoc/bin/protoc
:
This returns something like:
The compiler tools are ready. Time to use them.
Create the target folder if it does not exist yet:
# Getting third party files
You need to get the imports that appear in your .proto
files. Usually you can find the following in query.proto
(opens new window):
You need local copies of the right file versions in the right locations. Pay particular attention to Cosmos SDK's version of your project. You can check by running:
This returns something like:
Use this version as a tag on Github. One way to retrieve the pagination file (opens new window) is:
You can do the same for the others, found in the third_party
folder (opens new window) under the same version:
# Compilation
You can now compile the Protobuf files. To avoid adding all the .proto
files manually to the command, use xargs
:
--proto_path
is only ./proto
so that your imports (such as import "cosmos/base...
) can be found.
You should now see your files compiled into TypeScript. They have been correctly filed under their respective folders and contain both types and services definitions. It also created the compiled versions of your third party imports.
# A note about the result
Your tx.proto
file may have contained the following:
If so, you find its service declaration in the compiled tx.ts
file:
It also appears in the default implementation:
The important points to remember from this are:
rpc: RPC
is an instance of a Protobuf RPC client that is given to you by CosmJS. Although the interface appears to be declared locally (opens new window), this is the same interface found throughout CosmJS (opens new window). It is given to you on construction (opens new window). At this point you do not need an implementation for it.- You can see
encode
anddecode
in action. Notice the.finish()
that flushes the Protobuf writer buffer. - The
rpc.request
makes calls that are correctly understood by the Protobuf compiled server on the other side.
You can find the same structure in query.ts
(opens new window).
# Proper saving
Commit the extra .proto
files as well as the compiled ones to your repository so you do not need to recreate them.
Take inspiration from cosmjs-types
codegen.sh
(opens new window):
- Create a script file named
ts-proto.sh
with the previous command, or create aMakefile
target. - Add an npm run target (opens new window) with it, to keep track of how this was done and easily reproduce it in the future when you update a Protobuf file.
# Add convenience with types
CosmJS provides an interface to which all the created types conform, TsProtoGeneratedType
(opens new window), which is itself a sub-type of GeneratedType
(opens new window). In the same file, note the definition:
The typeUrl
is the identifier by which Protobuf identifies the type of the data to serialize or deserialize. It is composed of the type's package and its name. For instance (and see also here (opens new window)):
In this case, the MsgSend
's type URL is "/cosmos.bank.v1beta1.MsgSend"
(opens new window).
Each of your types is associated like this. You can declare each string as a constant value, such as:
Save those along with generated
in ./client/src/types/modules
.
# For messages
Messages, sub-types of Msg
, are assembled into transactions that are then sent to CometBFT. CosmJS types already include types for transactions (opens new window). These are assembled, signed, and sent by the SigningStargateClient
(opens new window) of CosmJS.
The Msg
kind also needs to be added to a registry. To facilitate that, you should prepare them in a nested array:
Add child types to EncodeObject
to direct Typescript:
In the previous code, you cannot reuse your msgSendTypeUrl
because it is a value not a type. You can add a type helper, which is useful in an if else
situation:
# For queries
Queries have very different types of calls. It makes sense to organize them in one place, called an extension. For example:
Note that there is a key bank:
inside it. This becomes important later on when you add it to Stargate.
- Create an extension interface for your module using function names and parameters that satisfy your needs.
- It is recommended to make sure that the key is unique and does not overlap with any other modules of your application.
- Create a factory for its implementation copying the model here (opens new window). Remember that the
QueryClientImpl
(opens new window) implementation must come from your own compiled Protobuf query service.
# Integration with Stargate
StargateClient
and SigningStargateClient
are typically the ultimate abstractions that facilitate the querying and sending of transactions. You are now ready to add your own elements to them. The easiest way is to inherit from them and expose the extra functions you require.
If your extra functions map one-for-one with those of your own extension, then you can publicly expose the extension itself to minimize duplication in StargateClient
(opens new window) and SigningStargateClient
(opens new window).
For example, if you have your interface MyExtension
with a myKey
key and you are creating MyStargateClient
:
You can extend StargateClientOptions
(opens new window) if your own client can receive further options.
You also need to inform MySigningStargateClient
about the extra encodable types it should be able to handle. The list is defined in a registry that you can pass as options (opens new window).
Take inspiration from the SigningStargateClient
source code (opens new window) itself. Collect your new types into an array:
Taking inspiration from the same place (opens new window), add the registry creator:
Now you are ready to combine this into your own MySigningStargateClient
. It still takes an optional registry, but if that is missing it adds your newly defined default one:
You can optionally add dedicated functions that use your own types, modeled on:
Think of your functions as examples of proper use, that other developers can reuse when assembling more complex transactions.
You are ready to import and use this in a server script or a GUI.
If you would like to get started on building your own CosmJS elements on your own checkers game, you can go straight to the exercise in CosmJS for Your Chain to start from scratch.
More specifically, you can jump to:
- Create Custom Objects, to see how to compile the Protobuf objects.
- Create Custom Messages, to see how to create messages relevant for checkers.
- Backend Script for Game Indexing, to see how this can be used also to listen to events coming from the blockchain.
- Integrate CosmJS and Keplr, to see how to use and integrate what you prepared into a preexisting Checkers GUI.
To summarize, this section has explored:
- How CosmJS's out-of-the-box interfaces understand how messages of standard Cosmos SDK modules are serialized, meaning that your unique modules will require custom CosmJS interfaces of their own.
- How to create the necessary Protobuf objects and clients in Typescript, the extensions that facilitate the use of these clients, and any further level of abstraction that you deem useful for integration.
- How to integrate CosmJS with Ignite's client and signing client, which are typically the ultimate abstractions that facilitate the querying and sending of transactions.