npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lynx-graph-sdk

v0.0.7

Published

TypeScript SDK for querying Lynx Protocol subgraphs

Downloads

223

Readme

Lynx Graph SDK

A TypeScript SDK for querying Lynx Protocol subgraphs across multiple chains. This SDK provides type-safe queries, helper functions, and utilities for both frontend and backend applications.

🚀 Latest Release (v0.0.4)

New Features

  • 🛡️ Advanced Error Handling: Custom error classes with retry logic and recovery suggestions
  • ✅ Input Validation: Comprehensive validation for all inputs with helpful error messages
  • 🚦 Rate Limiting: Built-in rate limiting with request queuing and priority support
  • 📊 Enhanced Analytics: Improved metrics calculation using actual subgraph data
  • 🔄 Multi-Network Support: Seamless switching between Sonic, Boba, and Flare networks

Installation

npm install lynx-graph-sdk

# or with yarn
yarn add lynx-graph-sdk@beta

# or with pnpm
pnpm add lynx-graph-sdk@beta

Requirements

  • Node.js >= 18.0.0
  • TypeScript >= 5.3.0 (for TypeScript projects)
  • ethers ^5.7.2 (included as dependency)

Quick Start

import { 
  LynxGraphClient, 
  Network, 
  PositionPhase,
  ValidationError,
  RateLimitError 
} from 'lynx-graph-sdk';

// Initialize client with your subgraph endpoints
const client = new LynxGraphClient({
  endpoints: [
    {
      url: 'https://api.studio.thegraph.com/query/YOUR_ID/lynx-sonic/version/latest',
      network: Network.SONIC,
      chainId: 146,
      name: 'Sonic'
    },
    // Add other networks as needed
  ],
  defaultNetwork: Network.SONIC,
  cacheEnabled: true,
  cacheTTL: 60, // 1 minute
  maxRetries: 3,
  retryDelay: 1000,
});

// Query with automatic validation and error handling
try {
  const positions = await client.getPositions({
    trader: '0x123...', // Automatically validated
    currentPhase: PositionPhase.OPENED,
    first: 10,
  });
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Invalid input:', error.suggestion);
  } else if (error instanceof RateLimitError) {
    console.error('Rate limited, retry after:', error.retryAfter);
  }
}

// Get pool statistics with enhanced metrics
const poolHelpers = new PoolHelpers(client);
const tvl = await poolHelpers.getPoolTVL('sonic-usdc');
console.log('TVL:', tvl.tvl);
console.log('Pending Deposits:', tvl.pendingDeposits);

Configuration

Required: Subgraph Endpoints

You must provide your own subgraph endpoints when initializing the client. The SDK does not include default endpoints.

const endpoints = [
  {
    url: 'https://your-sonic-subgraph-url',
    network: Network.SONIC,
    chainId: 146,
    name: 'Sonic'
  },
  {
    url: 'https://your-boba-subgraph-url',
    network: Network.BOBA,
    chainId: 288,
    name: 'Boba'
  },
  {
    url: 'https://your-flare-subgraph-url',
    network: Network.FLARE,
    chainId: 14,
    name: 'Flare'
  }
];

const client = new LynxGraphClient({ endpoints });

Features

🛡️ Enterprise-Grade Error Handling

import { LynxSDKError, NetworkError, DefaultErrorHandler } from 'lynx-graph-sdk';

// Custom error handler with retry logic
const errorHandler = new DefaultErrorHandler(
  3, // max retries
  1000, // base delay
  30000 // max delay
);

// Automatic retry for transient errors
if (error instanceof NetworkError && errorHandler.shouldRetry(error)) {
  const delay = errorHandler.getRetryDelay(error, attemptNumber);
  await new Promise(resolve => setTimeout(resolve, delay));
  // Retry the operation
}

✅ Comprehensive Input Validation

import { validateAddress, validateBigNumber, ValidationChain } from 'lynx-graph-sdk';

// Individual validators
const address = validateAddress('0x742d...', 'trader');
const amount = validateBigNumber('1000000', 'collateral', {
  min: '100000',
  max: '10000000000',
  allowZero: false
});

// Batch validation
const chain = new ValidationChain();
chain
  .check(() => validateAddress(userAddress))
  .check(() => validateLeverage(leverage))
  .check(() => validateTimestamp(timestamp));
  
if (!chain.isValid()) {
  console.error('Validation errors:', chain.getErrors());
}

