# @cosmjs/amino Agent Guide

> **Package**: `@cosmjs/amino` v0.38.0 **Purpose**: Amino encoding, signing, and
> wallet management for Cosmos SDK chains **Layer**: Signing Layer (depends on
> crypto, encoding, math, utils)

---

## Package Overview

### What does this package do?

`@cosmjs/amino` provides Amino JSON encoding and signing capabilities for Cosmos
SDK transactions. Amino is the legacy JSON-based serialization format used
before Protobuf became standard in Cosmos SDK 0.40+. This package is essential
for:

- **Wallet Management**: HD wallets (BIP-39/BIP-44/SLIP-10) with Secp256k1
- **Transaction Signing**: Amino JSON format signing
- **Address Generation**: Bech32 address encoding from public keys
- **Coin Handling**: Safe coin arithmetic and parsing
- **Multisig Support**: Creating and managing multisig threshold pubkeys

### When to use this package

- Building wallets that need to sign Amino transactions
- Supporting legacy Cosmos SDK chains (pre-0.40)
- Implementing offline signers
- Working with Ledger hardware wallets (via amino signing)
- Creating multisig transactions

### When NOT to use this package

- For Protobuf Direct signing → use `@cosmjs/proto-signing`
- For cryptographic primitives only → use `@cosmjs/crypto`
- For RPC communication → use `@cosmjs/tendermint-rpc`
- For high-level client operations → use `@cosmjs/stargate`

---

## Key Exports

### Wallet Classes

| Export              | Purpose                        | Usage                               |
| ------------------- | ------------------------------ | ----------------------------------- |
| `Secp256k1HdWallet` | HD wallet with BIP-39 mnemonic | Primary wallet implementation       |
| `Secp256k1Wallet`   | Single-key wallet              | Simple wallet without HD derivation |

### Signing Interfaces

| Export               | Purpose                                     |
| -------------------- | ------------------------------------------- |
| `OfflineAminoSigner` | Interface for Amino signers                 |
| `AminoSignResponse`  | Signature response format                   |
| `AccountData`        | Account information (address, pubkey, algo) |

### Address Functions

| Export                                   | Purpose                             |
| ---------------------------------------- | ----------------------------------- |
| `pubkeyToAddress(pubkey, prefix)`        | Convert pubkey to Bech32 address    |
| `pubkeyToRawAddress(pubkey)`             | Convert pubkey to raw address bytes |
| `rawSecp256k1PubkeyToRawAddress(pubkey)` | Secp256k1-specific conversion       |

### Coin Utilities

| Export                   | Purpose                            |
| ------------------------ | ---------------------------------- |
| `coin(amount, denom)`    | Create a single coin               |
| `coins(amount, denom)`   | Create a coin array                |
| `parseCoins(string)`     | Parse "1000uatom,500ustake" format |
| `addCoins(coin1, coin2)` | Add two coins safely               |

### Encoding Functions

| Export                                | Purpose                       |
| ------------------------------------- | ----------------------------- |
| `encodeSecp256k1Pubkey(pubkey)`       | Encode pubkey to Amino format |
| `encodeBech32Pubkey(pubkey, prefix)`  | Encode pubkey to Bech32       |
| `decodeAminoPubkey(pubkey)`           | Decode Amino pubkey           |
| `encodeSecp256k1Signature(signature)` | Encode signature              |

### Sign Doc Functions

| Export                                                           | Purpose               |
| ---------------------------------------------------------------- | --------------------- |
| `makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence)` | Create sign document  |
| `serializeSignDoc(signDoc)`                                      | Serialize for signing |

---

## Common Usage Patterns

### 1. Creating a Wallet from Mnemonic

✅ **CORRECT**: Use static factory method

```typescript
import { Secp256k1HdWallet } from "@cosmjs/amino";

// Create wallet from mnemonic
const wallet = await Secp256k1HdWallet.fromMnemonic(
  "surround miss nominee dream gap cross assault thank captain prosper drop duty group candy wealth weather scale put",
  {
    prefix: "cosmos", // Address prefix
    hdPaths: [makeCosmoshubPath(0)], // Derivation path
  },
);

// Get accounts
const accounts = await wallet.getAccounts();
console.log(accounts[0].address); // cosmos1...
```

