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

@pear-protocol/hyperliquid-sdk

v0.1.20

Published

React SDK for Pear Protocol Hyperliquid API integration

Downloads

2,684

Readme

@pear-protocol/hyperliquid-sdk

A comprehensive React SDK for integrating with Pear Protocol's Hyperliquid trading platform. Build perpetual trading interfaces with real-time WebSocket data, position management, and market analytics.

Table of Contents


Installation

npm install @pear-protocol/hyperliquid-sdk
# or
yarn add @pear-protocol/hyperliquid-sdk
# or
pnpm add @pear-protocol/hyperliquid-sdk

Peer Dependencies

Ensure you have React 18+ installed:

npm install react react-dom

Quick Start

import {
  PearHyperliquidProvider,
  useAuth,
  usePosition,
  useMarket,
} from '@pear-protocol/hyperliquid-sdk';

function App() {
  return (
    <PearHyperliquidProvider
      apiBaseUrl="https://hl-ui.pearprotocol.io"
      wsUrl="wss://hl-ui.pearprotocol.io/ws"
      clientId="YOUR_CLIENT_ID"
    >
      <TradingApp />
    </PearHyperliquidProvider>
  );
}

function TradingApp() {
  const { isAuthenticated, loginWithSignedMessage } = useAuth();
  const { openPositions, createPosition } = usePosition();
  const { allTokenMetadata } = useMarket();

  if (!isAuthenticated) {
    return <button onClick={() => loginWithSignedMessage(address, signMessage)}>Connect</button>;
  }

  return (
    <div>
      <h2>Open Positions: {openPositions?.length ?? 0}</h2>
      {/* Your trading UI */}
    </div>
  );
}

Provider Setup

Wrap your application with PearHyperliquidProvider to enable SDK functionality:

import { PearHyperliquidProvider } from '@pear-protocol/hyperliquid-sdk';

function App() {
  return (
    <PearHyperliquidProvider
      apiBaseUrl="https://hl-ui.pearprotocol.io"  // Pear API endpoint
      wsUrl="wss://hl-ui.pearprotocol.io/ws"      // WebSocket endpoint
      clientId="YOUR_CLIENT_ID"                    // Your application ID
    >
      {children}
    </PearHyperliquidProvider>
  );
}

Provider Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | apiBaseUrl | string | 'https://hl-ui.pearprotocol.io' | Pear Protocol API base URL | | wsUrl | string | 'wss://hl-ui.pearprotocol.io/ws' | WebSocket server URL | | clientId | string | 'PEARPROTOCOLUI' | Application client identifier |

Accessing Provider Context

import { usePearHyperliquid } from '@pear-protocol/hyperliquid-sdk';

function Component() {
  const {
    clientId,
    apiBaseUrl,
    wsUrl,
    isConnected,        // Pear WebSocket connection status
    lastError,          // Pear WebSocket last error
    nativeIsConnected,  // Hyperliquid WebSocket connection status
    nativeLastError,    // Hyperliquid WebSocket last error
  } = usePearHyperliquid();
}

Authentication

The SDK provides EIP-712 signature-based authentication:

import { useAuth } from '@pear-protocol/hyperliquid-sdk';

function AuthComponent() {
  const {
    isAuthenticated,
    isLoading,
    address,
    loginWithSignedMessage,
    loginWithPrivy,
    logout,
  } = useAuth();

  const handleLogin = async () => {
    // Using wallet signature (e.g., with wagmi/viem)
    await loginWithSignedMessage(
      walletAddress,
      async (message) => {
        // Your wallet's signMessage function
        return await signMessage({ message });
      }
    );
  };

  const handlePrivyLogin = async () => {
    // Using Privy authentication
    await loginWithPrivy(walletAddress, privyAccessToken);
  };
}

Authentication Flow

  1. SDK requests an EIP-712 message from the server
  2. User signs the message with their wallet
  3. Signature is sent to authenticate
  4. JWT tokens are stored and managed automatically

Hooks Reference

Trading Hooks

usePosition()