🚦 Advanced Rate Limiting

import { RateLimiter, MultiNetworkRateLimiter } from 'lynx-graph-sdk';

// Per-network rate limiting
const networkLimiter = new MultiNetworkRateLimiter({
  SONIC: { capacity: 10, refillRate: 2 },
  BOBA: { capacity: 5, refillRate: 1 },
  FLARE: { capacity: 8, refillRate: 1.5 }
});

// Execute with automatic queuing
await networkLimiter.execute(
  'SONIC',
  async () => client.getPositions(filter),
  { priority: 10 } // High priority request
);

🔍 Type-Safe Queries

All queries are fully typed with TypeScript, providing autocomplete and type checking.

🌐 Multi-Chain Support

Built-in support for:

  • Sonic (Fantom)
  • Boba Network
  • Flare Network

🚀 Performance

  • Built-in caching with TTL
  • Automatic retries with exponential backoff
  • Request batching and deduplication
  • Optimized GraphQL queries
  • Rate limiting to prevent 429 errors

🛠 Helper Functions

Pre-built helpers for common use cases:

  • Position analysis with P&L tracking
  • Pool metrics and TVL calculations
  • Analytics and trend analysis
  • Trader statistics and leaderboards
  • Risk assessment tools

Core Concepts

Client Configuration

const client = new LynxGraphClient({
  // Custom endpoints (optional)
  endpoints: [
    {
      url: 'https://your-subgraph-url',
      network: Network.SONIC,
      chainId: 146,
      name: 'Sonic',
    },
  ],
  
  // Default network
  defaultNetwork: Network.SONIC,
  
  // Retry configuration
  maxRetries: 3,
  retryDelay: 1000,
  
  // Request timeout
  timeout: 30000,
  
  // Cache configuration
  cacheEnabled: true,
  cacheTTL: 60, // seconds
});

Network Switching

// Switch network
client.setNetwork(Network.BOBA);

// Get current network
const currentNetwork = client.getNetwork();

// Get available networks
const networks = client.getAvailableNetworks();

Query Examples

Position Queries

import { PositionPhase, Direction, Trigger } from 'lynx-graph-sdk';

// Get all positions with filters
const positions = await client.getPositions({
  trader: '0x123...',
  pool: 'sonic-usdc',
  direction: Direction.LONG,
  currentPhase: PositionPhase.OPENED,
  leverage_gte: '200', // 2x leverage
  openTimestamp_gte: Math.floor(Date.now() / 1000) - 86400, // Last 24h
  orderBy: PositionOrderBy.openTimestamp,
  orderDirection: OrderBy.DESC,
  first: 50,
});

// Get specific position
const position = await client.getPositionById('position-id');

// Get active positions for a trader
const activePositions = await client.getActivePositions(
  '0x123...', // trader
  'sonic-usdc', // pool (optional)
  { first: 100 }
);

Pool Queries

// Get all pools
const pools = await client.getPools({
  sourceChainId: 146, // Sonic
  orderBy: PoolOrderBy.name,
});

// Get pool details
const pool = await client.getPoolById('sonic-usdc');

// Get pool epochs
const epochs = await client.getPoolEpochs('sonic-usdc', {
  epochNumber_gte: 100,
  first: 10,
});

// Get liquidity providers
const providers = await client.getProviders({
  pool: 'sonic-usdc',
  amountSupplying_gte: '1000000000000000000000', // 1000 tokens
  orderBy: ProviderOrderBy.amountSupplying,
  orderDirection: OrderBy.DESC,
});

Analytics Queries

// Get daily analytics
const dailyData = await client.getDailyAnalytics({
  pool: 'sonic-usdc',
  timestamp_gte: Math.floor(Date.now() / 1000) - (30 * 86400), // Last 30 days
  orderBy: TimeBucketOrderBy.timestamp,
  orderDirection: OrderBy.ASC,
});

// Get hourly analytics
const hourlyData = await client.getHourlyAnalytics({
  pool: 'sonic-usdc',
  timestamp_gte: Math.floor(Date.now() / 1000) - 86400, // Last 24h
});

// Get global statistics
const globalStats = await client.getGlobalStats('sonic-usdc');

Helper Classes

PositionHelpers

import { PositionHelpers } from 'lynx-graph-sdk';

const positionHelpers = new PositionHelpers(client);

// Get trader's open positions
const openPositions = await positionHelpers.getTraderOpenPositions('0x123...');

