MCPcopy Index your code
hub / github.com/Bvvvp009/lighter-ts

github.com/Bvvvp009/lighter-ts @v1.0.12

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.0.12 ↗ · + Follow
910 symbols 2,165 edges 121 files 156 documented · 17%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Lighter Protocol TypeScript SDK

A complete TypeScript SDK for Lighter Protocol - trade perpetual futures with built-in stop-loss and take-profit orders, position management, and comprehensive error handling.

🔐 Signer Integration

This SDK uses a WASM signer for cryptographic operations. The signer is compiled during the build process.

Key Features: - ✅ Uses a WASM signer for transaction signing - ✅ Automatic error recovery and nonce management - ✅ Support for all transaction types - ✅ Multiple API key support - ✅ Production-ready and battle-tested

📦 Installation

npm install lighter-ts-sdk
# or
yarn add lighter-ts-sdk

Module Formats

The package ships ESM, CommonJS, and a browser UMD bundle, resolved automatically via package.json's exports field. Both of the following work out of the box:

// ESM (import)
import { SignerClient, ApiClient, OrderType } from 'lighter-ts-sdk';
// CommonJS (require)
const { SignerClient, ApiClient, OrderType } = require('lighter-ts-sdk');

<script src="https://unpkg.com/lighter-ts-sdk/dist/umd/lighter-ts-sdk.js"></script>
<script>
  const { SignerClient } = window.LighterSDK;
</script>

🚀 What Does This SDK Do?

The Lighter TypeScript SDK provides everything you need to: - Trade perpetual futures and spot markets on Lighter Protocol - Create orders (Market, Limit, TWAP) with automatic SL/TP - Build grouped orders (OTO, OCO, OTOCO) and self-trade-prevention orders - Manage positions (open, close, update leverage and margin mode) - Manage sub-accounts and transfer funds between accounts (including spot↔perp) - Approve and route fees to integrators (frontends, bots, affiliate platforms) - Manage Unified Trading Account (UTA) and per-asset margin settings - Use public pools, staking, and RFQ where available on your account - Monitor transactions with built-in status tracking - Handle errors automatically with retry logic

See examples/ for a runnable script covering every feature above.

🎯 Getting Started

Step 1: Set Up Your Environment

Create a .env file in your project root:

# Required credentials
API_PRIVATE_KEY=your_private_key_here
ACCOUNT_INDEX=0
API_KEY_INDEX=0
BASE_URL=https://mainnet.zklighter.elliot.ai

# Optional: for specific examples
MARKET_ID=0
SUB_ACCOUNT_INDEX=1
DEPOSIT_AMOUNT=1

Step 2: Install the SDK

npm install lighter-ts-sdk

Step 3: Your First Trade

import { SignerClient, OrderType } from 'lighter-ts-sdk';
import dotenv from 'dotenv';

dotenv.config();

async function placeOrder() {
  // Initialize the client
  const signerClient = new SignerClient({
    url: process.env.BASE_URL!,
    privateKey: process.env.API_PRIVATE_KEY!,
    accountIndex: parseInt(process.env.ACCOUNT_INDEX!),
    apiKeyIndex: parseInt(process.env.API_KEY_INDEX!)
  });

  // Initialize WASM signer (required)
  await signerClient.initialize();
  await signerClient.ensureWasmClient();

  // Create a market order with SL/TP using OTOCO
  const result = await signerClient.createOtocoOrder({
    mainOrder: {
      marketIndex: 0,              // ETH market
      clientOrderIndex: Date.now(), // Unique ID
      baseAmount: 10000,           // 0.01 ETH (scaled: 1 ETH = 1,000,000)
      isAsk: false,                // BUY (true = SELL)
      orderType: OrderType.MARKET,

      // Slippage protection
      idealPrice: 400000,           // Ideal price ($4000)
      maxSlippage: 0.001           // Max 0.1% slippage
    },
    // Automatic stop-loss
    stopLoss: {
      triggerPrice: 380000,       // Stop loss at $3800
      isLimit: false              // Market SL
    },
    // Automatic take-profit
    takeProfit: {
      triggerPrice: 420000,       // Take profit at $4200
      isLimit: false              // Market TP
    }
  });

  // Check if order succeeded
  if (result.error || !result.hash) {
    console.error('❌ Order failed:', result.error);
    return;
  }

  console.log('✅ OTOCO order created!');
  console.log('Grouped order hash:', result.hash);

  // Wait for transaction confirmation
  await signerClient.waitForTransaction(result.hash, 30000);

  await signerClient.close();
}