Manage positions with full CRUD operations:

import { usePosition } from '@pear-protocol/hyperliquid-sdk';

function PositionManager() {
  const {
    openPositions,      // OpenPositionDto[] - enriched position data
    isLoading,
    createPosition,     // Create new position
    closePosition,      // Close specific position
    closeAllPositions,  // Close all positions
    adjustPosition,     // Rebalance position weights
    updateRiskParameters, // Update TP/SL
    updateLeverage,     // Change leverage
  } = usePosition();

  const handleCreate = async () => {
    await createPosition({
      longAssets: [{ asset: 'BTC', weight: 50 }, { asset: 'ETH', weight: 50 }],
      shortAssets: [{ asset: 'SOL', weight: 100 }],
      usdValue: 1000,
      leverage: 5,
      slippage: 0.5,
      executionType: 'MARKET',
      takeProfit: { triggerType: 'WEIGHTED_RATIO', triggerValue: 1.1 },
      stopLoss: { triggerType: 'WEIGHTED_RATIO', triggerValue: 0.95 },
    });
  };
}

useTrading()

High-level trading operations with enriched trade history:

import { useTrading } from '@pear-protocol/hyperliquid-sdk';

function TradingComponent() {
  const {
    tradeHistories,     // Trade history with metadata
    createTrade,
    adjustTrade,
    closeTrade,
  } = useTrading();
}

useOrders()

Manage open and trigger orders:

import { useOrders } from '@pear-protocol/hyperliquid-sdk';

function OrdersComponent() {
  const {
    openOrders,         // OpenLimitOrderDto[]
    triggerOrders,      // Filtered trigger orders
    adjustOrder,
    cancelOrder,
  } = useOrders();
}

useSpotOrder()

Execute spot swaps:

import { useSpotOrder } from '@pear-protocol/hyperliquid-sdk';

function SpotSwap() {
  const { executeSpotOrder, isLoading } = useSpotOrder();

  const handleSwap = async () => {
    await executeSpotOrder({
      fromAsset: 'USDC',
      toAsset: 'USDH',
      amount: 100,
    });
  };
}

useTwap()

Monitor TWAP order execution:

import { useTwap } from '@pear-protocol/hyperliquid-sdk';

function TwapMonitor() {
  const { twapOrders, cancelTwapOrder } = useTwap();

  return twapOrders?.map(order => (
    <div key={order.orderId}>
      Status: {order.status}
      Progress: {order.filledUsdValue} / {order.totalUsdValue}
      Chunks: {order.chunks.length - order.remainingChunks} / {order.chunks.length}
    </div>
  ));
}

Data Hooks

useMarket()

Access token metadata:

import { useMarket } from '@pear-protocol/hyperliquid-sdk';

function MarketData() {
  const {
    allTokenMetadata,   // Record<string, TokenMetadata>
    getAssetByName,     // (symbol: string) => TokenMetadata | null
  } = useMarket();

  const btcData = getAssetByName('BTC');
  // { symbol: 'BTC', currentPrice: 50000, maxLeverage: 50, ... }
}

useMarketData()

Get market baskets and analytics:

import { useMarketData, type CollateralFilter } from '@pear-protocol/hyperliquid-sdk';

function MarketAnalytics() {
  const {
    activeBaskets,      // Active market baskets
    highlightedBaskets, // Featured baskets
    topGainers,         // Best performing
    topLosers,          // Worst performing
    watchlistBaskets,   // User's watchlist
    isLoading,
    collateralFilter,   // 'ALL' | 'USDC' | 'USDH'
    setCollateralFilter,
  } = useMarketData();
}

useAllUserBalances()

Aggregate user balances:

import { useAllUserBalances } from '@pear-protocol/hyperliquid-sdk';

function BalanceDisplay() {
  const {
    spotUsdcBalance,
    spotUsdhBalance,
    availableToTradeUsdc,
    availableToTradeUsdh,
    isLoading,
  } = useAllUserBalances();
}

useTokenSelectionMetadata()

Get computed metrics for selected tokens:

import { useTokenSelectionMetadata } from '@pear-protocol/hyperliquid-sdk';

function SelectionMetrics() {
  const {
    longTokensMetadata,   // Metadata for selected long tokens
    shortTokensMetadata,  // Metadata for selected short tokens
    weightedRatio,        // Current weighted price ratio
    weightedRatio24h,     // 24h weighted ratio change
    priceRatio,           // Simple price ratio
    openInterest,         // Combined OI
    volume,               // Combined volume
    maxLeverage,          // Maximum allowed leverage
    minMargin,            // Minimum margin required
    leverageMatched,      // If all tokens support same leverage
    isPriceDataReady,
  } = useTokenSelectionMetadata();
}

useHistoricalPriceData()

Fetch and cache historical prices:

import { useHistoricalPriceData } from '@pear-protocol/hyperliquid-sdk';

function ChartData() {
  const { fetchHistoricalData, getCachedData } = useHistoricalPriceData();

  useEffect(() => {
    fetchHistoricalData('BTC', startTime, endTime, '1h');
  }, []);

  const candles = getCachedData('BTC', startTime, endTime);
}

useBasketCandles()

Compose weighted candles from multiple assets:

import { useBasketCandles } from '@pear-protocol/hyperliquid-sdk';

function BasketChart() {
  const {
    basketCandles,      // Weighted OHLCV data
    isLoading,
    error,
  } = useBasketCandles({
    longAssets: [{ symbol: 'BTC', weight: 50 }, { symbol: 'ETH', weight: 50 }],
    shortAssets: [{ symbol: 'SOL', weight: 100 }],
    interval: '1h',
    leverage: 5,
  });
}

WebSocket Hooks

useHyperliquidWebSocket()

Access Pear API WebSocket (managed by provider):

import { useHyperliquidWebSocket } from '@pear-protocol/hyperliquid-sdk';

// Typically used internally by the provider
const { isConnected, lastError } = useHyperliquidWebSocket({
  wsUrl: 'wss://hl-ui.pearprotocol.io/ws',
  address: userAddress,
  enabled: true,
});

useHyperliquidNativeWebSocket()

Access Hyperliquid native WebSocket (managed by provider):

import { useHyperliquidNativeWebSocket } from '@pear-protocol/hyperliquid-sdk';

// Typically used internally by the provider
const { isConnected, lastError } = useHyperliquidNativeWebSocket({
  address: userAddress,
  tokens: ['BTC', 'ETH'],
  enabled: true,
});

UI State Hooks

useUserSelection()

Manage token selection state:

import { useUserSelection } from '@pear-protocol/hyperliquid-sdk';

function TokenSelector() {
  const {
    longTokens,           // TokenSelection[]
    shortTokens,          // TokenSelection[]
    addToken,             // (isLong: boolean) => boolean
    removeToken,          // (isLong: boolean, index: number) => void
    updateTokenWeight,    // (isLong: boolean, index: number, weight: number) => void
    handleTokenSelect,    // (symbol: string) => void
    setTokenSelections,   // (longs, shorts) => void
    resetToDefaults,      // Reset to default selection
    candleInterval,       // Current chart interval
    setCandleInterval,    // Set chart interval
    openTokenSelector,    // Token selector modal state
    setOpenTokenSelector,
    conflicts,            // Detected token conflicts
    openConflictModal,
  } = useUserSelection();

  const handleAddLong = () => {
    const success = addToken(true); // Returns false if MAX_ASSETS_PER_LEG reached
  };
}

useWatchlist()

Manage user watchlist:

import { useWatchlist } from '@pear-protocol/hyperliquid-sdk';

function Watchlist() {
  const { toggleWatchlist, isLoading } = useWatchlist();

  const handleToggle = async () => {
    await toggleWatchlist(
      [{ asset: 'BTC', weight: 50 }],
      [{ asset: 'ETH', weight: 50 }]
    );
  };
}

useNotifications()

Access user notifications:

import { useNotifications } from '@pear-protocol/hyperliquid-sdk';

