JavaScript / TypeScript SDK

The official JavaScript SDK for Lichen. Full TypeScript types, async/await API, and integrated WebSocket subscriptions.

Installation

bash
npm install @lichen/sdk

The SDK requires Node.js 18+ or a browser environment with fetch support. WebSocket features require the ws package in Node.js (included as a dependency).

The package is not yet published to npm. For now, install from the local source in sdk/js/:

bash
npm install ./sdk/js

Quick Start

TypeScript
import { Connection, Keypair, PublicKey, TransactionBuilder } from '@lichen/sdk';

// Connect to a local validator
const conn = new Connection('http://localhost:8899', 'ws://localhost:8900');

// Generate a keypair
const keypair = Keypair.generate();
console.log('Address:', keypair.pubkey().toBase58());

// Check balance
const balance = await conn.getBalance(keypair.pubkey());
console.log(`Balance: ${balance.molt} LICN (${balance.spores} spores)`);

// Build and send a transfer
const recipient = new PublicKey('RecipientBase58Address...');
const blockhash = await conn.getRecentBlockhash();

const tx = new TransactionBuilder()
  .add(TransactionBuilder.transfer(keypair.pubkey(), recipient, 1_000_000_000))
  .setRecentBlockhash(blockhash)
  .buildAndSign(keypair);

const signature = await conn.sendTransaction(tx);
console.log('TX Signature:', signature);

Connection Class

new Connection(rpcUrl, wsUrl?)

Create a connection to a Lichen validator node.

Parameters

Name Type Required Description
rpcUrl string Yes HTTP JSON-RPC endpoint URL
wsUrl string No WebSocket endpoint URL (required for subscriptions)
TypeScript
const conn = new Connection('http://localhost:8899', 'ws://localhost:8900');

Chain Queries

getSlot(): Promise<number>

Get the current slot number.

TypeScript
const slot = await conn.getSlot();
// 42

getLatestBlock(): Promise<Block>

Get the most recently produced block. Returns { slot, hash, parentHash, transactions, timestamp }.

TypeScript
const block = await conn.getLatestBlock();
console.log(`Slot ${block.slot}, ${block.transactions} txs`);

getBlock(slot: number): Promise<Block>

Get a block by slot number.

TypeScript
const block = await conn.getBlock(42);

getRecentBlockhash(): Promise<string>

Get a recent blockhash for signing transactions.

TypeScript
const blockhash = await conn.getRecentBlockhash();

getMetrics(): Promise<Metrics>

Get chain performance metrics: { tps, totalTransactions, totalBlocks, averageBlockTime }.

getChainStatus(): Promise<ChainStatus>

Get comprehensive status: { currentSlot, validatorCount, totalStake, tps, totalTransactions, totalBlocks, averageBlockTime, isHealthy }.

health(): Promise<{ status: string }>

Liveness probe. Returns { status: "ok" }.

getNetworkInfo(): Promise<NetworkInfo>

Get network info: { chainId, networkId, version, currentSlot, validatorCount, peerCount }.

getPeers(): Promise<any[]>

Get connected P2P peers.

getTotalBurned(): Promise<Balance>

Get total burned LICN. Returns { spores, licn }.

Account Methods

getBalance(pubkey: PublicKey): Promise<Balance>

Get account balance in spores and LICN.

Parameters

Name Type Required Description
pubkey PublicKey Yes Account public key
TypeScript
const balance = await conn.getBalance(new PublicKey('7xKXtg2CW87d...'));
console.log(balance.spores); // 5000000000
console.log(balance.molt);   // 5.0

getAccount(pubkey: PublicKey): Promise<Account>

Get raw account data: { spores, owner, executable, data }.

getAccountInfo(pubkey: PublicKey): Promise<any>

Get enhanced account information with additional metadata.

getTransactionHistory(pubkey: PublicKey, limit?: number): Promise<any>

Get paginated transaction history for an account. Default limit is 10.

Transaction Methods

sendTransaction(transaction: Transaction): Promise<string>

Serialize and submit a signed transaction to the mempool. Returns the transaction signature.

Parameters

Name Type Required Description
transaction Transaction Yes A signed Transaction object
TypeScript
const blockhash = await conn.getRecentBlockhash();
const tx = new TransactionBuilder()
  .add(TransactionBuilder.transfer(from.pubkey(), to, 1_000_000_000))
  .setRecentBlockhash(blockhash)
  .buildAndSign(from);