placeOrder().catch(console.error);

📚 Core Concepts

Understanding Price Units

Lighter uses fixed decimal scaling: - ETH amounts: 1 ETH = 1,000,000 units - Prices: $1 = 100 units

// To buy 0.01 ETH at $4000:
baseAmount: 10000        // 0.01 ETH (10,000 / 1,000,000)
price: 400000           // $4000 (400,000 / 100)

Order Types

OrderType.MARKET    // Executes immediately at market price
OrderType.LIMIT     // Executes at your specified price
OrderType.TWAP      // Executes gradually over time

Direction (isAsk)

isAsk: false  // BUY - You're buying ETH
isAsk: true   // SELL - You're selling ETH

Stop-Loss and Take-Profit

SL/TP orders are automatically reduce-only - they only close positions:

stopLoss: {
  triggerPrice: 380000,  // When price hits this, close position
  isLimit: false         // false = market SL, true = limit SL
},
takeProfit: {
  triggerPrice: 420000,  // When price hits this, take profit
  isLimit: false         // false = market TP, true = limit TP
}

Important: SL/TP orders require an existing position. For Market orders, this works immediately. For Limit orders, SL/TP are created in the same batch.

Note for TWAP orders: TWAP orders execute over time, creating positions gradually. SL/TP cannot be created in the same batch as TWAP orders. You should create SL/TP orders separately after the TWAP has started creating positions.

🌐 Network-Aware Transaction Status Monitoring

Lighter Protocol transactions go through multiple network states. Use waitForTransaction() to monitor status changes with automatic error handling and recovery:

// Transaction status constants
enum TransactionStatus {
  PENDING = 0,        // Initial state, not yet queued
  QUEUED = 1,         // Queued for processing
  COMMITTED = 2,      // Committed to block
  EXECUTED = 3,       // Successfully executed
  FAILED = 4,         // Execution failed
  REJECTED = 5        // Transaction rejected
}

// Monitor transaction with built-in retry logic
try {
  const txResult = await signerClient.waitForTransaction(
    txHash,
    30000,  // maxWaitTime: wait up to 30 seconds
    2000    // pollInterval: check status every 2 seconds
  );

  console.log('Status:', txResult.status);  // Will be EXECUTED (3) if successful
  console.log('✅ Transaction confirmed on-chain');
} catch (error) {
  // Error handling is centralized here
  if (error.message.includes('timeout')) {
    console.error('❌ Transaction didn\'t confirm within timeout');
  } else if (error.message.includes('FAILED') || error.message.includes('REJECTED')) {
    console.error('❌ Transaction failed:', error.message);
  } else {
    console.error('❌ Unexpected error:', error.message);
  }
}

// Advanced: Manual status polling for fine-grained control
const checkStatus = async (hash: string) => {
  const txResult = await signerClient.getTransaction(hash);

  switch (txResult.status) {
    case SignerClient.TX_STATUS_PENDING:
      console.log('⏳ Still pending...');
      break;
    case SignerClient.TX_STATUS_QUEUED:
      console.log('📋 Queued for processing');
      break;
    case SignerClient.TX_STATUS_COMMITTED:
      console.log('✍️ Committed to block');
      break;
    case SignerClient.TX_STATUS_EXECUTED:
      console.log('✅ Transaction executed successfully');
      break;
    case SignerClient.TX_STATUS_FAILED:
      console.error('❌ Transaction execution failed');
      break;
    case SignerClient.TX_STATUS_REJECTED:
      console.error('❌ Transaction was rejected');
      break;
  }

  return txResult;
};