function NotificationCenter() {
  const {
    notifications,      // NotificationDto[]
    markAsRead,
    isLoading,
  } = useNotifications();
}

useAccountSummary()

Get portfolio-level metrics:

import { useAccountSummary } from '@pear-protocol/hyperliquid-sdk';

function AccountOverview() {
  const { accountSummary } = useAccountSummary();

  return (
    <div>
      <p>Account Value: ${accountSummary?.totalAccountValue}</p>
      <p>Unrealized PnL: ${accountSummary?.totalUnrealizedPnl}</p>
      <p>Margin Used: ${accountSummary?.totalMarginUsed}</p>
    </div>
  );
}

Client Functions

The SDK exports client functions for direct API calls:

Position Operations

import {
  createPosition,
  closePosition,
  closeAllPositions,
  adjustPosition,
  updateRiskParameters,
  updateLeverage,
} from '@pear-protocol/hyperliquid-sdk';

// Create position
const result = await createPosition(apiBaseUrl, {
  longAssets: [{ asset: 'BTC', weight: 100 }],
  shortAssets: [{ asset: 'ETH', weight: 100 }],
  usdValue: 1000,
  leverage: 5,
  slippage: 0.5,
  executionType: 'MARKET',
});

// Close position
await closePosition(apiBaseUrl, positionId, { slippage: 0.5 });

// Update TP/SL
await updateRiskParameters(apiBaseUrl, positionId, {
  takeProfit: { triggerType: 'WEIGHTED_RATIO', triggerValue: 1.1 },
  stopLoss: { triggerType: 'WEIGHTED_RATIO', triggerValue: 0.95 },
});

Order Operations

import {
  adjustOrder,
  cancelOrder,
  cancelTwapOrder,
  executeSpotOrder,
} from '@pear-protocol/hyperliquid-sdk';

// Adjust limit order
await adjustOrder(apiBaseUrl, orderId, { limitRatio: 1.05 });

// Cancel order
await cancelOrder(apiBaseUrl, orderId);

// Execute spot swap
await executeSpotOrder(apiBaseUrl, {
  fromAsset: 'USDC',
  toAsset: 'USDH',
  amount: 100,
});

Watchlist Operations

import { toggleWatchlist } from '@pear-protocol/hyperliquid-sdk';

await toggleWatchlist(apiBaseUrl, longAssets, shortAssets);

Utility Functions

Position Validation

import {
  validateMinimumAssetSize,
  validateMaxAssetsPerLeg,
  calculateMinimumPositionValue,
  MINIMUM_ASSET_USD_VALUE,  // 11
  MAX_ASSETS_PER_LEG,       // 15
} from '@pear-protocol/hyperliquid-sdk';

try {
  validateMinimumAssetSize(usdValue, longAssets, shortAssets);
  validateMaxAssetsPerLeg(longAssets, shortAssets);
} catch (error) {
  if (error instanceof MinimumPositionSizeError) {
    console.log('Minimum:', error.minimumRequired);
  }
}

const minValue = calculateMinimumPositionValue(longAssets, shortAssets);

Token Metadata

import {
  TokenMetadataExtractor,
  selectTokenMetadataBySymbols,
  getAssetByName,
} from '@pear-protocol/hyperliquid-sdk';

// Extract metadata for a token
const metadata = TokenMetadataExtractor.extractTokenMetadata(
  'BTC',
  perpMetaAssets,
  assetContexts,
  allMids,
  activeAssetData
);

// Filter metadata by symbols
const filtered = selectTokenMetadataBySymbols(allMetadata, ['BTC', 'ETH']);

// Single lookup
const btc = getAssetByName(allMetadata, 'BTC');

Basket Calculations

import {
  computeBasketCandles,
  calculateWeightedRatio,
  createCandleLookups,
  getCompleteTimestamps,
} from '@pear-protocol/hyperliquid-sdk';

// Compute weighted basket candles
const basketCandles = computeBasketCandles(
  longAssets,
  shortAssets,
  longCandles,
  shortCandles,
  leverage
);