const sig = await conn.sendTransaction(tx);
console.log('Signature:', sig);

getTransaction(signature: string): Promise<any>

Look up a transaction by its hex-encoded signature.

simulateTransaction(transaction: Transaction): Promise<any>

Dry-run a transaction without committing it. Useful for fee estimation and validation.

Validator & Staking

getValidators(): Promise<Validator[]>

Get all registered validators with stake, reputation, blocks proposed, votes cast.

getValidatorInfo(pubkey: PublicKey): Promise<Validator>

Get detailed information for a specific validator.

getValidatorPerformance(pubkey: PublicKey): Promise<any>

Get performance metrics for a validator.

stake(from: Keypair, validator: PublicKey, amount: number): Promise<string>

Build, sign, and send a stake transaction. Amount is in spores.

TypeScript
const validator = new PublicKey('ValidatorPubkey...');
const sig = await conn.stake(keypair, validator, 10_000_000_000); // 10 LICN

unstake(from: Keypair, validator: PublicKey, amount: number): Promise<string>

Build, sign, and send an unstake request transaction.

getStakingStatus(pubkey: PublicKey): Promise<any>

Get staking status for an account.

getStakingRewards(pubkey: PublicKey): Promise<any>

Get accumulated staking rewards.

Contract Methods

getContractInfo(contractId: PublicKey): Promise<any>

Get information about a deployed smart contract. Returns contract_id, owner, code_size, is_executable, has_abi, abi_functions, code_hash, version. For tokens, includes a token_metadata object with total_supply, decimals, token_symbol, token_name, mintable, burnable. Registry metadata (from --metadata at deploy) may also include description, website, logo_url, twitter, telegram, discord.

getContractLogs(contractId: PublicKey): Promise<any>

Get execution logs emitted by a contract.

getContractAbi(contractId: PublicKey): Promise<any>

Get the ABI/IDL for a contract.

setContractAbi(contractId: PublicKey, abi: any): Promise<any>

Set or update a contract's ABI (owner only).

getAllContracts(): Promise<any>

List all deployed contracts.

Program Methods

getProgram(programId: PublicKey): Promise<any>

Get program information.

getPrograms(): Promise<any>

List all deployed programs.

getProgramStats(programId: PublicKey): Promise<any>

Get execution statistics for a program.

getProgramCalls(programId: PublicKey): Promise<any>

Get recent call history for a program.

getProgramStorage(programId: PublicKey): Promise<any>

Get on-chain storage summary for a program.

NFT Methods

getCollection(collectionId: PublicKey): Promise<any>

Get NFT collection metadata.

getNFT(collectionId: PublicKey, tokenId: number): Promise<any>

Get a specific NFT by collection and token ID.

getNFTsByOwner(owner: PublicKey): Promise<any>

Get all NFTs owned by an address.

getNFTsByCollection(collectionId: PublicKey): Promise<any>

Get all NFTs in a collection.

getNFTActivity(collectionId: PublicKey, tokenId: number): Promise<any>

Get activity history for a specific NFT.

WebSocket Subscriptions

All subscription methods require a wsUrl to be set in the Connection constructor. Each on* method returns a subscription ID for later unsubscribing with the corresponding off* method.

onSlot(callback: (slot: number) => void): Promise<number>

Subscribe to slot updates. Unsubscribe with offSlot(subId).

onBlock(callback: (block: Block) => void): Promise<number>

Subscribe to new blocks. Unsubscribe with offBlock(subId).

onTransaction(callback: (tx: any) => void): Promise<number>

Subscribe to transactions observed in canonical blocks. Use signature status subscriptions when you need explicit processed / confirmed / finalized commitment tracking. Unsubscribe with offTransaction(subId).

onAccountChange(pubkey: PublicKey, callback: (account: any) => void): Promise<number>

Watch a specific account for balance changes. Unsubscribe with offAccountChange(subId).

onLogs(callback: (log: any) => void, contractId?: PublicKey): Promise<number>

Stream contract logs. Pass a contractId to filter to one contract, or omit for all. Unsubscribe with offLogs(subId).

onProgramUpdates(callback) / onProgramCalls(callback, programId?)

Subscribe to program deploy/upgrade events and program invocations. Unsubscribe with offProgramUpdates(subId) / offProgramCalls(subId).