### 2. Generating a New Wallet

✅ **CORRECT**: Generate with 12, 15, 18, 21, or 24 word mnemonic

```typescript
import { Secp256k1HdWallet } from "@cosmjs/amino";

// Generate new wallet (24 words by default)
const wallet = await Secp256k1HdWallet.generate(24, {
  prefix: "osmo", // Osmosis addresses
});

const mnemonic = wallet.mnemonic;
// IMPORTANT: Store mnemonic securely!
```

### 3. Signing a Transaction

✅ **CORRECT**: Use signAmino method

```typescript
import { makeSignDoc, serializeSignDoc } from "@cosmjs/amino";

const signDoc = makeSignDoc(
  [msg], // Array of AminoMsg
  {
    amount: [{ amount: "5000", denom: "uatom" }],
    gas: "200000",
  },
  "cosmoshub-4", // Chain ID
  "My memo",
  "12345", // Account number (string!)
  "67", // Sequence (string!)
);

const { signature, signed } = await wallet.signAmino(signerAddress, signDoc);
```

### 4. Working with Coins

✅ **CORRECT**: Safe coin operations

```typescript
import { coin, coins, parseCoins, addCoins } from "@cosmjs/amino";

// Create single coin
const amount1 = coin(1000, "uatom");

// Create coin array
const amount2 = coins(500, "uatom");

// Parse from string
const parsed = parseCoins("1000uatom,500ustake");
// [{ amount: "1000", denom: "uatom" }, { amount: "500", denom: "ustake" }]

// Add coins safely
const total = addCoins(
  { amount: "1000", denom: "uatom" },
  { amount: "500", denom: "uatom" },
);
// { amount: "1500", denom: "uatom" }
```

❌ **WRONG**: Mixing denoms

```typescript
// This will throw an error
const invalid = addCoins(
  { amount: "1000", denom: "uatom" },
  { amount: "500", denom: "ustake" }, // Different denom!
);
```

### 5. Serializing and Deserializing Wallets

✅ **CORRECT**: Encrypt wallet with password

```typescript
import { Secp256k1HdWallet } from "@cosmjs/amino";

// Serialize (encrypt) wallet
const serialized = await wallet.serialize("my-strong-password");
// Returns encrypted JSON string

// Deserialize (decrypt) wallet
const restored = await Secp256k1HdWallet.deserialize(
  serialized,
  "my-strong-password",
);
```

### 6. Custom HD Paths

✅ **CORRECT**: Specify custom derivation paths

```typescript
import { Secp256k1HdWallet } from "@cosmjs/amino";
import { stringToPath } from "@cosmjs/crypto";

const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: "cosmos",
  hdPaths: [
    stringToPath("m/44'/118'/0'/0/0"), // Account 0
    stringToPath("m/44'/118'/0'/0/1"), // Account 1
    stringToPath("m/44'/118'/1'/0/0"), // Different wallet
  ],
});

// This wallet now manages 3 accounts
const accounts = await wallet.getAccounts();
// accounts.length === 3
```

### 7. Converting Pubkey to Address

✅ **CORRECT**: Use pubkeyToAddress helper

```typescript
import { pubkeyToAddress, encodeSecp256k1Pubkey } from "@cosmjs/amino";

const pubkey = encodeSecp256k1Pubkey(pubkeyBytes);
const address = pubkeyToAddress(pubkey, "cosmos");
// Returns: "cosmos1..."
```

### 8. Creating Multisig Pubkey

✅ **CORRECT**: Threshold multisig setup

```typescript
import {
  createMultisigThresholdPubkey,
  encodeSecp256k1Pubkey,
} from "@cosmjs/amino";

const pubkey1 = encodeSecp256k1Pubkey(pubkeyBytes1);
const pubkey2 = encodeSecp256k1Pubkey(pubkeyBytes2);
const pubkey3 = encodeSecp256k1Pubkey(pubkeyBytes3);

// 2-of-3 multisig
const multisigPubkey = createMultisigThresholdPubkey(
  [pubkey1, pubkey2, pubkey3],
  2, // Threshold
);
```

