npm package: @hypersignals/hyperliquid-privy-sdk
Description: Unified Hyperliquid SDK with Privy integration for web, mobile, and backend
Author: tomarsachin2271
Latest version: 0.4.1

# @hypersignals/hyperliquid-privy-sdk

A unified TypeScript SDK for trading on Hyperliquid with Privy wallet integration. Works seamlessly across **React Web**, **React Native/Expo**, and **Node.js backend** with a consistent API.

[![npm version](https://img.shields.io/npm/v/@hypersignals/hyperliquid-privy-sdk.svg)](https://www.npmjs.com/package/@hypersignals/hyperliquid-privy-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- ✅ **Universal API** - Same methods work across web, mobile, and backend
- ✅ **Type-Safe** - Full TypeScript support with comprehensive types
- ✅ **Privy Integration** - Built-in support for Privy embedded wallets
- ✅ **Headless Signing** - No UI popups (optional)
- ✅ **Delegated Wallets** - Backend can trade on behalf of users (with permission)
- ✅ **Complete Trading Suite** - Limit, market, trigger orders, TP/SL, TWAP, leverage management
- ✅ **Tree Shakeable** - Import only what you need
- ✅ **Resilient Connection** - Automatic REST fallback when WebSocket fails, with background recovery

## Installation

```bash
npm install @hypersignals/hyperliquid-privy-sdk
```

### Peer Dependencies

For **React Web**:
```bash
npm install @privy-io/react-auth
```

For **React Native/Expo**:
```bash
npm install @privy-io/expo
```

For **Backend** (Node.js): No additional dependencies needed!

## Documentation

- 📖 **[Web App Usage Guide](./WEB_USAGE.md)** - Complete guide for React web apps with examples
- 💰 **[Builder Fees Guide](./BUILDER_FEES.md)** - How to configure and customize builder fees
- 📚 Full API reference below

## Quick Start

### React Web Example (Simplified API)

```typescript
// 1. Wrap your app with SDK provider (in layout/root)
import { usePrivy } from '@privy-io/react-auth';
import { HyperliquidSDKProvider } from '@hypersignals/hyperliquid-privy-sdk/web';

function Layout({ children }) {
  const { ready, wallets, signTypedData } = usePrivy();

  return (
    <HyperliquidSDKProvider
      ready={ready}
      signTypedData={signTypedData}
      wallets={wallets}
      isTestnet={false}
      builder={true}
      environment="prod"
    >
      {children}
    </HyperliquidSDKProvider>
  );
}

// 2. Use SDK in your components
import { useHyperliquidClient } from '@hypersignals/hyperliquid-privy-sdk/web';

function TradingComponent() {
  const { client, isReady } = useHyperliquidClient();

  // Place market order with TP/SL (builder fee automatically applied)
  const buyETH = async () => {
    if (!isReady || !client) return;

    const result = await client.placeSymbolOrder({
      symbol: 'ETH',        // Symbol-based (no asset IDs!)
      side: 'buy',
      orderType: 'market',
      quantity: '0.1',
      slippage: 0.05,       // Auto price calculation
      takeProfit: { triggerPrice: '4200' },
      stopLoss: { triggerPrice: '3800' },
    });

    if (result.status === 'ok') {
      console.log('Order placed with TP/SL!');
    }
  };

  return <button onClick={buyETH}>Buy ETH</button>;
}
```

> 📖 See [WEB_USAGE.md](./WEB_USAGE.md) for complete examples and all features

### React Native/Expo Example

```typescript
import { HyperliquidClient } from '@hypersignals/hyperliquid-privy-sdk';
import { useSignTypedData, useWallets } from '@privy-io/expo';

// EXACT SAME CODE AS REACT WEB! 🎉
```

### Backend (Node.js/Telegram Bot) Example

```typescript
import { createServerClient } from '@hypersignals/hyperliquid-privy-sdk/server';

// Create backend client (builder fees automatically applied)
const client = createServerClient({
  userId: 'did:privy:...',
  walletAddress: '0x...',
  appId: process.env.PRIVY_APP_ID,
  appSecret: process.env.PRIVY_APP_SECRET,
});

// Place order using symbol-based API
const result = await client.placeSymbolOrder({
  symbol: 'ETH',
  side: 'buy',
  orderType: 'market',
  quantity: '0.1',
  slippage: 0.05,
});

console.log('Order placed:', result);
```

## Builder Fees

The SDK **automatically includes a 5 basis point (0.05%) builder fee** on all orders by default. This supports platform development and maintenance.

### Default Configuration

- **Builder Address**: `0x8af3545a3988b7A46f96F9F1AE40c0e64Fa493C2`
- **Builder Fee**: 5 basis points (0.05%)
- **Applied to**: All order types automatically

### Customization (Optional)

See [BUILDER_FEES.md](./BUILDER_FEES.md) for:
- How to disable builder fees
- How to use custom builder address and fee
- How to integrate with backend API for dynamic configuration

Example:
```typescript
<HyperliquidSDKProvider
  ready={ready}
  signTypedData={signTypedData}
  wallets={wallets}
  builder={false}  // Disable builder fees
>
  {children}
</HyperliquidSDKProvider>
```

## API Reference

### Order Methods

#### `placeLimitOrder(params)`
Place a limit order.

```typescript
await client.placeLimitOrder({
  asset: 0,          // Asset ID (0=BTC, 1=ETH, etc.)
  isBuy: true,       // true=long, false=short
  price: '30000',    // Limit price
  size: '0.1',       // Order size
  reduceOnly: false, // Only reduce position
  timeInForce: 'Gtc', // 'Gtc', 'Ioc', or 'Alo'
  clientOrderId: '0x...', // Optional client order ID
});
```

#### `placeMarketOrder(params)`
Place a market order (executed immediately with IoC).

```typescript
await client.placeMarketOrder({
  asset: 0,
  isBuy: true,
  price: '30000',    // Current market price (still required by API)
  size: '0.1',
  reduceOnly: false,
});
```

#### `placeTriggerOrder(params)`
Place a trigger order (stop loss or take profit).

```typescript
await client.placeTriggerOrder({
  asset: 0,
  isBuy: false,
  size: '0.1',
  triggerPrice: '29000', // Trigger when price hits this
  limitPrice: '28900',   // Optional: limit price when triggered (omit for market)
  reduceOnly: true,
  tpsl: 'sl',           // 'tp' or 'sl'
});
```

#### `placeTpSlOrder(params)`
Place both TP and SL orders for a position.

```typescript
await client.placeTpSlOrder({
  asset: 0,
  size: '0.1',
  isLong: true,        // Closing a long position
  takeProfit: {
    triggerPrice: '35000',
    limitPrice: '34900', // Optional
  },
  stopLoss: {
    triggerPrice: '28000',
    limitPrice: '27900', // Optional
  },
});
```

#### `batchOrders(params)`
Place multiple orders in a single transaction.

```typescript
await client.batchOrders({
  orders: [
    {
      asset: 0,
      isBuy: true,
      price: '30000',
      size: '0.01',
      reduceOnly: false,
      orderType: 'limit',
      timeInForce: 'Gtc',
    },
    {
      asset: 0,
      isBuy: false,
      price: '31000',
      size: '0.01',
      reduceOnly: false,
      orderType: 'limit',
      timeInForce: 'Gtc',
    },
    {
      asset: 1, // ETH
      isBuy: true,
      price: '2000',
      size: '0.1',
      reduceOnly: false,
      orderType: 'limit',
      timeInForce: 'Gtc',
    },
  ],
  grouping: 'na', // 'na' | 'normalTpsl' | 'positionTpsl'
});
```

#### `modifyOrder(params)`
Modify an existing order.

```typescript
await client.modifyOrder({
  orderId: 123,
  order: {
    asset: 0,
    isBuy: true,
    price: '31000',    // New price
    size: '0.2',       // New size
    reduceOnly: false,
    timeInForce: 'Gtc',
  },
});
```

#### `batchModifyOrders(params)`
Modify multiple orders in a single transaction.

```typescript
await client.batchModifyOrders({
  modifies: [
    {
      orderId: 123,
      order: {
        asset: 0,
        isBuy: true,
        price: '31000',
        size: '0.2',
        reduceOnly: false,
        timeInForce: 'Gtc',
      },
    },
    {
      orderId: 456,
      order: {
        asset: 1,
        isBuy: false,
        price: '2100',
        size: '0.15',
        reduceOnly: false,
        timeInForce: 'Gtc',
      },
    },
  ],
});
```

#### `cancelOrders(params)`
Cancel orders by ID.

```typescript
await client.cancelOrders({
  cancels: [
    { asset: 0, orderId: 123 },
    { asset: 1, orderId: 456 },
  ],
});
```

#### `cancelAllOrders(asset?)`
Cancel all orders (optionally for a specific asset).

```typescript
await client.cancelAllOrders(0); // Cancel all BTC orders
await client.cancelAllOrders();  // Cancel all orders
```

### Leverage & Margin Methods

#### `updateLeverage(params)`
Set leverage and margin mode.

```typescript
await client.updateLeverage({
  asset: 0,
  isCross: true,    // true=cross, false=isolated
  leverage: 5,      // 1-50x
});
```

#### `setMarginMode(params)`
Helper to set margin mode.

```typescript
await client.setMarginMode({
  asset: 0,
  mode: 'cross',    // 'cross' or 'isolated'
  leverage: 5,
});
```

#### `updateIsolatedMargin(params)`
Add or remove margin from isolated position.

```typescript
await client.updateIsolatedMargin({
  asset: 0,
  isBuy: true,      // Long or short side
  amountUsd: 100,   // Positive to add, negative to remove
});
```

### TWAP Methods

#### `placeTwapOrder(params)`
Place a TWAP (Time-Weighted Average Price) order.

```typescript
await client.placeTwapOrder({
  asset: 0,
  isBuy: true,
  size: '1.0',
  durationMinutes: 60,  // Spread over 1 hour
  randomizeTiming: true,
  reduceOnly: false,
});
```

#### `cancelTwapOrder(params)`
Cancel a TWAP order.

```typescript
await client.cancelTwapOrder({
  asset: 0,
  twapId: 1,
});
```

### Schedule Cancel (Dead Man's Switch)

#### `scheduleCancel(timeMs?)`
Schedule automatic cancellation of all orders.

```typescript
// Cancel all orders in 1 hour
await client.scheduleCancel(Date.now() + 3600000);

// Remove scheduled cancel
await client.removeScheduledCancel();
```

### DEX Abstraction (HIP-3)

#### `getDexAbstractionState(userAddress?)`
Check if DEX fee abstraction is enabled for a wallet.

```typescript
// Check current user's DEX abstraction status
const status = await client.getDexAbstractionState();

if (status === true) {
  console.log('DEX abstraction is enabled');
} else if (status === false) {
  console.log('DEX abstraction is disabled');
} else {
  console.log('DEX abstraction is not set');
}

// Check another user's status
const otherUserStatus = await client.getDexAbstractionState('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
```

#### `enableAgentDexAbstraction()`
Enable DEX fee abstraction using Agent signing.

```typescript
const result = await client.enableAgentDexAbstraction();

if (result.status === 'ok') {
  console.log('DEX abstraction enabled successfully!');
} else {
  console.error('Failed to enable:', result.message);
}
```

**Note:** Once enabled via Agent, DEX abstraction cannot be disabled. This is by design in Hyperliquid's HIP-3 implementation.

## Backend-Specific Features

### Getting Delegated Wallets

```typescript
import { HyperliquidBackendClient } from '@hypersignals/hyperliquid-privy-sdk/backend';

const client = new HyperliquidBackendClient({
  privy: { appId: '...', appSecret: '...', walletId: '...' },
});

// Get all delegated wallets for a user
const wallets = await client.getUserDelegatedWallets('privy-user-id');
console.log(wallets);
// [{ address: '0x...', walletId: 'prv_...', chainType: 'ethereum' }]
```

## Delegated Wallet Setup (Required for Backend)

For backend trading, users must first delegate their wallet:

### Frontend: Delegate Wallet

```typescript
import { useDelegatedActions, useWallets } from '@privy-io/react-auth';

function DelegateButton() {
  const { delegateWallet } = useDelegatedActions();
  const { wallets } = useWallets();

  const handleDelegate = async () => {
    await delegateWallet({
      address: wallets[0].address,
      chainType: 'ethereum',
    });
    // User sees Privy modal to approve delegation
  };

  return <button onClick={handleDelegate}>Delegate Wallet</button>;
}
```

## Asset IDs

Common asset IDs (use these in the `asset` parameter):

```typescript
import { ASSET_IDS } from '@hypersignals/hyperliquid-privy-sdk';

ASSET_IDS.BTC   // 0
ASSET_IDS.ETH   // 1
ASSET_IDS.SOL   // 2
ASSET_IDS.ARB   // 3
ASSET_IDS.AVAX  // 4
```

## Error Handling

```typescript
try {
  await client.placeLimitOrder({ ... });
} catch (error) {
  if (error instanceof Error) {
    console.error('Order failed:', error.message);
    // Common errors:
    // - "Insufficient margin"
    // - "Invalid price"
    // - "User rejected the request"
    // - "Request timeout after 30000ms"
  }
}
```

### Connection Resilience

The SDK automatically handles WebSocket connection issues:

- **WebSocket errors** (connection failed, network issues) → Automatically falls back to REST API
- **API errors** (insufficient margin, invalid price) → Thrown as exceptions (no fallback)
- **Background recovery** → WebSocket reconnects automatically in the background
- **Automatic switch back** → When WebSocket recovers, SDK switches back from REST

You can check the current transport state:

```typescript
const { client } = useHyperliquidClient();

// Check if currently using REST fallback
if (client?.isUsingRestFallback()) {
  console.log('Using REST API (WebSocket recovering in background)');
}
```

## Advanced Usage

### Custom Timeout

```typescript
import { HyperliquidClient } from '@hypersignals/hyperliquid-privy-sdk';
import { HyperliquidAPIClient } from '@hypersignals/hyperliquid-privy-sdk/core/utils/api';

// Default timeout is 30 seconds
// For custom timeout, you'll need to extend the client
```

### Testing with Testnet

```typescript
<HyperliquidSDKProvider
  ready={ready}
  signTypedData={signTypedData}
  wallets={wallets}
  isTestnet={true}  // Use Hyperliquid testnet
>
  {children}
</HyperliquidSDKProvider>
```

## TypeScript Support

Full TypeScript support with comprehensive types:

```typescript
import type {
  OrderResponse,
  SuccessResponse,
  CancelResponse,
  LimitOrderParams,
  MarketOrderParams,
  TriggerOrderParams,
} from '@hypersignals/hyperliquid-privy-sdk';
```

## Examples

See the [examples](./examples) directory for complete implementations:

- [`examples/react-web`](./examples/react-web) - React web app example
- [`examples/react-native`](./examples/react-native) - React Native/Expo example
- [`examples/telegram-bot`](./examples/telegram-bot) - Telegram bot example

## Development

```bash
# Install dependencies
npm install

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Build
npm run build

# Lint
npm run lint

# Type check
npm run typecheck
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT © [HyperSignals](https://github.com/bcnmy)

## Support

- 📚 [Documentation](https://github.com/bcnmy/hyperliquid-privy-sdk)
- 🐛 [Issues](https://github.com/bcnmy/hyperliquid-privy-sdk/issues)
- 💬 [Discussions](https://github.com/bcnmy/hyperliquid-privy-sdk/discussions)

## Acknowledgments

- [Hyperliquid](https://hyperliquid.xyz) - The decentralized exchange
- [Privy](https://privy.io) - Embedded wallet infrastructure
- Built by [HyperSignals](https://github.com/bcnmy/hyperliquid-privy-sdk)