// Get P&L history
const pnlHistory = await positionHelpers.getTraderPnLHistory(
  '0x123...',
  new Date('2024-01-01'),
  new Date()
);
console.log(`Total P&L: ${pnlHistory.totalPnL}`);
console.log(`Win Rate: ${pnlHistory.winRate}%`);

// Get positions at risk of liquidation
const riskyPositions = await positionHelpers.getPositionsAtRisk(
  'sonic-usdc',
  0.2 // 20% from liquidation
);

// Calculate aggregate statistics
const stats = positionHelpers.calculateStats(positions);
console.log(`Total Volume: ${stats.totalVolume}`);
console.log(`Average Leverage: ${stats.avgLeverage}x`);

PoolHelpers

import { PoolHelpers } from 'lynx-graph-sdk';

const poolHelpers = new PoolHelpers(client);

// Get TVL
const tvl = await poolHelpers.getPoolTVL('sonic-usdc');
console.log(`TVL: $${tvl.tvl}`);
console.log(`Net TVL: $${tvl.netTVL}`);

// Get utilization
const utilization = await poolHelpers.getPoolUtilization('sonic-usdc');
console.log(`Utilization Rate: ${utilization.utilizationRate}%`);
console.log(`Available Liquidity: $${utilization.availableLiquidity}`);

// Get pool performance
const performance = await poolHelpers.getPoolPerformance('sonic-usdc', 30);
console.log(`APY: ${performance.apy}%`);
console.log(`Daily Volume: $${performance.avgDailyVolume}`);

// Get top providers
const topProviders = await poolHelpers.getTopProviders('sonic-usdc', 10);
topProviders.forEach(({ provider, sharePercent }) => {
  console.log(`${provider.address}: ${sharePercent}%`);
});

// Check pool health
const health = await poolHelpers.getPoolHealth('sonic-usdc');
if (!health.isHealthy) {
  console.log('Warnings:', health.warnings.join(', '));
}

AnalyticsHelpers

import { AnalyticsHelpers } from 'lynx-graph-sdk';

const analyticsHelpers = new AnalyticsHelpers(client);

// Get protocol-wide stats
const protocolStats = await analyticsHelpers.getProtocolStats();
console.log(`Total Volume: $${protocolStats.totalVolume}`);
console.log(`Total Positions: ${protocolStats.totalPositions}`);

// Get volume trends
const volumeTrends = await analyticsHelpers.getVolumeTrends(
  'sonic-usdc',
  30,
  'day'
);

// Get fee breakdown
const feeTrends = await analyticsHelpers.getFeeTrends('sonic-usdc', 30);

// Get open interest trends
const oiTrends = await analyticsHelpers.getOpenInterestTrends(
  'sonic-usdc',
  30,
  'hour'
);

// Compare pools
const comparison = await analyticsHelpers.comparePoolsPerformance(
  ['sonic-usdc', 'sonic-eth'],
  30
);

Utility Functions

Formatting

import { 
  formatBigNumber, 
  formatPrice, 
  formatLeverage,
  formatPercentage,
  formatTimestamp,
  calculatePnlPercentage 
} from 'lynx-graph-sdk';

// Format amounts with decimals
const formatted = formatBigNumber('1000000000000000000', 18); // "1.0"

// Format prices (8 decimals)
const price = formatPrice('10000000000'); // "100.00"

// Format leverage
const leverage = formatLeverage('200'); // "2.00"

// Calculate P&L percentage
const pnlPercent = calculatePnlPercentage(
  '50000000000000000000', // 50 profit
  '1000000000000000000000' // 1000 collateral
); // "5.00%"

Address Validation

import { isValidAddress, normalizeAddress } from 'lynx-graph-sdk';

if (isValidAddress(userInput)) {
  const normalized = normalizeAddress(userInput);
  // Use normalized address
}

Advanced Usage

Custom Queries

import { gql } from 'lynx-graph-sdk';

const CUSTOM_QUERY = gql`
  query GetCustomData($pool: String!) {
    lexPoolEntity(id: $pool) {
      id
      name
      positions(first: 10, orderBy: openTimestamp, orderDirection: desc) {
        id
        trader {
          id
        }
        extra_pnl
      }
    }
  }
`;

// Use raw GraphQL client
const graphClient = client.getGraphQLClient(Network.SONIC);
const data = await graphClient.request(CUSTOM_QUERY, { pool: 'sonic-usdc' });

Query Builder