---

## Type Definitions

### Core Types

```typescript
// Account data returned by getAccounts()
interface AccountData {
  readonly address: string; // Bech32 address
  readonly algo: Algo; // "secp256k1" | "ed25519" | "sr25519"
  readonly pubkey: Uint8Array; // Raw public key bytes
}

// Coin type
interface Coin {
  readonly denom: string; // e.g. "uatom"
  readonly amount: string; // Always string for safety
}

// Amino message (generic)
interface AminoMsg {
  readonly type: string; // e.g. "cosmos-sdk/MsgSend"
  readonly value: any; // Message-specific data
}

// Standard fee
interface StdFee {
  readonly amount: readonly Coin[];
  readonly gas: string;
  readonly granter?: string;
  readonly payer?: string;
}

// Sign document
interface StdSignDoc {
  readonly chain_id: string;
  readonly account_number: string;
  readonly sequence: string;
  readonly fee: StdFee;
  readonly msgs: readonly AminoMsg[];
  readonly memo: string;
}

// Signature response
interface AminoSignResponse {
  readonly signed: StdSignDoc;
  readonly signature: StdSignature;
}

interface StdSignature {
  readonly pub_key: Pubkey;
  readonly signature: string; // Base64 encoded
}
```

### Pubkey Types

```typescript
// Secp256k1 pubkey (most common)
interface Secp256k1Pubkey {
  readonly type: "tendermint/PubKeySecp256k1";
  readonly value: string; // Base64 encoded
}

// Ed25519 pubkey
interface Ed25519Pubkey {
  readonly type: "tendermint/PubKeyEd25519";
  readonly value: string;
}

// Multisig threshold pubkey
interface MultisigThresholdPubkey {
  readonly type: "tendermint/PubKeyMultisigThreshold";
  readonly value: {
    readonly threshold: string;
    readonly pubkeys: readonly Pubkey[];
  };
}
```

---

## Configuration

### Wallet Options

```typescript
interface Secp256k1HdWalletOptions {
  /** BIP39 password (usually empty string) */
  readonly bip39Password: string;

  /** HD derivation paths (default: m/44'/118'/0'/0/0) */
  readonly hdPaths: readonly HdPath[];

  /** Bech32 address prefix (default: "cosmos") */
  readonly prefix: string;
}
```

### Default Values

| Option          | Default                  | Description                |
| --------------- | ------------------------ | -------------------------- |
| `bip39Password` | `""`                     | Empty string (no password) |
| `hdPaths`       | `[makeCosmoshubPath(0)]` | `m/44'/118'/0'/0/0`        |
| `prefix`        | `"cosmos"`               | Cosmos Hub addresses       |

### Common Address Prefixes

| Chain          | Prefix   | Coin Type |
| -------------- | -------- | --------- |
| Cosmos Hub     | `cosmos` | 118       |
| Osmosis        | `osmo`   | 118       |
| Juno           | `juno`   | 118       |
| Stargaze       | `stars`  | 118       |
| Akash          | `akash`  | 118       |
| Secret Network | `secret` | 529       |

---

## Security Best Practices

### 1. Mnemonic Storage

❌ **NEVER**:

```typescript
// Don't hardcode mnemonics
const wallet = await Secp256k1HdWallet.fromMnemonic(
  "surround miss nominee...", // NEVER DO THIS IN PRODUCTION
);

// Don't log mnemonics
console.log(wallet.mnemonic); // DANGEROUS!
```

✅ **DO**:

```typescript
// Use environment variables or secure storage
const mnemonic = process.env.WALLET_MNEMONIC;
if (!mnemonic) throw new Error("Mnemonic not configured");

// Use encrypted serialization
const encrypted = await wallet.serialize(strongPassword);
// Store encrypted string in database
```

### 2. Password Requirements

✅ **CORRECT**: Use strong passwords for serialization

```typescript
// Good password practices
const password = generateSecurePassword(); // At least 16 chars
const serialized = await wallet.serialize(password);

// Use KDF configuration for extra security
import { executeKdf } from "@cosmjs/amino";

const strongKdf = {
  algorithm: "argon2id",
  params: {
    outputLength: 32,
    opsLimit: 24,
    memLimitKib: 12 * 1024,
  },
};
```

