Typescript SDK

CCL IBC SDK for typescript developers

Typescript Demo

See a fullstack Next.js typescript demo here (using Osmosis Mainnet). Code available here.

Dependencies

For encryption, we recommend using @solar-republic/neutrino which has useful chacha20poly1305related functionalities and additional primitives for generating ephemereal lightweight wallets. Installation:

npm install --save @solar-republic/neutrino

For signing, encoding and other cryptographic needs in the Cosmos ecosystem, it is common to use the suite of @cosmjs packages. You can install the following:

npm install --save @cosmjs/crypto @cosmjs/amino @cosmjs/encoding

If you are developing in the browser environment or connecting to a public network you might also need

npm install --save @cosmjs/stargate
# or
npm install --save @cosmjs/cosmwasm-stargate

Note: You can also use any Typescript / Javascript package managers and runtimes e,g, bun, yarn, pnpm etc.

Generating Wallets

For chacha20poly1305, we need to use a crypthographic keypair and it's advised to use one that isn't the same as the user's wallet. The SDK provides a method for generating a new wallet that can be used for encryption purposes. For our purposes, we just need a private / public keys of Secp256k1 type and there are various ways to generate them.

@cosmjs/crypto

import { Slip10Curve, Random, Bip39, Slip10, stringToPath, Secp256k1 } from "@cosmjs/crypto"

const seed = await Bip39.mnemonicToSeed(Bip39.encode(Random.getBytes(16)));
const { privateKey } = Slip10.derivePath(Slip10Curve.Secp256k1, seed, stringToPath("m/44'/1'/0'/0"));
const pair = await Secp256k1.makeKeypair(privateKey);
// must be compressed to 33 bytes from 65
const publicKey = Secp256k1.compressPubkey(pair.pubkey);

@solar-republic/neutrino

@secretjs

Query Client

Before proceeding to encryption, you might want to create a quering client that will be used for querying the state and contract of the Secret Network. At the very least, it is requited for fetching the public key of a gateway contract for deriving a shared key used later for encryption.

To perform a simple query on a secret contract we can use methods from @solar-republic/neutrino:

For more persistent use-cases you can use secretjs:

Signatures

To make sure that malicious applications aren't tricking the user into signing an actual blockchain transaction, it is discouraged to sign arbitrary blobs of data. To address the situation, there are various standards that inject additional data to the message before signing it. The most used in the Cosmos ecosystem is defined in ADR 036 which is also used in the SDK.

Browser Wallets

Most of the Cosmos wallets provide a method for signing arbitrary messages following the mentioned specification.

Here is a definition taken from documentation of Keplr wallet:

Although the API method requires a chainId, it is set to empty string before signing the message

Cosmology

Cosmology defines signArbitrary method as part of the interface for their wallet client and provides implementation / integration for every popular Cosmos wallet out there

CosmJS

The logic of the method has already been implemented and proposed as an addition to the library however it has been hanging in a unmerged PR for a while. You can find the full implementation with examples and tests [PR] Here

Manually

Getting Signer and Signer Address

Firstly we need to get an amino signer that will be used for generating the signature. @cosmjs has a defined interface OfflineAminoSigner with signAmino and getAccounts methods and any other signer that implements it can be used for the purpose.

Generating the message and StdSignDoc

To use signAmino, we need to generate a StdSignDoc object that will be used for signing the message to pass as an argument.

CosmJS provides a function for this:

The 036 standard requires the message fields to AminoMsg to be:

As for the rest of the fields, they can be set to an empty string or 0. The final example will look like this:

After getting the document we can sign it with the signer:

Encryption

After getting a public key of a gateway contract you can use it to derive a shared key like this:

Encrypting + Signing

Produced digest of hashing the ciphertext can be used as our message that we want to sign according to the 036 standard. The final message will look like this:

After this we are getting all the required fields for creating an EncryptedPayload message or an ExecuteMsg::Encrypted { ... }

Broadcasting the message

The encrypted message is safe to broadcast over public blockchain and other infrastructure. A common use-case in context of Cosmos account might be broadcasting it over IBC originating from a chain other than the Secret Network.

The potential use-case might involve broadcasting the message by initiating an IBC message directly and attaching the message as a payload (IBC-Hook) or passing the message to a smart contract on a remote chain to process and bridge it to the Secret Network.

Since Cosmwasm is quite flexible with defining messages due to supporting JSON serialization, it is possible the process is very similar in both cases so we only going to cover IBC-hooks for simplicity:

Last updated

Was this helpful?