onNftMints(callback, collectionId?) / onNftTransfers(callback, collectionId?)

Subscribe to NFT mint and transfer events. Optionally filter by collection. Unsubscribe with offNftMints(subId) / offNftTransfers(subId).

onMarketListings(callback) / onMarketSales(callback)

Subscribe to marketplace listing and sale events. Unsubscribe with offMarketListings(subId) / offMarketSales(subId).

close(): void

Close the WebSocket connection and clear all subscriptions.

Keypair Class

Ed25519 keypair for signing transactions. Uses tweetnacl under the hood.

Keypair.generate(): Keypair

Generate a new random keypair.

TypeScript
const kp = Keypair.generate();
console.log('Public key:', kp.pubkey().toBase58());
console.log('Secret key length:', kp.secretKey.length); // 64 bytes

Keypair.fromSeed(seed: Uint8Array): Keypair

Derive a keypair from a 32-byte seed. Throws if seed is not exactly 32 bytes.

TypeScript
const seed = new Uint8Array(32); // deterministic seed
const kp = Keypair.fromSeed(seed);

keypair.pubkey(): PublicKey

Get the public key as a PublicKey object.

keypair.sign(message: Uint8Array): Uint8Array

Sign an arbitrary message. Returns the 64-byte Ed25519 detached signature.

Properties

Property Type Description
publicKey Uint8Array 32-byte public key
secretKey Uint8Array 64-byte secret key (seed + public key)

PublicKey Class

A 32-byte public key with base58 encoding/decoding. Uses bs58 under the hood.

new PublicKey(value: string | Uint8Array | number[])

Create a PublicKey from a base58 string, Uint8Array, or number array. Throws if the resulting bytes are not exactly 32 bytes.

TypeScript
const pk1 = new PublicKey('7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU');
const pk2 = new PublicKey(new Uint8Array(32));
const pk3 = new PublicKey([0, 1, 2, /* ... 32 bytes */]);

Methods

Method Returns Description
toBase58() string Base58-encoded string representation
toBytes() Uint8Array Raw 32-byte array
toString() string Same as toBase58()
equals(other: PublicKey) boolean Byte-level equality check

Static Methods

Method Returns Description
PublicKey.fromBase58(str) PublicKey Create from base58 string
PublicKey.fromBytes(bytes) PublicKey Create from Uint8Array

Transaction Types & Builder

Types

TypeScript
interface Instruction {
  programId: PublicKey;
  accounts: PublicKey[];
  data: Uint8Array;
}

interface Message {
  instructions: Instruction[];
  recentBlockhash: string;
}

interface Transaction {
  signatures: string[];  // hex-encoded
  message: Message;
}

TransactionBuilder

Fluent builder for constructing and signing transactions.

Method Returns Description
add(instruction) this Append an instruction
setRecentBlockhash(hash) this Set the recent blockhash
build() Message Build unsigned message
buildAndSign(keypair) Transaction Build, sign, and return a Transaction

Static Instruction Builders

Method Description
TransactionBuilder.transfer(from, to, amount) Create a LICN transfer instruction (type 0)
TransactionBuilder.stake(from, validator, amount) Create a stake instruction (type 9)
TransactionBuilder.unstake(from, validator, amount) Create an unstake instruction (type 10)
TypeScript
const blockhash = await conn.getRecentBlockhash();

const tx = new TransactionBuilder()
  .add(TransactionBuilder.transfer(
    keypair.pubkey(),
    new PublicKey('RecipientAddr...'),
    5_000_000_000  // 5 LICN
  ))
  .setRecentBlockhash(blockhash)
  .buildAndSign(keypair);

const sig = await conn.sendTransaction(tx);

Error Handling

All RPC methods throw standard JavaScript Error objects with descriptive messages from the server.

TypeScript
try {
  const balance = await conn.getBalance(pubkey);
} catch (error) {
  if (error.message.includes('Account not found')) {
    console.log('Account does not exist yet');
  } else if (error.message.includes('Rate limit')) {
    // Back off and retry
    await new Promise(r => setTimeout(r, 1000));
  } else {
    throw error;
  }
}

Common error codes:

  • -32601 — Method not found
  • -32602 — Invalid params
  • -32003 — Admin auth required
  • -32005 — Rate limit exceeded / Subscription limit reached