### 3. Private Key Handling

❌ **NEVER**:

```typescript
// Don't expose private keys
const privkey = wallet.getPrivateKey(); // This doesn't exist!
```

✅ **DO**:

```typescript
// Use the wallet's signing methods
const signature = await wallet.signAmino(address, signDoc);
// Private key stays internal
```

---

## Common Patterns

### Pattern: Multi-Account Wallet

```typescript
import { Secp256k1HdWallet, makeCosmoshubPath } from "@cosmjs/amino";

// Create wallet with multiple accounts
const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: "cosmos",
  hdPaths: [makeCosmoshubPath(0), makeCosmoshubPath(1), makeCosmoshubPath(2)],
});

const accounts = await wallet.getAccounts();
// accounts[0].address: cosmos1...
// accounts[1].address: cosmos1... (different)
// accounts[2].address: cosmos1... (different)
```

### Pattern: Cross-Chain Wallet

```typescript
// Same mnemonic, different prefixes
const cosmosWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: "cosmos",
});

const osmoWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: "osmo",
});

// Same private key, different addresses
const [cosmosAccount] = await cosmosWallet.getAccounts();
const [osmoAccount] = await osmoWallet.getAccounts();
// cosmosAccount.address: cosmos1...
// osmoAccount.address: osmo1...
```

### Pattern: Offline Signing

```typescript
import { makeSignDoc, serializeSignDoc } from "@cosmjs/amino";

// 1. Create sign doc (can be done online)
const signDoc = makeSignDoc(msgs, fee, chainId, memo, accountNumber, sequence);

// 2. Sign offline (air-gapped machine)
const { signature, signed } = await wallet.signAmino(signerAddress, signDoc);

// 3. Broadcast online (different machine)
// Send signature + signed to online machine for broadcasting
```

---

## Testing Utilities

### Test Mnemonics

```typescript
// From testutils.ts
export const testMnemonic =
  "surround miss nominee dream gap cross assault thank captain prosper drop duty group candy wealth weather scale put";

// Use in tests
const testWallet = await Secp256k1HdWallet.fromMnemonic(testMnemonic);
```

### Mock Signer

```typescript
import { Secp256k1HdWallet } from "@cosmjs/amino";

// Create deterministic test wallet
const wallet = await Secp256k1HdWallet.fromMnemonic(
  "test test test test test test test test test test test junk",
  { prefix: "cosmos" },
);
```

---

## Common Mistakes to Avoid

### 1. Using Numbers for Large Amounts

❌ **WRONG**:

```typescript
// JavaScript numbers lose precision above 2^53
const coin = coin(9007199254740992, "uatom"); // Unsafe!
```

✅ **CORRECT**:

```typescript
// Use strings for large amounts
const coin = coin("9007199254740992", "uatom");
```

### 2. Forgetting Async/Await

❌ **WRONG**:

```typescript
const wallet = Secp256k1HdWallet.fromMnemonic(mnemonic); // Missing await!
```

✅ **CORRECT**:

```typescript
const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic);
```

### 3. Wrong Account Number/Sequence Types

❌ **WRONG**:

```typescript
const signDoc = makeSignDoc(
  msgs,
  fee,
  chainId,
  memo,
  12345, // Should be string!
  67, // Should be string!
);
```

✅ **CORRECT**:

```typescript
const signDoc = makeSignDoc(
  msgs,
  fee,
  chainId,
  memo,
  "12345", // String
  "67", // String
);
```

### 4. Mixing Coin Denoms

❌ **WRONG**:

```typescript
const total = addCoins(
  { amount: "100", denom: "uatom" },
  { amount: "50", denom: "uosmo" }, // Different denom throws!
);
```

✅ **CORRECT**:

```typescript
// Add coins with same denom
const total = addCoins(
  { amount: "100", denom: "uatom" },
  { amount: "50", denom: "uatom" },
);
```

### 5. Not Validating Mnemonic

❌ **WRONG**:

```typescript
// User input without validation
const wallet = await Secp256k1HdWallet.fromMnemonic(userInput);
```

