or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

decoding.mdindex.mdpubkey.mdregistry.mdsigning.mdwallets.md
tile.json

signing.mddocs/

Transaction Signing

Direct signing utilities for creating signing documents and authentication information for Cosmos SDK transactions. These functions support the direct signing mode (ADR-020) using protobuf serialization.

Capabilities

Signing Document Creation

Create and serialize signing documents for Cosmos SDK transactions.

/**
 * Creates a SignDoc for transaction signing
 * @param bodyBytes - Serialized transaction body
 * @param authInfoBytes - Serialized authentication info
 * @param chainId - Chain identifier (e.g., "cosmoshub-4")
 * @param accountNumber - Account number from the blockchain
 * @returns SignDoc ready for signing
 */
function makeSignDoc(
  bodyBytes: Uint8Array,
  authInfoBytes: Uint8Array,
  chainId: string,
  accountNumber: number
): SignDoc;

/**
 * Creates the bytes that need to be signed from a SignDoc
 * @param signDoc - The signing document
 * @returns Serialized bytes for signing
 */
function makeSignBytes(signDoc: SignDoc): Uint8Array;

Usage Examples:

import { makeSignDoc, makeSignBytes } from "@cosmjs/proto-signing";
import { TxBody, AuthInfo } from "cosmjs-types/cosmos/tx/v1beta1/tx";

// Create transaction body and auth info (simplified example)
const txBody = TxBody.fromPartial({
  messages: [/* your messages */],
  memo: "My transaction",
});
const bodyBytes = TxBody.encode(txBody).finish();

const authInfo = AuthInfo.fromPartial({
  signerInfos: [/* signer info */],
  fee: { amount: [], gasLimit: BigInt(200000) },
});
const authInfoBytes = AuthInfo.encode(authInfo).finish();

// Create signing document
const signDoc = makeSignDoc(
  bodyBytes,
  authInfoBytes,
  "cosmoshub-4",
  123 // account number
);

// Get bytes to sign
const signBytes = makeSignBytes(signDoc);

// Sign with wallet
const signature = await wallet.signDirect(signerAddress, signDoc);

Authentication Info Creation

Create authentication information containing signer details and fee information.

/**
 * Creates and serializes an AuthInfo document
 * This implementation does not support different signing modes for different signers
 * @param signers - Array of signer information with public keys and sequence numbers
 * @param feeAmount - Array of fee amounts in various denominations
 * @param gasLimit - Gas limit for the transaction
 * @param feeGranter - Optional fee granter address
 * @param feePayer - Optional fee payer address
 * @param signMode - Signing mode, defaults to SIGN_MODE_DIRECT
 * @returns Serialized AuthInfo bytes
 */
function makeAuthInfoBytes(
  signers: ReadonlyArray<{ readonly pubkey: Any; readonly sequence: bigint | number }>,
  feeAmount: readonly Coin[],
  gasLimit: number,
  feeGranter: string | undefined,
  feePayer: string | undefined,
  signMode?: SignMode
): Uint8Array;

Usage Examples:

import { makeAuthInfoBytes, encodePubkey } from "@cosmjs/proto-signing";
import { coins } from "@cosmjs/amino";
import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing";

// Prepare signer information
const account = (await wallet.getAccounts())[0];
const pubkeyAny = encodePubkey({
  type: "tendermint/PubKeySecp256k1",
  value: toBase64(account.pubkey),
});

const signers = [{
  pubkey: pubkeyAny,
  sequence: 42, // Current account sequence
}];

// Create auth info
const authInfoBytes = makeAuthInfoBytes(
  signers,
  coins(5000, "uatom"), // Fee amount
  200000, // Gas limit
  undefined, // No fee granter
  undefined, // No fee payer
  SignMode.SIGN_MODE_DIRECT
);

Fee Granter and Fee Payer Support

Support for advanced fee payment scenarios including third-party fee payment.

// Fee granter example - someone else pays fees
const authInfoWithGranter = makeAuthInfoBytes(
  signers,
  coins(5000, "uatom"),
  200000,
  "cosmos1feeGranterAddress...", // Fee granter pays
  undefined,
  SignMode.SIGN_MODE_DIRECT
);

// Fee payer example - explicit fee payer
const authInfoWithPayer = makeAuthInfoBytes(
  signers,
  coins(5000, "uatom"),
  200000,
  undefined,
  "cosmos1feePayerAddress...", // Explicit fee payer
  SignMode.SIGN_MODE_DIRECT
);

Types

interface SignDoc {
  /** Serialized transaction body bytes */
  bodyBytes: Uint8Array;
  /** Serialized auth info bytes */
  authInfoBytes: Uint8Array;
  /** Chain identifier */
  chainId: string;
  /** Account number from blockchain state */
  accountNumber: bigint;
}

interface Coin {
  /** Denomination (e.g., "uatom", "stake") */
  denom: string;
  /** Amount as string */
  amount: string;
}

interface Any {
  /** Type URL identifying the message type */
  typeUrl: string;
  /** Serialized message value */
  value: Uint8Array;
}

enum SignMode {
  /** Direct signing mode using protobuf serialization */
  SIGN_MODE_DIRECT = 1,
  /** Legacy amino signing mode */
  SIGN_MODE_LEGACY_AMINO_JSON = 127,
}

Complete Signing Flow

import {
  DirectSecp256k1HdWallet,
  makeSignDoc,
  makeAuthInfoBytes,
  Registry,
  encodePubkey
} from "@cosmjs/proto-signing";
import { TxBody } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import { MsgSend } from "cosmjs-types/cosmos/bank/v1beta1/tx";
import { coins, toBase64 } from "@cosmjs/amino";

// 1. Create wallet and get account
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic);
const accounts = await wallet.getAccounts();
const signerAddress = accounts[0].address;

// 2. Create transaction body
const registry = new Registry();
registry.register("/cosmos.bank.v1beta1.MsgSend", MsgSend);

const sendMsg = {
  fromAddress: signerAddress,
  toAddress: "cosmos1recipient...",
  amount: coins(1000000, "uatom"),
};

const txBody = TxBody.fromPartial({
  messages: [registry.encode({ typeUrl: "/cosmos.bank.v1beta1.MsgSend", value: sendMsg })],
  memo: "Sent via @cosmjs/proto-signing",
});
const bodyBytes = TxBody.encode(txBody).finish();

// 3. Create auth info
const pubkeyAny = encodePubkey({
  type: "tendermint/PubKeySecp256k1",
  value: toBase64(accounts[0].pubkey),
});

const authInfoBytes = makeAuthInfoBytes(
  [{ pubkey: pubkeyAny, sequence: 42 }],
  coins(5000, "uatom"), // Fee
  200000, // Gas limit
  undefined, // Fee granter
  undefined  // Fee payer
);

// 4. Create and sign
const signDoc = makeSignDoc(bodyBytes, authInfoBytes, "cosmoshub-4", 123);
const signResponse = await wallet.signDirect(signerAddress, signDoc);

console.log("Signature:", signResponse.signature);
console.log("Signed doc:", signResponse.signed);