The SDK includes a powerful QueryBuilder for creating dynamic GraphQL queries with conditional where clauses:

import { QueryBuilder } from 'lynx-graph-sdk';

// Build dynamic queries with conditional filters
const builder = new QueryBuilder('positions', 'GetPositions')
  .select('id', 'trader { id }', 'extra_pnl')
  .paginate(50, 0)
  .orderBy('openTimestamp', 'desc');

// Only add where conditions if values exist
if (traderId) builder.where('trader', traderId);
if (minLeverage) builder.where('leverage', minLeverage, 'gte');
if (poolId) builder.where('pool', poolId);

// Build the query - automatically handles null/undefined values
const { query, variables } = builder.buildConditional();

// The QueryBuilder solves The Graph's null value filter issues
// It only includes where clauses for defined values

Cache Management

// Clear all cache
client.clearCache();

// Clear specific cache key
client.clearCacheForKey('getPoolById:sonic-usdc');

// Disable cache for specific query
const client = new LynxGraphClient({
  cacheEnabled: false, // Disable globally
});

Error Handling

The SDK provides comprehensive error handling with specific error types and recovery suggestions:

import { 
  LynxSDKError,
  NetworkError,
  ValidationError,
  QueryError,
  TimeoutError,
  RateLimitError,
  DataIntegrityError,
  ConfigurationError,
  SubgraphSyncError,
  isLynxSDKError,
  getErrorType
} from 'lynx-graph-sdk';

try {
  const positions = await client.getPositions({ 
    trader: '0xinvalid' 
  });
} catch (error) {
  if (isLynxSDKError(error)) {
    console.error(`Error [${error.code}]: ${error.message}`);
    console.log('Suggestion:', error.suggestion);
    console.log('Context:', error.context);
    
    // Handle specific error types
    switch (error.code) {
      case 'VALIDATION_ERROR':
        // Show validation message to user
        break;
      case 'RATE_LIMIT_ERROR':
        // Wait and retry
        const rateLimitError = error as RateLimitError;
        await new Promise(r => setTimeout(r, rateLimitError.retryAfter * 1000));
        break;
      case 'NETWORK_ERROR':
      case 'TIMEOUT_ERROR':
        // Retry with backoff
        break;
      case 'SUBGRAPH_SYNC_ERROR':
        // Use historical data or wait for sync
        const syncError = error as SubgraphSyncError;
        console.log(`Subgraph is ${syncError.chainBlock - syncError.syncedBlock} blocks behind`);
        break;
    }
  }
}

Error Recovery

The SDK includes automatic retry logic for transient errors:

import { DefaultErrorHandler } from 'lynx-graph-sdk';

const errorHandler = new DefaultErrorHandler();

async function queryWithRetry<T>(
  operation: () => Promise<T>,
  maxAttempts = 3
): Promise<T> {
  let lastError: LynxSDKError;
  
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await operation();
    } catch (error) {
      if (!isLynxSDKError(error) || !errorHandler.shouldRetry(error)) {
        throw error;
      }
      
      lastError = error;
      if (attempt < maxAttempts) {
        const delay = errorHandler.getRetryDelay(error, attempt);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }
  
  throw lastError!;
}

Integration Examples

React Hook

import { useState, useEffect } from 'react';
import { LynxGraphClient, Position, Network } from 'lynx-graph-sdk';

function useTraderPositions(trader: string, network: Network) {
  const [positions, setPositions] = useState<Position[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const client = new LynxGraphClient({ defaultNetwork: network });
    
    async function fetchPositions() {
      try {
        setLoading(true);
        const data = await client.getTraderPositions(trader);
        setPositions(data);
      } catch (err) {
        setError(err as Error);
      } finally {
        setLoading(false);
      }
    }

    fetchPositions();
  }, [trader, network]);

  return { positions, loading, error };
}

Node.js Backend

import express from 'express';
import { LynxGraphClient, PoolHelpers, Network } from 'lynx-graph-sdk';

const app = express();
const client = new LynxGraphClient({
  defaultNetwork: Network.SONIC,
  cacheEnabled: true,
  cacheTTL: 300, // 5 minutes
});

const poolHelpers = new PoolHelpers(client);

app.get('/api/pools/:poolId/tvl', async (req, res) => {
  try {
    const tvl = await poolHelpers.getPoolTVL(req.params.poolId);
    res.json(tvl);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/api/pools/:poolId/health', async (req, res) => {
  try {
    const health = await poolHelpers.getPoolHealth(req.params.poolId);
    res.json(health);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

Type Definitions

The SDK exports all types from the GraphQL schema:

import {
  // Entities
  Position,
  Trader,
  LexPoolEntity,
  Epoch,
  Provider,
  TimeBucketDayData,
  TimeBucketHourData,
  LexGlobalTracker,
  
  // Enums
  PositionPhase,
  Direction,
  Trigger,
  OpenOrderType,
  PairGroupName,
  SupplyRequestState,
  
  // Filters
  PositionFilter,
  PoolFilter,
  EpochFilter,
  
  // Config
  Network,
  SDKConfig,
} from 'lynx-graph-sdk';

Troubleshooting

Common Issues

Rate Limiting

If you're hitting rate limits frequently:

// Increase rate limit configuration
const client = new LynxGraphClient({
  maxRetries: 5,
  retryDelay: 2000,
});

// Or use custom rate limiter
const rateLimiter = new RateLimiter({
  defaultCapacity: 20,
  defaultRefillRate: 2,
  maxQueueSize: 100,
});

Validation Errors

For address validation issues:

// Ensure addresses are properly formatted
const address = '0x' + userInput.toLowerCase().replace(/^0x/, '');
const validatedAddress = validateAddress(address);

Network Switching

// Check available networks before switching
const networks = client.getAvailableNetworks();
if (networks.includes(Network.BOBA)) {
  client.setNetwork(Network.BOBA);
}

Migration Guide

From Direct GraphQL Queries

Before:

const query = gql`
  query GetPositions($trader: String!) {
    positions(where: { trader: $trader }) {
      id
      leverage
    }
  }
`;
const result = await graphClient.request(query, { trader });

After:

const positions = await client.getPositions({ 
  trader,
  first: 100 
});

From v0.0.0 to v0.0.1-beta

  1. Update imports:
// Old
import { LynxGraphClient } from 'lynx-graph-sdk';

// New - import error types
import { 
  LynxGraphClient,
  ValidationError,
  RateLimitError 
} from 'lynx-graph-sdk';
  1. Add error handling:
// Wrap queries in try-catch
try {
  const result = await client.getPositions(filter);
} catch (error) {
  // Handle specific error types
}
  1. Update pool helper usage:
// TVL response structure changed
const tvl = await poolHelpers.getPoolTVL(poolId);
// Now includes: tvl, pendingDeposits, pendingRedeems, netTVL

📚 Documentation

Additional Documentation

For more detailed documentation and guides, check out the docs/ directory:

  • SDK Integration Guide - Complete guide for integrating the Lynx Graph SDK into your application
  • SDK Architecture - Detailed documentation of the SDK's internal architecture and design patterns

API Documentation

Full API documentation with all available methods, types, and examples is available in the integration guide. Key sections include:

  • Client initialization and configuration
  • Query methods and filters
  • Helper functions for analytics and calculations
  • Error handling and retry strategies
  • Rate limiting and performance optimization
  • Multi-network support

Contributing

  1. Clone the repository
  2. Install dependencies: npm install
  3. Build the SDK: npm run build
  4. Run tests: npm test
  5. Run linter: npm run lint

Development

# Run tests in watch mode
npm run test:watch

# Check types
npm run typecheck

# Generate GraphQL types
npm run generate

# Run with debug logging
DEBUG=lynx-graph-sdk* npm test

Changelog

v0.0.4 (2024-12-28)

  • Critical Fix: getActivePositions now properly returns active positions
  • Moved test scripts to sdk/scripts/ directory
  • Added npm test commands for validation

v0.0.3 (2024-12-28)

  • Initial fix attempt for getActivePositions (incomplete)
  • Added comprehensive validation script
  • Stable release from beta

v0.0.1-beta.2 (2024-08-17)

  • Enhanced type safety and query optimizations

v0.0.1-beta.1 (2024-08-16)

  • 🛡️ Added comprehensive error handling system
  • ✅ Implemented input validation for all parameters
  • 🚦 Added rate limiting with request queuing
  • 📊 Updated helpers to use actual subgraph schema
  • 🔧 Fixed TypeScript compilation issues
  • 🔍 Added QueryBuilder for dynamic GraphQL queries
  • 🐛 Fixed negative number formatting in BigNumber utilities
  • 📚 Enhanced documentation and examples

Support

License

MIT © Lynx Protocol