// Calculate weighted price ratio
const ratio = calculateWeightedRatio(longMetadata, shortMetadata, weights);

Chart Interval Conversion

import {
  mapTradingViewIntervalToCandleInterval,
  mapCandleIntervalToTradingViewInterval,
} from '@pear-protocol/hyperliquid-sdk';

const candleInterval = mapTradingViewIntervalToCandleInterval('60'); // '1h'
const tvInterval = mapCandleIntervalToTradingViewInterval('1h'); // '60'

Order Helpers

import {
  getOrderLeverage,
  getOrderUsdValue,
  getOrderTriggerType,
  getOrderTriggerValue,
  getOrderDirection,
  isBtcDomOrder,
} from '@pear-protocol/hyperliquid-sdk';

const leverage = getOrderLeverage(order);
const isBtcDom = isBtcDomOrder(order);

Conflict Detection

import { ConflictDetector } from '@pear-protocol/hyperliquid-sdk';

const conflicts = ConflictDetector.detectConflicts(longTokens, shortTokens);
// Returns TokenConflict[] if same token appears in both legs

Types Reference

Core Types

import type {
  // API Response
  ApiResponse,
  ApiErrorResponse,

  // Position Types
  OpenPositionDto,
  PositionAssetDetailDto,

  // Order Types
  OpenLimitOrderDto,
  OrderAssetDto,
  OrderStatus,
  TriggerOrderNotificationType,

  // Market Data
  TokenMetadata,
  ActiveAssetsResponse,
  ActiveAssetGroupItem,

  // WebSocket
  WebSocketConnectionState,
  WebSocketChannel,

  // Token Selection
  TokenSelection,
  TokenConflict,

  // Candles
  CandleInterval,
  CandleData,

  // TWAP
  TwapMonitoringDto,

  // Account
  PlatformAccountSummaryResponseDto,
} from '@pear-protocol/hyperliquid-sdk';

Key Type Definitions

interface TokenMetadata {
  symbol: string;
  assetName: string;
  currentPrice: number;
  priceChange24h: number;
  priceChangePercent24h: number;
  maxLeverage: number;
  openInterest: string;
  volume: string;
  fundingRate: number;
  isAtOiCaps: boolean;
  collateralToken?: 'USDC' | 'USDH';
}

interface OpenPositionDto {
  positionId: string;
  longAssets: PositionAssetDetailDto[];
  shortAssets: PositionAssetDetailDto[];
  entryRatio: number;
  markRatio: number;
  marginUsed: number;
  positionValue: number;
  unrealizedPnl: number;
  takeProfit?: TpSlOrderParameters;
  stopLoss?: TpSlOrderParameters;
}

type TriggerOrderNotificationType =
  | 'PRICE'
  | 'PRICE_RATIO'
  | 'WEIGHTED_RATIO'
  | 'CROSS_ASSET_PRICE'
  | 'PREDICTION_MARKET_OUTCOME'
  | 'BTC_DOM';

type CandleInterval = '1m' | '5m' | '15m' | '1h' | '4h' | '1d';

Examples

Complete Trading Flow

import {
  PearHyperliquidProvider,
  useAuth,
  usePosition,
  useMarket,
  useUserSelection,
  useTokenSelectionMetadata,
  useAllUserBalances,
} from '@pear-protocol/hyperliquid-sdk';

function TradingInterface() {
  const { isAuthenticated, loginWithSignedMessage } = useAuth();
  const { openPositions, createPosition, closePosition } = usePosition();
  const { allTokenMetadata } = useMarket();
  const { longTokens, shortTokens, addToken, updateTokenWeight } = useUserSelection();
  const { weightedRatio, maxLeverage, minMargin } = useTokenSelectionMetadata();
  const { availableToTradeUsdc } = useAllUserBalances();

  const handleCreatePosition = async () => {
    try {
      await createPosition({
        longAssets: longTokens.map(t => ({ asset: t.symbol, weight: t.weight })),
        shortAssets: shortTokens.map(t => ({ asset: t.symbol, weight: t.weight })),
        usdValue: 1000,
        leverage: Math.min(maxLeverage, 10),
        slippage: 0.5,
        executionType: 'MARKET',
      });
    } catch (error) {
      console.error('Failed to create position:', error);
    }
  };

  return (
    <div>
      <h2>Available: ${availableToTradeUsdc}</h2>
      <h3>Weighted Ratio: {weightedRatio.toFixed(4)}</h3>
      <h3>Max Leverage: {maxLeverage}x</h3>

      <div>
        <h4>Long Tokens</h4>
        {longTokens.map((token, i) => (
          <div key={i}>
            {token.symbol}: {token.weight}%
            @ ${allTokenMetadata[token.symbol]?.currentPrice}
          </div>
        ))}
      </div>

      <button onClick={handleCreatePosition}>
        Open Position
      </button>

      <div>
        <h4>Open Positions ({openPositions?.length ?? 0})</h4>
        {openPositions?.map(pos => (
          <div key={pos.positionId}>
            PnL: ${pos.unrealizedPnl.toFixed(2)}
            <button onClick={() => closePosition(pos.positionId, { slippage: 0.5 })}>
              Close
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

Real-time Price Display

import { useMarket, usePearHyperliquid } from '@pear-protocol/hyperliquid-sdk';

function PriceDisplay({ symbol }: { symbol: string }) {
  const { isConnected, nativeIsConnected } = usePearHyperliquid();
  const { getAssetByName } = useMarket();

  const metadata = getAssetByName(symbol);

  if (!nativeIsConnected) {
    return <div>Connecting...</div>;
  }

  return (
    <div>
      <h3>{symbol}</h3>
      <p>Price: ${metadata?.currentPrice.toFixed(2)}</p>
      <p>24h Change: {metadata?.priceChangePercent24h.toFixed(2)}%</p>
      <p>Funding: {(metadata?.fundingRate * 100).toFixed(4)}%</p>
    </div>
  );
}

Contributing

Development Setup

  1. Clone the repository:
git clone https://github.com/pear-protocol/hyperliquid.git
cd hyperliquid/pear-hyperliquid-sdk
  1. Install dependencies:
yarn install
  1. Start development mode:
yarn dev

Project Structure

pear-hyperliquid-sdk/
├── src/
│   ├── clients/          # API client functions
│   │   ├── auth.ts       # Authentication endpoints
│   │   ├── positions.ts  # Position management
│   │   ├── orders.ts     # Order management
│   │   ├── watchlist.ts  # Watchlist operations
│   │   ├── hyperliquid.ts # Hyperliquid public API
│   │   └── ...
│   ├── hooks/            # React hooks
│   │   ├── useAuth.ts
│   │   ├── usePosition.ts
│   │   ├── useOrders.ts
│   │   ├── useMarket.ts
│   │   ├── useMarketData.ts
│   │   └── ... (20+ hooks)
│   ├── store/            # Zustand stores
│   │   ├── userDataStore.ts      # User authentication & real-time data
│   │   ├── hyperliquidDataStore.ts # Market metadata & prices
│   │   ├── userSelection.ts      # Token selection UI state
│   │   ├── marketDataStore.ts    # Market baskets
│   │   └── ...
│   ├── utils/            # Utility functions
│   │   ├── position-validator.ts
│   │   ├── token-metadata-extractor.ts
│   │   ├── basket-calculator.ts
│   │   └── ...
│   ├── provider.tsx      # PearHyperliquidProvider component
│   ├── websocket.ts      # Pear API WebSocket
│   ├── hyperliquid-websocket.ts # Native Hyperliquid WebSocket
│   ├── types.ts          # TypeScript definitions
│   └── index.ts          # Public API exports
├── dist/                 # Build output
├── package.json
├── tsconfig.json
└── rollup.config.js

Architecture Overview

┌─────────────────────────────────────────────────────────────────┐
│                    PearHyperliquidProvider                       │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────────────────┐    ┌─────────────────────┐            │
│  │  Pear API WebSocket │    │ Hyperliquid Native  │            │
│  │  (user data, orders)│    │  WS (market data)   │            │
│  └──────────┬──────────┘    └──────────┬──────────┘            │
│             │                          │                        │
│             ▼                          ▼                        │
│  ┌─────────────────────────────────────────────────────────────┤
│  │                    Zustand Stores                            │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │  │ userDataStore│  │hyperliquid │  │ userSelection│         │
│  │  │  (auth, pos) │  │ DataStore  │  │   (UI state) │         │
│  │  └─────────────┘  └─────────────┘  └─────────────┘         │
│  └─────────────────────────────────────────────────────────────┤
│             │                          │                        │
│             ▼                          ▼                        │
│  ┌─────────────────────────────────────────────────────────────┤
│  │                      React Hooks                             │
│  │  usePosition, useOrders, useMarket, useAuth, ...            │
│  └─────────────────────────────────────────────────────────────┤
└─────────────────────────────────────────────────────────────────┘

Available Scripts

| Script | Description | |--------|-------------| | yarn build | Build the SDK for production | | yarn dev | Start development mode with watch | | yarn type-check | Run TypeScript type checking | | yarn clean | Remove build artifacts | | yarn copy-to-node-modules | Copy build to parent node_modules (for local development) |

Code Style

  • TypeScript: Strict mode enabled
  • Exports: ESM only (no CommonJS)
  • React: Functional components with hooks
  • State: Zustand for global state
  • API Calls: Axios with interceptors

Adding a New Hook

  1. Create the hook file in src/hooks/:
// src/hooks/useMyFeature.ts
import { useCallback } from 'react';
import { useUserData } from '../store/userDataStore';
import { usePearHyperliquid } from '../provider';

export function useMyFeature() {
  const { apiBaseUrl } = usePearHyperliquid();
  const address = useUserData((state) => state.address);

  const myFunction = useCallback(async () => {
    // Implementation
  }, [apiBaseUrl, address]);

  return { myFunction };
}
  1. Export from src/hooks/index.ts:
export * from './useMyFeature';

Adding a New Client Function

  1. Create or update the client file in src/clients/:
// src/clients/myFeature.ts
import { apiClient } from '../utils/http';
import type { ApiResponse } from '../types';

export interface MyRequestPayload {
  // ...
}

export interface MyResponseDto {
  // ...
}

export async function myApiCall(
  baseUrl: string,
  payload: MyRequestPayload
): Promise<ApiResponse<MyResponseDto>> {
  const response = await apiClient.post(`${baseUrl}/my-endpoint`, payload);
  return response;
}
  1. Export from src/index.ts:
export * from './clients/myFeature';

Adding New Types

Add types to src/types.ts and export them from src/index.ts:

// src/types.ts
export interface MyNewType {
  // ...
}

// src/index.ts
export type { MyNewType } from './types';

Building

# Production build
yarn build

# Type checking only
yarn type-check

Publishing

  1. Update version in package.json
  2. Build the package: yarn build
  3. Publish to npm: npm publish

The package is published to npm as @pear-protocol/hyperliquid-sdk.

Key Design Patterns

Composition Pattern: Multiple stores compose to create computed state. For example, usePosition() combines data from userDataStore, hyperliquidDataStore, and computes enriched position data.

Selector Pattern: Zustand selectors enable granular subscriptions. Only components using specific data re-render when it changes.

WebSocket Multiplexing: Two independent WebSocket streams handle different data types. The Pear API WebSocket handles user-specific data while the native Hyperliquid WebSocket handles market data.

Lazy Initialization: WebSocket connections wait for perpMetaAssets to be available before connecting, preventing premature subscriptions.

Testing

When implementing tests:

  1. Use React Testing Library for hook testing
  2. Mock WebSocket connections for real-time data tests
  3. Mock API responses with MSW or similar

Commit Guidelines

  • Use conventional commits format
  • Keep commits focused and atomic
  • Include relevant issue references

License

MIT License - see LICENSE for details.

Support