// Pattern: Fire-and-forget with error handling
const result = await signerClient.createOrder(orderParams);
if (result.hash) {
  // Schedule async confirmation check (don't block)
  signerClient.waitForTransaction(result.hash, 60000).catch(err => {
    console.error('Transaction confirmation failed:', err);
    // Handle error (alert user, retry, etc.)
  });
}

Key Points: - waitForTransaction() centralizes error handling and automatic retries - No need to parse transaction status manually after wait - Throw errors are detected and propagated with context - Use timeout to prevent indefinite waits in production systems

💰 Margin Management with Direction Constants

Lighter Protocol supports both cross-margin and isolated-margin modes. Margin direction constants determine whether you're adding or removing collateral:

Margin Mode Constants

// Margin mode
SignerClient.CROSS_MARGIN_MODE = 0      // Shared collateral across markets
SignerClient.ISOLATED_MARGIN_MODE = 1   // Per-market collateral

// Margin direction (when updating isolated margin)
SignerClient.ISOLATED_MARGIN_REMOVE_COLLATERAL = 0  // Remove collateral from position
SignerClient.ISOLATED_MARGIN_ADD_COLLATERAL = 1     // Add collateral to position

Adding Margin (Collateral) to Isolated Position

// Add 100 USDC collateral to ETH position in isolated mode
const [marginInfo, txHash, error] = await signerClient.updateMargin(
  0,      // marketIndex: 0 = ETH/USDC
  100,    // usdcAmount: 100 USDC to add
  SignerClient.ISOLATED_MARGIN_ADD_COLLATERAL  // direction: 1
);

if (error) {
  console.error('Failed to add margin:', error);
} else {
  console.log('✅ Margin added:', txHash);

  // Wait for confirmation
  await signerClient.waitForTransaction(txHash, 30000);
  console.log('✅ Margin update confirmed');
}

Removing Margin (Collateral) from Isolated Position

// Remove 50 USDC collateral from ETH position
const [marginInfo, txHash, error] = await signerClient.updateMargin(
  0,      // marketIndex: 0 = ETH/USDC
  50,     // usdcAmount: 50 USDC to remove
  SignerClient.ISOLATED_MARGIN_REMOVE_COLLATERAL  // direction: 0
);

if (error) {
  console.error('Failed to remove margin:', error);
} else {
  console.log('✅ Margin removed:', txHash);

  // Wait for confirmation
  await signerClient.waitForTransaction(txHash, 30000);
  console.log('✅ Margin removal confirmed');
}

Cross-Margin vs Isolated-Margin Workflows

// === CROSS-MARGIN MODE ===
// Step 1: Update leverage to cross-margin
const [crossInfo1, crossHash1, crossErr1] = await signerClient.updateLeverage(
  0,  // marketIndex
  SignerClient.CROSS_MARGIN_MODE,  // mode: 0
  5   // leverage: 5x
);

// Step 2: Create order (no margin updates needed - uses account balance)
const result = await signerClient.createMarketOrder({
  marketIndex: 0,
  baseAmount: 10000,
  isAsk: false
});

// === ISOLATED-MARGIN MODE ===
// Step 1: Update leverage to isolated-margin
const [isolatedInfo1, isolatedHash1, isolatedErr1] = await signerClient.updateLeverage(
  0,  // marketIndex
  SignerClient.ISOLATED_MARGIN_MODE,  // mode: 1
  20  // leverage: 20x (IMF = 10000/20 = 500)
);

// Step 2: Create order
const result = await signerClient.createMarketOrder({
  marketIndex: 0,
  baseAmount: 10000,
  isAsk: false
});

// Step 3: Manage collateral dynamically
// Add more collateral if position grows risky
await signerClient.updateMargin(
  0,
  200,  // Add 200 USDC
  SignerClient.ISOLATED_MARGIN_ADD_COLLATERAL
);

// Remove collateral if position has buffer
await signerClient.updateMargin(
  0,
  100,  // Remove 100 USDC
  SignerClient.ISOLATED_MARGIN_REMOVE_COLLATERAL
);

