Skip to content

Instantly share code, notes, and snippets.

@webmaster128
Last active March 17, 2024 21:58
Show Gist options
  • Star 43 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save webmaster128/8444d42a7eceeda2544c8a59fbd7e1d9 to your computer and use it in GitHub Desktop.
Save webmaster128/8444d42a7eceeda2544c8a59fbd7e1d9 to your computer and use it in GitHub Desktop.
CosmJS + Stargate – A guided tour

Support for Cosmos SDK Stargate in CosmJS has been ongoing work for several months now. Stargate is released and CosmJS is here to connect to it.

Starting points

Let's explore what is new for Stargate support:

Install CosmJS ^0.24.0

npm install @cosmjs/proto-signing @cosmjs/stargate
# or
yarn add @cosmjs/proto-signing @cosmjs/stargate

Send your first Stargate transaction from JavaScript:

import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { assertIsBroadcastTxSuccess, SigningStargateClient, StargateClient } from "@cosmjs/stargate";

const mnemonic = "surround miss nominee dream gap cross assault thank captain prosper drop duty group candy wealth weather scale put";
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic);
const [firstAccount] = await wallet.getAccounts();

const rpcEndpoint = "https://rpc.my_tendermint_rpc_node";
const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, wallet);

const recipient = "cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5";
const amount = {
  denom: "ucosm",
  amount: "1234567",
};
const result = await client.sendTokens(firstAccount.address, recipient, [amount], "Have fun with your star coins");
assertIsBroadcastTxSuccess(result);

Easy, right? Maybe too easy to be actually useful for anyone except exchanges. Here is how you send your custom message types:

import { DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing";
import {
  assertIsBroadcastTxSuccess,
  SigningStargateClient,
  StargateClient,
} from "@cosmjs/stargate";

// A message type auto-generated from .proto files using ts-proto. @cosmjs/stargate ships some
// common types but don't rely on those being available. You need to set up your own code generator
// for the types you care about. How this is done should be documented, but is not yet:
// https://github.com/cosmos/cosmjs/issues/640
import { MsgDelegate } from "@cosmjs/stargate/build/codec/cosmos/staking/v1beta1/tx"; 

const mnemonic =
  "surround miss nominee dream gap cross assault thank captain prosper drop duty group candy wealth weather scale put";
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic);
const [firstAccount] = await wallet.getAccounts();

const rpcEndpoint = "https://rpc.my_tendermint_rpc_node";
const client = await SigningStargateClient.connectWithSigner(
  rpcEndpoint,
  wallet,
  { registry: registry }
);

const msg = MsgDelegate.create({
  delegatorAddress: alice.address0,
  validatorAddress: validator.validatorAddress,
  amount: {
    denom: "uatom",
    amount: "1234567",
  },
});
const msgAny = {
  typeUrl: msgDelegateTypeUrl,
  value: msg,
};
const fee = {
  amount: [
    {
      denom: "uatom",
      amount: "2000",
    },
  ],
  gas: "180000", // 180k
};
const memo = "Use your power wisely";
const result = await client.signAndBroadcast(
  firstAccount.address,
  [msgAny],
  fee,
  memo
);
assertIsBroadcastTxSuccess(result);

If you're not on the Cosmos Hub, you probably want to configure your address prefix and your HD derivation path:

import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { stringToPath } from "@cosmjs/crypto";

const mnemonic =
  "surround miss nominee dream gap cross assault thank captain prosper drop duty group candy wealth weather scale put";
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(
  mnemonic,
  stringToPath("m/0'/1/2'/2/1000000000"),
  "blub"
);
const [firstAccount] = await wallet.getAccounts();
// firstAccount.address now starts with blub1

Things we built with CosmJS

The above examples focus on signing, but there are plenty of things you can build with CosmJS and only some of them require signing.

  • Wallets (hot and cold; with and without a UI)
  • Explorers
  • Scrapers
  • Key/Address generators
  • dApps
  • IBC relayers

Used CosmJS before

If you have experience working with CosmJS from Cosmos SDK 0.37–0.39 (Launchpad) times, please note the following significant changes in the Stargate client library:

  • The Stargate client always connects to a Tendermint RPC endpoint (HTTP or WebSockets). The LCD API is not used anymore.
  • We can now encode/decode binary transactions locally, as the client has a full protobuf implementation. This was not possible before due to the lack of an Amino encoder/decoder.
  • Ledger signing support should work via SIGN_MODE_LEGACY_AMINO_JSON. Please see #594

Get in touch

The CosmJS development team is happy to get in touch with you for all questions and suggestions.

Further reading

@anupam-io
Copy link

can you do an example on Osmosis using OsmoJS?

@dgabriele
Copy link

The second example is missing the code where the registry var is instantiated.

@alexrobaina
Copy link

alexrobaina commented Aug 27, 2022

Hi Everyone! I want to share this example.
I use cosmjs to get the balance address and work for cosmos and osmosis.

import { Coin, createProtobufRpcClient, QueryClient } from "@cosmjs/stargate";
import { QueryClientImpl } from "cosmjs-types/cosmos/bank/v1beta1/query";
import { Tendermint34Client } from "@cosmjs/tendermint-rpc";

const getBalance = async (denom: string, address: string, rcp: string): Promise<Coin | undefined> => {
    try {
      const tendermint = await Tendermint34Client.connect(rcp);
      const queryClient = new QueryClient(tendermint);
      const rpcClient = createProtobufRpcClient(queryClient);
      const bankQueryService = new QueryClientImpl(rpcClient);

      const { balance } = await bankQueryService.Balance({
        address,
        denom,
      });

      return balance;
    } catch (error) {
      console.log(error);
    }
  };

If you want to get balance from Cosmos I use these parameters

const balance = getBalance(
    "uatom",
    "cosmos1peydkky2dcj0n8mc9nl4rx0qwwmwph94mkp6we",
    "https://cosmos-mainnet-rpc.allthatnode.com:26657/"
 );
  

If you want to get balance from osmosis I use these parameters

const balance = getBalance(
    "uosmo",
    "osmo1peydkky2dcj0n8mc9nl4rx0qwwmwph94ndj2ct",
    "https://osmosis-mainnet-rpc.allthatnode.com:26657/"
  );

@davidp94
Copy link

How to get the gas price @webmaster128 ?

@tuloski
Copy link

tuloski commented Mar 23, 2023

How to use it with other chains? For example with terra?
I find very hard to understand how to use this complex software. Very little documentation and code is not commented.

@JGJP
Copy link

JGJP commented Mar 28, 2023

@tuloski generally you would just have to change the rpc endpoint, address format, and denom

@ally9335
Copy link

How to load or create a Wallet from a private key? The same as this

let wallet = DirectSecp256k1HdWallet.fromMnemonic(....)

but from an existing private key.

@Adophilus
Copy link

@ally9335 I tried this but it didn't work... unfortunately 🥲

@dlpigpen
Copy link

I got this error when executing a message: Unregistered type url: /cosmwasm.wasm.v1.MsgExecuteContract

@mrtruongleo
Copy link

How to load or create a Wallet from a private key? The same as this

let wallet = DirectSecp256k1HdWallet.fromMnemonic(....)

but from an existing private key.

to load wallet from a private key, you can try this:

import { Secp256k1Wallet} from "@cosmjs/launchpad"; //you need to install 
const wallet = await Secp256k1Wallet.fromKey(
  Buffer.from('Your_private_key', "hex"), 
 'cosmos' //here you can get address with other prefix (like dydx, celestia...)
);
const senderAddress = (await wallet.getAccounts())[0].address;

@mehranhydary
Copy link

@dlpigpen did you figure out the issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment