Cascade
Getting Started

Client Setup

Initialize the Lumera client for browser and Node.js environments.

Creating a Client

The createLumeraClient factory is the entry point for all Cascade operations. It connects to the Lumera blockchain and configures the Supernode API client.

Chain Configuration

Both Keplr and Leap require a chain configuration to register the Lumera network. Define it once and reuse it:

chain-config.ts
export const CHAIN_ID = "lumera-testnet-2";
 
export const LUMERA_CHAIN_INFO = {
  chainId: CHAIN_ID,
  chainName: "Lumera Testnet",
  rpc: "https://rpc.testnet.lumera.io",
  rest: "https://lcd.testnet.lumera.io",
  bip44: { coinType: 118 },
  bech32Config: {
    bech32PrefixAccAddr: "lumera",
    bech32PrefixAccPub: "lumerapub",
    bech32PrefixValAddr: "lumeravaloper",
    bech32PrefixValPub: "lumeravaloperpub",
    bech32PrefixConsAddr: "lumeravalcons",
    bech32PrefixConsPub: "lumeravalconspub",
  },
  currencies: [
    { coinDenom: "LUME", coinMinimalDenom: "ulume", coinDecimals: 6 },
  ],
  feeCurrencies: [
    {
      coinDenom: "LUME",
      coinMinimalDenom: "ulume",
      coinDecimals: 6,
      gasPriceStep: { low: 0.025, average: 0.03, high: 0.04 },
    },
  ],
  stakeCurrency: {
    coinDenom: "LUME",
    coinMinimalDenom: "ulume",
    coinDecimals: 6,
  },
  features: ["stargate", "ibc-transfer"],
};

Browser with Keplr Wallet

keplr-client.ts
import { createLumeraClient, getKeplrSigner } from "@lumera-protocol/sdk-js";
import { CHAIN_ID, LUMERA_CHAIN_INFO } from "./chain-config";
 
// Register the Lumera chain and request wallet access
await window.keplr.experimentalSuggestChain(LUMERA_CHAIN_INFO);
 
// getKeplrSigner returns a unified signer with getAccounts, signDirect,
// signAmino, and signArbitrary already wired up.
const signer = await getKeplrSigner(CHAIN_ID);
const [account] = await signer.getAccounts();
 
const client = await createLumeraClient({
  preset: "testnet",
  signer,
  address: account.address,
  gasPrice: "0.025ulume",
});

Browser with Leap Wallet

leap-client.ts
import { createLumeraClient } from "@lumera-protocol/sdk-js";
import { CHAIN_ID, LUMERA_CHAIN_INFO } from "./chain-config";
 
// Register the Lumera chain and request wallet access
await window.leap.experimentalSuggestChain(LUMERA_CHAIN_INFO);
await window.leap.enable(CHAIN_ID);
 
// getOfflineSignerAuto provides getAccounts, signAmino, and signDirect.
// We only need to add signArbitrary, Cascade uses it for Supernode auth.
const offlineSigner = await window.leap.getOfflineSignerAuto(CHAIN_ID);
const accounts = await offlineSigner.getAccounts();
 
const signer = {
  ...offlineSigner,
  async signArbitrary(_chainId: string, signerAddress: string, data: string) {
    const result = await window.leap.signArbitrary(_chainId, signerAddress, data);
    return { signed: data, signature: result.signature, pub_key: result.pub_key };
  },
};
 
const client = await createLumeraClient({
  preset: "testnet",
  signer,
  address: accounts[0].address,
  gasPrice: "0.025ulume",
});

Node.js with Mnemonic

In Node.js you need a Direct signer for transaction signing and an Amino signer for signArbitrary, which Cascade uses for Supernode authentication:

node-client.ts
import { createLumeraClient } from "@lumera-protocol/sdk-js";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import {
  Secp256k1HdWallet,
  makeSignDoc as makeAminoSignDoc,
} from "@cosmjs/amino";
 
const mnemonic = process.env.LUMERA_MNEMONIC!;
 
const directWallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: "lumera",
});
const aminoWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: "lumera",
});
const [account] = await directWallet.getAccounts();
 
const signer = {
  getAccounts: () => directWallet.getAccounts(),
  signDirect: (addr: string, doc: any) => directWallet.signDirect(addr, doc),
  signAmino: (addr: string, doc: any) => aminoWallet.signAmino(addr, doc),
  async signArbitrary(
    chainId: string,
    signerAddress: string,
    data: string
  ) {
    const signDoc = makeAminoSignDoc(
      [
        {
          type: "sign/MsgSignData",
          value: {
            signer: signerAddress,
            data: Buffer.from(data).toString("base64"),
          },
        },
      ],
      { gas: "0", amount: [] },
      "",
      "",
      0,
      0
    );
    const { signature } = await aminoWallet.signAmino(signerAddress, signDoc);
    return {
      signed: data,
      signature: signature.signature,
      pub_key: signature.pub_key,
    };
  },
};
 
const client = await createLumeraClient({
  preset: "testnet",
  signer: signer as any,
  address: account.address,
  gasPrice: "0.025ulume",
});

Security: Never hardcode mnemonics. Use environment variables or a secrets manager.

Client Configuration Options

interface LumeraClientConfig {
  // Use a preset for testnet or mainnet endpoints
  preset?: "testnet" | "mainnet";
 
  // Or specify endpoints manually
  // (without a preset, rpcUrl, chainId, and snapiUrl are all required)
  rpcUrl?: string;
  lcdUrl?: string;
  chainId?: string;
  snapiUrl?: string;
 
  // Signer (wallet or DirectSecp256k1HdWallet) - required
  signer: OfflineSigner;
 
  // Sender bech32 address - required
  address: string;
 
  // Gas price for transaction fee estimation
  gasPrice?: string;
 
  // HTTP client options for SN-API requests
  http?: {
    timeout?: number;    // default 30000
    maxRetries?: number; // default 3
  };
}

Presets

PresetChain IDRPCLCDSN-API
testnetlumera-testnet-2https://rpc.testnet.lumera.iohttps://lcd.testnet.lumera.iohttps://snapi.testnet.lumera.io
mainnetlumera-mainnet-1https://rpc.lumera.iohttps://lcd.lumera.iohttps://snapi.lumera.io

Custom Endpoints

For local development or self-hosted nodes:

const client = await createLumeraClient({
  chainId: "<your-chain-id>", // whatever you passed to `lumerad init --chain-id`
  rpcUrl: "http://localhost:26657",
  lcdUrl: "http://localhost:1317",
  snapiUrl: "http://localhost:8080",
  signer: wallet,
  address: account.address,
  gasPrice: "0.025ulume",
});

Client Structure

Once created, the client exposes two primary sub-clients:

// --- Blockchain queries (nested under Action / Supernode / Tx) ---
client.Blockchain.Action.getParams();
client.Blockchain.Action.getAction(actionId);
client.Blockchain.Action.getActionFee(dataSizeKb); // size in KB, rounded up
client.Blockchain.Supernode.listSupernodes();
client.Blockchain.Tx.signAndBroadcast(signerAddress, messages, fee);
 
// --- Cascade storage (high-level) ---
client.Cascade.uploader.uploadFile(file, params); // upload + monitor
client.Cascade.downloader.download(actionId);     // signs the action ID via ADR-036

Next Steps

Edit this page

On this page

Client Setup | Lumera Cascade Docs