Important: - Cross-margin pools collateral across all markets - Isolated margin requires explicit collateral management per-market - direction parameter is only used for isolated-margin positions - Always verify sufficient collateral before removing it

🔧 Common Operations

Create a Market Order

const [tx, hash, error] = await signerClient.createMarketOrder({
  marketIndex: 0,
  clientOrderIndex: Date.now(),
  baseAmount: 10000,        // Amount (0.01 ETH)
  avgExecutionPrice: 400000, // Max execution price ($4000)
  isAsk: false              // BUY
});

if (error || !hash) {
  console.error('Failed:', error);
  return;
}

Create a Limit Order

const [tx, hash, error] = await signerClient.createOrder({
  marketIndex: 0,
  clientOrderIndex: Date.now(),
  baseAmount: 10000,        // Amount (0.01 ETH)
  price: 400000,            // Limit price ($4000)
  isAsk: false,             // BUY
  orderType: OrderType.LIMIT,
  orderExpiry: Date.now() + (60 * 60 * 1000) // Expires in 1 hour
});

if (error || !hash) {
  console.error('Failed:', error);
  return;
}

// Wait for it to fill
await signerClient.waitForTransaction(hash);

Cancel an Order

const [tx, hash, error] = await signerClient.cancelOrder({
  marketIndex: 0,
  orderIndex: 12345  // Your order's index
});

if (error) {
  console.error('Cancel failed:', error);
  return;
}

await signerClient.waitForTransaction(hash);
console.log('✅ Order cancelled');

Close a Position

const [tx, hash, error] = await signerClient.createMarketOrder({
  marketIndex: 0,
  clientOrderIndex: Date.now(),
  baseAmount: 10000,        // Position size to close
  avgExecutionPrice: 400000,
  isAsk: false,              // Opposite of position
  reduceOnly: true          // IMPORTANT: Only closes, doesn't open new
});

if (error) {
  console.error('Close failed:', error);
  return;
}

await signerClient.waitForTransaction(hash);
console.log('✅ Position closed');

Check Order Status

const status = await signerClient.getTransaction(txHash);
console.log('Status:', status.status); // 0=pending, 1=queued, 2=committed, 3=executed

🛠️ API Reference

SignerClient Methods

Order Management

```t

Extension points exported contracts — how you extend this code

EventListener (Interface)
(no doc)
src/ws.d.ts
Configuration (Interface)
(no doc)
src/types/config.ts
MarketConfig (Interface)
(no doc)
src/utils/price-utils.ts
WasmSignerConfig (Interface)
(no doc)
src/signer/wasm-signer.ts
BlockQuery (Interface)
(no doc)
src/api/block-api.ts
OrderResult (Interface)
(no doc)
examples/spot/create_market_spot_orders.ts
Event (Interface)
(no doc)
src/ws.d.ts
ApiResponse (Interface)
(no doc)
src/types/config.ts

Core symbols most depended-on inside this repo

log
called by 911
src/utils/logger.ts
error
called by 246
src/utils/logger.ts
ensureWasmClient
called by 65
src/signer/wasm-signer-client.ts
initialize
called by 64
src/signer/wasm-signer-client.ts
close
called by 60
src/signer/wasm-signer-client.ts
close
called by 42
src/api/api-client.ts
waitForTransaction
called by 38
src/signer/wasm-signer-client.ts
priceToUnits
called by 34
src/utils/market-helper.ts

Shape

Method 434
Function 190
Interface 181
Class 94
Enum 11

Languages

TypeScript100%

Modules by API surface

src/signer/wasm-signer-client.ts87 symbols
src/signer/wasm-signer.ts83 symbols
src/api/account-api.ts59 symbols
wasm/wasm_exec.js51 symbols
src/utils/exceptions.ts45 symbols
src/api/order-api.ts41 symbols
src/api/transaction-api.ts32 symbols
src/api/ws-order-client.ts27 symbols
src/api/bridge-api.ts25 symbols
src/api/search-api.ts21 symbols
src/utils/price-utils.ts20 symbols
src/utils/logger.ts19 symbols

For agents

$ claude mcp add lighter-ts \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page