✅ **CORRECT**:

```typescript
import { EnglishMnemonic } from "@cosmjs/crypto";

try {
  // Validates mnemonic format and checksum
  const mnemonic = new EnglishMnemonic(userInput);
  const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic.toString());
} catch (error) {
  console.error("Invalid mnemonic:", error);
}
```

---

## Dependencies

### Runtime Dependencies

| Package            | Purpose                                               |
| ------------------ | ----------------------------------------------------- |
| `@cosmjs/crypto`   | Cryptographic operations (Secp256k1, BIP-39, SLIP-10) |
| `@cosmjs/encoding` | Encoding utilities (base64, bech32, hex)              |
| `@cosmjs/math`     | Safe integer math (Uint53, Decimal)                   |
| `@cosmjs/utils`    | Assertions and utilities                              |

### Key Algorithms

- **BIP-39**: Mnemonic generation and seed derivation
- **BIP-44/SLIP-10**: HD key derivation
- **Secp256k1**: Elliptic curve signing
- **SHA-256**: Hashing for addresses
- **RIPEMD-160**: Address generation
- **Argon2id**: Key derivation for encryption
- **XChaCha20-Poly1305**: Symmetric encryption

---

## API Reference

### Secp256k1HdWallet Methods

| Method                                 | Returns                      | Description          |
| -------------------------------------- | ---------------------------- | -------------------- |
| `fromMnemonic(mnemonic, options?)`     | `Promise<Secp256k1HdWallet>` | Create from mnemonic |
| `generate(length?, options?)`          | `Promise<Secp256k1HdWallet>` | Generate new wallet  |
| `deserialize(serialization, password)` | `Promise<Secp256k1HdWallet>` | Decrypt wallet       |
| `serialize(password)`                  | `Promise<string>`            | Encrypt wallet       |
| `getAccounts()`                        | `Promise<AccountData[]>`     | Get all accounts     |
| `signAmino(address, signDoc)`          | `Promise<AminoSignResponse>` | Sign transaction     |

### Helper Functions

| Function                          | Purpose                   |
| --------------------------------- | ------------------------- |
| `makeCosmoshubPath(account)`      | Create Cosmos Hub HD path |
| `coin(amount, denom)`             | Create single coin        |
| `coins(amount, denom)`            | Create coin array         |
| `parseCoins(input)`               | Parse coin string         |
| `addCoins(a, b)`                  | Add two coins             |
| `pubkeyToAddress(pubkey, prefix)` | Convert pubkey to address |
| `encodeSecp256k1Pubkey(pubkey)`   | Encode pubkey             |
| `makeSignDoc(...)`                | Create sign document      |
| `serializeSignDoc(signDoc)`       | Serialize for signing     |

---

## Integration Examples

### With @cosmjs/stargate

```typescript
import { Secp256k1HdWallet } from "@cosmjs/amino";
import { SigningStargateClient } from "@cosmjs/stargate";

// Create wallet
const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic);

// Connect to chain
const client = await SigningStargateClient.connectWithSigner(
  "https://rpc.cosmos.network",
  wallet, // Amino signer works here
);
```

### With Ledger

```typescript
import { LedgerSigner } from "@cosmjs/ledger-amino";

// Ledger implements OfflineAminoSigner
const ledger = new LedgerSigner(transport, {
  hdPaths: [makeCosmoshubPath(0)],
  prefix: "cosmos",
});

// Use like any other Amino signer
const accounts = await ledger.getAccounts();
```

---

## Version History

- **0.38.0** (Current): Node.js 22+ support, @noble v2 upgrade
- **0.32.0**: Added support for IBC denoms in parseCoins
- **0.29.0**: Improved type safety
- **0.26.0**: Stargate support

---

## Additional Resources

- **Main Docs**: `/docs/packages/amino.md`
- **API Reference**: https://cosmos.github.io/cosmjs/modules/_cosmjs_amino.html
- **Source Code**: `/packages/amino/src/`
- **Tests**: `/packages/amino/src/*.spec.ts`

---

**Last Updated**: January 6, 2026 **Package Version**: 0.38.0 **Stability**:
Stable


