Cosmos Transaction

Every transaction on Injective follows the same flow. The flow consists of three steps: preparing, signing and broadcasting the transaction. Let's dive into each step separately and explain the process in-depth (including examples) so we can understand the whole transaction flow.

Preparing a transaction

First of, we need to prepare the transaction for signing.

At this point you can't use some online abstractions that provide a quick way to prepare the transaction for you based on the provided Message and the signer (ex. using the @cosmjs/stargate package). The reason why is that these packages don't support Injective's publicKey typeUrl, so we have to do the preparation of the address on the client side.

To resolve this, we have provided functions which can prepare the txRaw transaction within out @injectivelabs/sdk-ts package. txRaw is the transaction interface used in Cosmos that contains details about the transaction and the signer itself.

Getting a private key from cosmos wallets is usually done by taking the current key for the chainId and accessing the pubKey from there (ex: const key = await window.keplr.getKey(chainId) => const pubKey = key.publicKey).

import {
  MsgSend,
  BaseAccount,
  ChainRestAuthApi,
  createTransaction,
  ChainRestTendermintApi,
} from "@injectivelabs/sdk-ts";
import { toBigNumber, toChainFormat } from "@injectivelabs/utils";
import { getStdFee, DEFAULT_BLOCK_TIMEOUT_HEIGHT } from "@injectivelabs/utils";

(async () => {
  const injectiveAddress = "inj1";
  const chainId = "injective-1"; /* ChainId.Mainnet */
  const restEndpoint =
    "https://sentry.lcd.injective.network"; /* getNetworkEndpoints(Network.MainnetSentry).rest */
  const amount = {
    denom: "inj",
    amount: toChainFormat(0.01).toFixed(),
  };

  /** Account Details **/
  const chainRestAuthApi = new ChainRestAuthApi(restEndpoint);
  const accountDetailsResponse = await chainRestAuthApi.fetchAccount(
    injectiveAddress
  );
  const baseAccount = BaseAccount.fromRestApi(accountDetailsResponse);

  /** Block Details */
  const chainRestTendermintApi = new ChainRestTendermintApi(restEndpoint);
  const latestBlock = await chainRestTendermintApi.fetchLatestBlock();
  const latestHeight = latestBlock.header.height;
  const timeoutHeight = toBigNumber(latestHeight).plus(
    DEFAULT_BLOCK_TIMEOUT_HEIGHT
  );

  /** Preparing the transaction */
  const msg = MsgSend.fromJSON({
    amount,
    srcInjectiveAddress: injectiveAddress,
    dstInjectiveAddress: injectiveAddress,
  });

  /** Get the PubKey of the Signer from the Wallet/Private Key */
  const pubKey = await getPubKey();

  /** Prepare the Transaction **/
  const { txRaw, signDoc } = createTransaction({
    pubKey,
    chainId,
    fee: getStdFee({}),
    message: msg,
    sequence: baseAccount.sequence,
    timeoutHeight: timeoutHeight.toNumber(),
    accountNumber: baseAccount.accountNumber,
  });
})();

Signing a transaction

Once we have prepared the transaction, we proceed to signing. Once you get the txRaw transaction from the previous step use any Cosmos native wallet to sign (ex: Keplr),

You can also use our @injectivelabs/wallet-strategy package to get out-of-the-box wallet provides that will give you abstracted methods that you can use to sign transactions. Refer to the documentation of the package, its straightforward to setup and use. This is the recommended way as you have access to more than one wallet to use in your dApp. The WalletStrategy provides more than just signing transaction abstractions.

Broadcasting a transaction

Once we have the signature ready, we need to broadcast the transaction to the Injective chain itself. After getting the signature from the second step, we need to include it in the signed transaction and broadcast it to the chain.

Example (Prepare + Sign + Broadcast)

Let's have a look at the whole flow (using Keplr as a signing wallet)

Example with WalletStrategy (Prepare + Sign + Broadcast)

Example can be found here.

Last updated