@pear-protocol/hyperliquid-sdk 0.0.79 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1141 @@
1
+ # @pear-protocol/hyperliquid-sdk
2
+
3
+ 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.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [Provider Setup](#provider-setup)
10
+ - [Authentication](#authentication)
11
+ - [Hooks Reference](#hooks-reference)
12
+ - [Trading Hooks](#trading-hooks)
13
+ - [Data Hooks](#data-hooks)
14
+ - [WebSocket Hooks](#websocket-hooks)
15
+ - [UI State Hooks](#ui-state-hooks)
16
+ - [Client Functions](#client-functions)
17
+ - [Utility Functions](#utility-functions)
18
+ - [Types Reference](#types-reference)
19
+ - [Examples](#examples)
20
+ - [Contributing](#contributing)
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install @pear-protocol/hyperliquid-sdk
28
+ # or
29
+ yarn add @pear-protocol/hyperliquid-sdk
30
+ # or
31
+ pnpm add @pear-protocol/hyperliquid-sdk
32
+ ```
33
+
34
+ ### Peer Dependencies
35
+
36
+ Ensure you have React 18+ installed:
37
+
38
+ ```bash
39
+ npm install react react-dom
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Quick Start
45
+
46
+ ```tsx
47
+ import {
48
+ PearHyperliquidProvider,
49
+ useAuth,
50
+ usePosition,
51
+ useMarket,
52
+ } from '@pear-protocol/hyperliquid-sdk';
53
+
54
+ function App() {
55
+ return (
56
+ <PearHyperliquidProvider
57
+ apiBaseUrl="https://hl-ui.pearprotocol.io"
58
+ wsUrl="wss://hl-ui.pearprotocol.io/ws"
59
+ clientId="YOUR_CLIENT_ID"
60
+ >
61
+ <TradingApp />
62
+ </PearHyperliquidProvider>
63
+ );
64
+ }
65
+
66
+ function TradingApp() {
67
+ const { isAuthenticated, loginWithSignedMessage } = useAuth();
68
+ const { openPositions, createPosition } = usePosition();
69
+ const { allTokenMetadata } = useMarket();
70
+
71
+ if (!isAuthenticated) {
72
+ return <button onClick={() => loginWithSignedMessage(address, signMessage)}>Connect</button>;
73
+ }
74
+
75
+ return (
76
+ <div>
77
+ <h2>Open Positions: {openPositions?.length ?? 0}</h2>
78
+ {/* Your trading UI */}
79
+ </div>
80
+ );
81
+ }
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Provider Setup
87
+
88
+ Wrap your application with `PearHyperliquidProvider` to enable SDK functionality:
89
+
90
+ ```tsx
91
+ import { PearHyperliquidProvider } from '@pear-protocol/hyperliquid-sdk';
92
+
93
+ function App() {
94
+ return (
95
+ <PearHyperliquidProvider
96
+ apiBaseUrl="https://hl-ui.pearprotocol.io" // Pear API endpoint
97
+ wsUrl="wss://hl-ui.pearprotocol.io/ws" // WebSocket endpoint
98
+ clientId="YOUR_CLIENT_ID" // Your application ID
99
+ >
100
+ {children}
101
+ </PearHyperliquidProvider>
102
+ );
103
+ }
104
+ ```
105
+
106
+ ### Provider Props
107
+
108
+ | Prop | Type | Default | Description |
109
+ |------|------|---------|-------------|
110
+ | `apiBaseUrl` | `string` | `'https://hl-ui.pearprotocol.io'` | Pear Protocol API base URL |
111
+ | `wsUrl` | `string` | `'wss://hl-ui.pearprotocol.io/ws'` | WebSocket server URL |
112
+ | `clientId` | `string` | `'PEARPROTOCOLUI'` | Application client identifier |
113
+
114
+ ### Accessing Provider Context
115
+
116
+ ```tsx
117
+ import { usePearHyperliquid } from '@pear-protocol/hyperliquid-sdk';
118
+
119
+ function Component() {
120
+ const {
121
+ clientId,
122
+ apiBaseUrl,
123
+ wsUrl,
124
+ isConnected, // Pear WebSocket connection status
125
+ lastError, // Pear WebSocket last error
126
+ nativeIsConnected, // Hyperliquid WebSocket connection status
127
+ nativeLastError, // Hyperliquid WebSocket last error
128
+ } = usePearHyperliquid();
129
+ }
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Authentication
135
+
136
+ The SDK provides EIP-712 signature-based authentication:
137
+
138
+ ```tsx
139
+ import { useAuth } from '@pear-protocol/hyperliquid-sdk';
140
+
141
+ function AuthComponent() {
142
+ const {
143
+ isAuthenticated,
144
+ isLoading,
145
+ address,
146
+ loginWithSignedMessage,
147
+ loginWithPrivy,
148
+ logout,
149
+ } = useAuth();
150
+
151
+ const handleLogin = async () => {
152
+ // Using wallet signature (e.g., with wagmi/viem)
153
+ await loginWithSignedMessage(
154
+ walletAddress,
155
+ async (message) => {
156
+ // Your wallet's signMessage function
157
+ return await signMessage({ message });
158
+ }
159
+ );
160
+ };
161
+
162
+ const handlePrivyLogin = async () => {
163
+ // Using Privy authentication
164
+ await loginWithPrivy(walletAddress, privyAccessToken);
165
+ };
166
+ }
167
+ ```
168
+
169
+ ### Authentication Flow
170
+
171
+ 1. SDK requests an EIP-712 message from the server
172
+ 2. User signs the message with their wallet
173
+ 3. Signature is sent to authenticate
174
+ 4. JWT tokens are stored and managed automatically
175
+
176
+ ---
177
+
178
+ ## Hooks Reference
179
+
180
+ ### Trading Hooks
181
+
182
+ #### `usePosition()`
183
+
184
+ Manage positions with full CRUD operations:
185
+
186
+ ```tsx
187
+ import { usePosition } from '@pear-protocol/hyperliquid-sdk';
188
+
189
+ function PositionManager() {
190
+ const {
191
+ openPositions, // OpenPositionDto[] - enriched position data
192
+ isLoading,
193
+ createPosition, // Create new position
194
+ closePosition, // Close specific position
195
+ closeAllPositions, // Close all positions
196
+ adjustPosition, // Rebalance position weights
197
+ updateRiskParameters, // Update TP/SL
198
+ updateLeverage, // Change leverage
199
+ } = usePosition();
200
+
201
+ const handleCreate = async () => {
202
+ await createPosition({
203
+ longAssets: [{ asset: 'BTC', weight: 50 }, { asset: 'ETH', weight: 50 }],
204
+ shortAssets: [{ asset: 'SOL', weight: 100 }],
205
+ usdValue: 1000,
206
+ leverage: 5,
207
+ slippage: 0.5,
208
+ executionType: 'MARKET',
209
+ takeProfit: { triggerType: 'WEIGHTED_RATIO', triggerValue: 1.1 },
210
+ stopLoss: { triggerType: 'WEIGHTED_RATIO', triggerValue: 0.95 },
211
+ });
212
+ };
213
+ }
214
+ ```
215
+
216
+ #### `useTrading()`
217
+
218
+ High-level trading operations with enriched trade history:
219
+
220
+ ```tsx
221
+ import { useTrading } from '@pear-protocol/hyperliquid-sdk';
222
+
223
+ function TradingComponent() {
224
+ const {
225
+ tradeHistories, // Trade history with metadata
226
+ createTrade,
227
+ adjustTrade,
228
+ closeTrade,
229
+ } = useTrading();
230
+ }
231
+ ```
232
+
233
+ #### `useOrders()`
234
+
235
+ Manage open and trigger orders:
236
+
237
+ ```tsx
238
+ import { useOrders } from '@pear-protocol/hyperliquid-sdk';
239
+
240
+ function OrdersComponent() {
241
+ const {
242
+ openOrders, // OpenLimitOrderDto[]
243
+ triggerOrders, // Filtered trigger orders
244
+ adjustOrder,
245
+ cancelOrder,
246
+ } = useOrders();
247
+ }
248
+ ```
249
+
250
+ #### `useSpotOrder()`
251
+
252
+ Execute spot swaps:
253
+
254
+ ```tsx
255
+ import { useSpotOrder } from '@pear-protocol/hyperliquid-sdk';
256
+
257
+ function SpotSwap() {
258
+ const { executeSpotOrder, isLoading } = useSpotOrder();
259
+
260
+ const handleSwap = async () => {
261
+ await executeSpotOrder({
262
+ fromAsset: 'USDC',
263
+ toAsset: 'USDH',
264
+ amount: 100,
265
+ });
266
+ };
267
+ }
268
+ ```
269
+
270
+ #### `useTwap()`
271
+
272
+ Monitor TWAP order execution:
273
+
274
+ ```tsx
275
+ import { useTwap } from '@pear-protocol/hyperliquid-sdk';
276
+
277
+ function TwapMonitor() {
278
+ const { twapOrders, cancelTwapOrder } = useTwap();
279
+
280
+ return twapOrders?.map(order => (
281
+ <div key={order.orderId}>
282
+ Status: {order.status}
283
+ Progress: {order.filledUsdValue} / {order.totalUsdValue}
284
+ Chunks: {order.chunks.length - order.remainingChunks} / {order.chunks.length}
285
+ </div>
286
+ ));
287
+ }
288
+ ```
289
+
290
+ ### Data Hooks
291
+
292
+ #### `useMarket()`
293
+
294
+ Access token metadata:
295
+
296
+ ```tsx
297
+ import { useMarket } from '@pear-protocol/hyperliquid-sdk';
298
+
299
+ function MarketData() {
300
+ const {
301
+ allTokenMetadata, // Record<string, TokenMetadata>
302
+ getAssetByName, // (symbol: string) => TokenMetadata | null
303
+ } = useMarket();
304
+
305
+ const btcData = getAssetByName('BTC');
306
+ // { symbol: 'BTC', currentPrice: 50000, maxLeverage: 50, ... }
307
+ }
308
+ ```
309
+
310
+ #### `useMarketData()`
311
+
312
+ Get market baskets and analytics:
313
+
314
+ ```tsx
315
+ import { useMarketData, type CollateralFilter } from '@pear-protocol/hyperliquid-sdk';
316
+
317
+ function MarketAnalytics() {
318
+ const {
319
+ activeBaskets, // Active market baskets
320
+ highlightedBaskets, // Featured baskets
321
+ topGainers, // Best performing
322
+ topLosers, // Worst performing
323
+ watchlistBaskets, // User's watchlist
324
+ isLoading,
325
+ collateralFilter, // 'ALL' | 'USDC' | 'USDH'
326
+ setCollateralFilter,
327
+ } = useMarketData();
328
+ }
329
+ ```
330
+
331
+ #### `useAllUserBalances()`
332
+
333
+ Aggregate user balances:
334
+
335
+ ```tsx
336
+ import { useAllUserBalances } from '@pear-protocol/hyperliquid-sdk';
337
+
338
+ function BalanceDisplay() {
339
+ const {
340
+ spotUsdcBalance,
341
+ spotUsdhBalance,
342
+ availableToTradeUsdc,
343
+ availableToTradeUsdh,
344
+ isLoading,
345
+ } = useAllUserBalances();
346
+ }
347
+ ```
348
+
349
+ #### `useTokenSelectionMetadata()`
350
+
351
+ Get computed metrics for selected tokens:
352
+
353
+ ```tsx
354
+ import { useTokenSelectionMetadata } from '@pear-protocol/hyperliquid-sdk';
355
+
356
+ function SelectionMetrics() {
357
+ const {
358
+ longTokensMetadata, // Metadata for selected long tokens
359
+ shortTokensMetadata, // Metadata for selected short tokens
360
+ weightedRatio, // Current weighted price ratio
361
+ weightedRatio24h, // 24h weighted ratio change
362
+ priceRatio, // Simple price ratio
363
+ openInterest, // Combined OI
364
+ volume, // Combined volume
365
+ maxLeverage, // Maximum allowed leverage
366
+ minMargin, // Minimum margin required
367
+ leverageMatched, // If all tokens support same leverage
368
+ isPriceDataReady,
369
+ } = useTokenSelectionMetadata();
370
+ }
371
+ ```
372
+
373
+ #### `useHistoricalPriceData()`
374
+
375
+ Fetch and cache historical prices:
376
+
377
+ ```tsx
378
+ import { useHistoricalPriceData } from '@pear-protocol/hyperliquid-sdk';
379
+
380
+ function ChartData() {
381
+ const { fetchHistoricalData, getCachedData } = useHistoricalPriceData();
382
+
383
+ useEffect(() => {
384
+ fetchHistoricalData('BTC', startTime, endTime, '1h');
385
+ }, []);
386
+
387
+ const candles = getCachedData('BTC', startTime, endTime);
388
+ }
389
+ ```
390
+
391
+ #### `useBasketCandles()`
392
+
393
+ Compose weighted candles from multiple assets:
394
+
395
+ ```tsx
396
+ import { useBasketCandles } from '@pear-protocol/hyperliquid-sdk';
397
+
398
+ function BasketChart() {
399
+ const {
400
+ basketCandles, // Weighted OHLCV data
401
+ isLoading,
402
+ error,
403
+ } = useBasketCandles({
404
+ longAssets: [{ symbol: 'BTC', weight: 50 }, { symbol: 'ETH', weight: 50 }],
405
+ shortAssets: [{ symbol: 'SOL', weight: 100 }],
406
+ interval: '1h',
407
+ leverage: 5,
408
+ });
409
+ }
410
+ ```
411
+
412
+ ### WebSocket Hooks
413
+
414
+ #### `useHyperliquidWebSocket()`
415
+
416
+ Access Pear API WebSocket (managed by provider):
417
+
418
+ ```tsx
419
+ import { useHyperliquidWebSocket } from '@pear-protocol/hyperliquid-sdk';
420
+
421
+ // Typically used internally by the provider
422
+ const { isConnected, lastError } = useHyperliquidWebSocket({
423
+ wsUrl: 'wss://hl-ui.pearprotocol.io/ws',
424
+ address: userAddress,
425
+ enabled: true,
426
+ });
427
+ ```
428
+
429
+ #### `useHyperliquidNativeWebSocket()`
430
+
431
+ Access Hyperliquid native WebSocket (managed by provider):
432
+
433
+ ```tsx
434
+ import { useHyperliquidNativeWebSocket } from '@pear-protocol/hyperliquid-sdk';
435
+
436
+ // Typically used internally by the provider
437
+ const { isConnected, lastError } = useHyperliquidNativeWebSocket({
438
+ address: userAddress,
439
+ tokens: ['BTC', 'ETH'],
440
+ enabled: true,
441
+ });
442
+ ```
443
+
444
+ ### UI State Hooks
445
+
446
+ #### `useUserSelection()`
447
+
448
+ Manage token selection state:
449
+
450
+ ```tsx
451
+ import { useUserSelection } from '@pear-protocol/hyperliquid-sdk';
452
+
453
+ function TokenSelector() {
454
+ const {
455
+ longTokens, // TokenSelection[]
456
+ shortTokens, // TokenSelection[]
457
+ addToken, // (isLong: boolean) => boolean
458
+ removeToken, // (isLong: boolean, index: number) => void
459
+ updateTokenWeight, // (isLong: boolean, index: number, weight: number) => void
460
+ handleTokenSelect, // (symbol: string) => void
461
+ setTokenSelections, // (longs, shorts) => void
462
+ resetToDefaults, // Reset to default selection
463
+ candleInterval, // Current chart interval
464
+ setCandleInterval, // Set chart interval
465
+ openTokenSelector, // Token selector modal state
466
+ setOpenTokenSelector,
467
+ conflicts, // Detected token conflicts
468
+ openConflictModal,
469
+ } = useUserSelection();
470
+
471
+ const handleAddLong = () => {
472
+ const success = addToken(true); // Returns false if MAX_ASSETS_PER_LEG reached
473
+ };
474
+ }
475
+ ```
476
+
477
+ #### `useWatchlist()`
478
+
479
+ Manage user watchlist:
480
+
481
+ ```tsx
482
+ import { useWatchlist } from '@pear-protocol/hyperliquid-sdk';
483
+
484
+ function Watchlist() {
485
+ const { toggleWatchlist, isLoading } = useWatchlist();
486
+
487
+ const handleToggle = async () => {
488
+ await toggleWatchlist(
489
+ [{ asset: 'BTC', weight: 50 }],
490
+ [{ asset: 'ETH', weight: 50 }]
491
+ );
492
+ };
493
+ }
494
+ ```
495
+
496
+ #### `useNotifications()`
497
+
498
+ Access user notifications:
499
+
500
+ ```tsx
501
+ import { useNotifications } from '@pear-protocol/hyperliquid-sdk';
502
+
503
+ function NotificationCenter() {
504
+ const {
505
+ notifications, // NotificationDto[]
506
+ markAsRead,
507
+ isLoading,
508
+ } = useNotifications();
509
+ }
510
+ ```
511
+
512
+ #### `useAccountSummary()`
513
+
514
+ Get portfolio-level metrics:
515
+
516
+ ```tsx
517
+ import { useAccountSummary } from '@pear-protocol/hyperliquid-sdk';
518
+
519
+ function AccountOverview() {
520
+ const { accountSummary } = useAccountSummary();
521
+
522
+ return (
523
+ <div>
524
+ <p>Account Value: ${accountSummary?.totalAccountValue}</p>
525
+ <p>Unrealized PnL: ${accountSummary?.totalUnrealizedPnl}</p>
526
+ <p>Margin Used: ${accountSummary?.totalMarginUsed}</p>
527
+ </div>
528
+ );
529
+ }
530
+ ```
531
+
532
+ ---
533
+
534
+ ## Client Functions
535
+
536
+ The SDK exports client functions for direct API calls:
537
+
538
+ ### Position Operations
539
+
540
+ ```tsx
541
+ import {
542
+ createPosition,
543
+ closePosition,
544
+ closeAllPositions,
545
+ adjustPosition,
546
+ updateRiskParameters,
547
+ updateLeverage,
548
+ } from '@pear-protocol/hyperliquid-sdk';
549
+
550
+ // Create position
551
+ const result = await createPosition(apiBaseUrl, {
552
+ longAssets: [{ asset: 'BTC', weight: 100 }],
553
+ shortAssets: [{ asset: 'ETH', weight: 100 }],
554
+ usdValue: 1000,
555
+ leverage: 5,
556
+ slippage: 0.5,
557
+ executionType: 'MARKET',
558
+ });
559
+
560
+ // Close position
561
+ await closePosition(apiBaseUrl, positionId, { slippage: 0.5 });
562
+
563
+ // Update TP/SL
564
+ await updateRiskParameters(apiBaseUrl, positionId, {
565
+ takeProfit: { triggerType: 'WEIGHTED_RATIO', triggerValue: 1.1 },
566
+ stopLoss: { triggerType: 'WEIGHTED_RATIO', triggerValue: 0.95 },
567
+ });
568
+ ```
569
+
570
+ ### Order Operations
571
+
572
+ ```tsx
573
+ import {
574
+ adjustOrder,
575
+ cancelOrder,
576
+ cancelTwapOrder,
577
+ executeSpotOrder,
578
+ } from '@pear-protocol/hyperliquid-sdk';
579
+
580
+ // Adjust limit order
581
+ await adjustOrder(apiBaseUrl, orderId, { limitRatio: 1.05 });
582
+
583
+ // Cancel order
584
+ await cancelOrder(apiBaseUrl, orderId);
585
+
586
+ // Execute spot swap
587
+ await executeSpotOrder(apiBaseUrl, {
588
+ fromAsset: 'USDC',
589
+ toAsset: 'USDH',
590
+ amount: 100,
591
+ });
592
+ ```
593
+
594
+ ### Watchlist Operations
595
+
596
+ ```tsx
597
+ import { toggleWatchlist } from '@pear-protocol/hyperliquid-sdk';
598
+
599
+ await toggleWatchlist(apiBaseUrl, longAssets, shortAssets);
600
+ ```
601
+
602
+ ---
603
+
604
+ ## Utility Functions
605
+
606
+ ### Position Validation
607
+
608
+ ```tsx
609
+ import {
610
+ validateMinimumAssetSize,
611
+ validateMaxAssetsPerLeg,
612
+ calculateMinimumPositionValue,
613
+ MINIMUM_ASSET_USD_VALUE, // 11
614
+ MAX_ASSETS_PER_LEG, // 15
615
+ } from '@pear-protocol/hyperliquid-sdk';
616
+
617
+ try {
618
+ validateMinimumAssetSize(usdValue, longAssets, shortAssets);
619
+ validateMaxAssetsPerLeg(longAssets, shortAssets);
620
+ } catch (error) {
621
+ if (error instanceof MinimumPositionSizeError) {
622
+ console.log('Minimum:', error.minimumRequired);
623
+ }
624
+ }
625
+
626
+ const minValue = calculateMinimumPositionValue(longAssets, shortAssets);
627
+ ```
628
+
629
+ ### Token Metadata
630
+
631
+ ```tsx
632
+ import {
633
+ TokenMetadataExtractor,
634
+ selectTokenMetadataBySymbols,
635
+ getAssetByName,
636
+ } from '@pear-protocol/hyperliquid-sdk';
637
+
638
+ // Extract metadata for a token
639
+ const metadata = TokenMetadataExtractor.extractTokenMetadata(
640
+ 'BTC',
641
+ perpMetaAssets,
642
+ assetContexts,
643
+ allMids,
644
+ activeAssetData
645
+ );
646
+
647
+ // Filter metadata by symbols
648
+ const filtered = selectTokenMetadataBySymbols(allMetadata, ['BTC', 'ETH']);
649
+
650
+ // Single lookup
651
+ const btc = getAssetByName(allMetadata, 'BTC');
652
+ ```
653
+
654
+ ### Basket Calculations
655
+
656
+ ```tsx
657
+ import {
658
+ computeBasketCandles,
659
+ calculateWeightedRatio,
660
+ createCandleLookups,
661
+ getCompleteTimestamps,
662
+ } from '@pear-protocol/hyperliquid-sdk';
663
+
664
+ // Compute weighted basket candles
665
+ const basketCandles = computeBasketCandles(
666
+ longAssets,
667
+ shortAssets,
668
+ longCandles,
669
+ shortCandles,
670
+ leverage
671
+ );
672
+
673
+ // Calculate weighted price ratio
674
+ const ratio = calculateWeightedRatio(longMetadata, shortMetadata, weights);
675
+ ```
676
+
677
+ ### Chart Interval Conversion
678
+
679
+ ```tsx
680
+ import {
681
+ mapTradingViewIntervalToCandleInterval,
682
+ mapCandleIntervalToTradingViewInterval,
683
+ } from '@pear-protocol/hyperliquid-sdk';
684
+
685
+ const candleInterval = mapTradingViewIntervalToCandleInterval('60'); // '1h'
686
+ const tvInterval = mapCandleIntervalToTradingViewInterval('1h'); // '60'
687
+ ```
688
+
689
+ ### Order Helpers
690
+
691
+ ```tsx
692
+ import {
693
+ getOrderLeverage,
694
+ getOrderUsdValue,
695
+ getOrderTriggerType,
696
+ getOrderTriggerValue,
697
+ getOrderDirection,
698
+ isBtcDomOrder,
699
+ } from '@pear-protocol/hyperliquid-sdk';
700
+
701
+ const leverage = getOrderLeverage(order);
702
+ const isBtcDom = isBtcDomOrder(order);
703
+ ```
704
+
705
+ ### Conflict Detection
706
+
707
+ ```tsx
708
+ import { ConflictDetector } from '@pear-protocol/hyperliquid-sdk';
709
+
710
+ const conflicts = ConflictDetector.detectConflicts(longTokens, shortTokens);
711
+ // Returns TokenConflict[] if same token appears in both legs
712
+ ```
713
+
714
+ ---
715
+
716
+ ## Types Reference
717
+
718
+ ### Core Types
719
+
720
+ ```tsx
721
+ import type {
722
+ // API Response
723
+ ApiResponse,
724
+ ApiErrorResponse,
725
+
726
+ // Position Types
727
+ OpenPositionDto,
728
+ PositionAssetDetailDto,
729
+
730
+ // Order Types
731
+ OpenLimitOrderDto,
732
+ OrderAssetDto,
733
+ OrderStatus,
734
+ TriggerOrderNotificationType,
735
+
736
+ // Market Data
737
+ TokenMetadata,
738
+ ActiveAssetsResponse,
739
+ ActiveAssetGroupItem,
740
+
741
+ // WebSocket
742
+ WebSocketConnectionState,
743
+ WebSocketChannel,
744
+
745
+ // Token Selection
746
+ TokenSelection,
747
+ TokenConflict,
748
+
749
+ // Candles
750
+ CandleInterval,
751
+ CandleData,
752
+
753
+ // TWAP
754
+ TwapMonitoringDto,
755
+
756
+ // Account
757
+ PlatformAccountSummaryResponseDto,
758
+ } from '@pear-protocol/hyperliquid-sdk';
759
+ ```
760
+
761
+ ### Key Type Definitions
762
+
763
+ ```tsx
764
+ interface TokenMetadata {
765
+ symbol: string;
766
+ assetName: string;
767
+ currentPrice: number;
768
+ priceChange24h: number;
769
+ priceChangePercent24h: number;
770
+ maxLeverage: number;
771
+ openInterest: string;
772
+ volume: string;
773
+ fundingRate: number;
774
+ isAtOiCaps: boolean;
775
+ collateralToken?: 'USDC' | 'USDH';
776
+ }
777
+
778
+ interface OpenPositionDto {
779
+ positionId: string;
780
+ longAssets: PositionAssetDetailDto[];
781
+ shortAssets: PositionAssetDetailDto[];
782
+ entryRatio: number;
783
+ markRatio: number;
784
+ marginUsed: number;
785
+ positionValue: number;
786
+ unrealizedPnl: number;
787
+ takeProfit?: TpSlOrderParameters;
788
+ stopLoss?: TpSlOrderParameters;
789
+ }
790
+
791
+ type TriggerOrderNotificationType =
792
+ | 'PRICE'
793
+ | 'PRICE_RATIO'
794
+ | 'WEIGHTED_RATIO'
795
+ | 'CROSS_ASSET_PRICE'
796
+ | 'PREDICTION_MARKET_OUTCOME'
797
+ | 'BTC_DOM';
798
+
799
+ type CandleInterval = '1m' | '5m' | '15m' | '1h' | '4h' | '1d';
800
+ ```
801
+
802
+ ---
803
+
804
+ ## Examples
805
+
806
+ ### Complete Trading Flow
807
+
808
+ ```tsx
809
+ import {
810
+ PearHyperliquidProvider,
811
+ useAuth,
812
+ usePosition,
813
+ useMarket,
814
+ useUserSelection,
815
+ useTokenSelectionMetadata,
816
+ useAllUserBalances,
817
+ } from '@pear-protocol/hyperliquid-sdk';
818
+
819
+ function TradingInterface() {
820
+ const { isAuthenticated, loginWithSignedMessage } = useAuth();
821
+ const { openPositions, createPosition, closePosition } = usePosition();
822
+ const { allTokenMetadata } = useMarket();
823
+ const { longTokens, shortTokens, addToken, updateTokenWeight } = useUserSelection();
824
+ const { weightedRatio, maxLeverage, minMargin } = useTokenSelectionMetadata();
825
+ const { availableToTradeUsdc } = useAllUserBalances();
826
+
827
+ const handleCreatePosition = async () => {
828
+ try {
829
+ await createPosition({
830
+ longAssets: longTokens.map(t => ({ asset: t.symbol, weight: t.weight })),
831
+ shortAssets: shortTokens.map(t => ({ asset: t.symbol, weight: t.weight })),
832
+ usdValue: 1000,
833
+ leverage: Math.min(maxLeverage, 10),
834
+ slippage: 0.5,
835
+ executionType: 'MARKET',
836
+ });
837
+ } catch (error) {
838
+ console.error('Failed to create position:', error);
839
+ }
840
+ };
841
+
842
+ return (
843
+ <div>
844
+ <h2>Available: ${availableToTradeUsdc}</h2>
845
+ <h3>Weighted Ratio: {weightedRatio.toFixed(4)}</h3>
846
+ <h3>Max Leverage: {maxLeverage}x</h3>
847
+
848
+ <div>
849
+ <h4>Long Tokens</h4>
850
+ {longTokens.map((token, i) => (
851
+ <div key={i}>
852
+ {token.symbol}: {token.weight}%
853
+ @ ${allTokenMetadata[token.symbol]?.currentPrice}
854
+ </div>
855
+ ))}
856
+ </div>
857
+
858
+ <button onClick={handleCreatePosition}>
859
+ Open Position
860
+ </button>
861
+
862
+ <div>
863
+ <h4>Open Positions ({openPositions?.length ?? 0})</h4>
864
+ {openPositions?.map(pos => (
865
+ <div key={pos.positionId}>
866
+ PnL: ${pos.unrealizedPnl.toFixed(2)}
867
+ <button onClick={() => closePosition(pos.positionId, { slippage: 0.5 })}>
868
+ Close
869
+ </button>
870
+ </div>
871
+ ))}
872
+ </div>
873
+ </div>
874
+ );
875
+ }
876
+ ```
877
+
878
+ ### Real-time Price Display
879
+
880
+ ```tsx
881
+ import { useMarket, usePearHyperliquid } from '@pear-protocol/hyperliquid-sdk';
882
+
883
+ function PriceDisplay({ symbol }: { symbol: string }) {
884
+ const { isConnected, nativeIsConnected } = usePearHyperliquid();
885
+ const { getAssetByName } = useMarket();
886
+
887
+ const metadata = getAssetByName(symbol);
888
+
889
+ if (!nativeIsConnected) {
890
+ return <div>Connecting...</div>;
891
+ }
892
+
893
+ return (
894
+ <div>
895
+ <h3>{symbol}</h3>
896
+ <p>Price: ${metadata?.currentPrice.toFixed(2)}</p>
897
+ <p>24h Change: {metadata?.priceChangePercent24h.toFixed(2)}%</p>
898
+ <p>Funding: {(metadata?.fundingRate * 100).toFixed(4)}%</p>
899
+ </div>
900
+ );
901
+ }
902
+ ```
903
+
904
+ ---
905
+
906
+ ## Contributing
907
+
908
+ ### Development Setup
909
+
910
+ 1. Clone the repository:
911
+
912
+ ```bash
913
+ git clone https://github.com/pear-protocol/hyperliquid.git
914
+ cd hyperliquid/pear-hyperliquid-sdk
915
+ ```
916
+
917
+ 2. Install dependencies:
918
+
919
+ ```bash
920
+ yarn install
921
+ ```
922
+
923
+ 3. Start development mode:
924
+
925
+ ```bash
926
+ yarn dev
927
+ ```
928
+
929
+ ### Project Structure
930
+
931
+ ```
932
+ pear-hyperliquid-sdk/
933
+ ├── src/
934
+ │ ├── clients/ # API client functions
935
+ │ │ ├── auth.ts # Authentication endpoints
936
+ │ │ ├── positions.ts # Position management
937
+ │ │ ├── orders.ts # Order management
938
+ │ │ ├── watchlist.ts # Watchlist operations
939
+ │ │ ├── hyperliquid.ts # Hyperliquid public API
940
+ │ │ └── ...
941
+ │ ├── hooks/ # React hooks
942
+ │ │ ├── useAuth.ts
943
+ │ │ ├── usePosition.ts
944
+ │ │ ├── useOrders.ts
945
+ │ │ ├── useMarket.ts
946
+ │ │ ├── useMarketData.ts
947
+ │ │ └── ... (20+ hooks)
948
+ │ ├── store/ # Zustand stores
949
+ │ │ ├── userDataStore.ts # User authentication & real-time data
950
+ │ │ ├── hyperliquidDataStore.ts # Market metadata & prices
951
+ │ │ ├── userSelection.ts # Token selection UI state
952
+ │ │ ├── marketDataStore.ts # Market baskets
953
+ │ │ └── ...
954
+ │ ├── utils/ # Utility functions
955
+ │ │ ├── position-validator.ts
956
+ │ │ ├── token-metadata-extractor.ts
957
+ │ │ ├── basket-calculator.ts
958
+ │ │ └── ...
959
+ │ ├── provider.tsx # PearHyperliquidProvider component
960
+ │ ├── websocket.ts # Pear API WebSocket
961
+ │ ├── hyperliquid-websocket.ts # Native Hyperliquid WebSocket
962
+ │ ├── types.ts # TypeScript definitions
963
+ │ └── index.ts # Public API exports
964
+ ├── dist/ # Build output
965
+ ├── package.json
966
+ ├── tsconfig.json
967
+ └── rollup.config.js
968
+ ```
969
+
970
+ ### Architecture Overview
971
+
972
+ ```
973
+ ┌─────────────────────────────────────────────────────────────────┐
974
+ │ PearHyperliquidProvider │
975
+ ├─────────────────────────────────────────────────────────────────┤
976
+ │ ┌─────────────────────┐ ┌─────────────────────┐ │
977
+ │ │ Pear API WebSocket │ │ Hyperliquid Native │ │
978
+ │ │ (user data, orders)│ │ WS (market data) │ │
979
+ │ └──────────┬──────────┘ └──────────┬──────────┘ │
980
+ │ │ │ │
981
+ │ ▼ ▼ │
982
+ │ ┌─────────────────────────────────────────────────────────────┤
983
+ │ │ Zustand Stores │
984
+ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
985
+ │ │ │ userDataStore│ │hyperliquid │ │ userSelection│ │
986
+ │ │ │ (auth, pos) │ │ DataStore │ │ (UI state) │ │
987
+ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │
988
+ │ └─────────────────────────────────────────────────────────────┤
989
+ │ │ │ │
990
+ │ ▼ ▼ │
991
+ │ ┌─────────────────────────────────────────────────────────────┤
992
+ │ │ React Hooks │
993
+ │ │ usePosition, useOrders, useMarket, useAuth, ... │
994
+ │ └─────────────────────────────────────────────────────────────┤
995
+ └─────────────────────────────────────────────────────────────────┘
996
+ ```
997
+
998
+ ### Available Scripts
999
+
1000
+ | Script | Description |
1001
+ |--------|-------------|
1002
+ | `yarn build` | Build the SDK for production |
1003
+ | `yarn dev` | Start development mode with watch |
1004
+ | `yarn type-check` | Run TypeScript type checking |
1005
+ | `yarn clean` | Remove build artifacts |
1006
+ | `yarn copy-to-node-modules` | Copy build to parent node_modules (for local development) |
1007
+
1008
+ ### Code Style
1009
+
1010
+ - **TypeScript**: Strict mode enabled
1011
+ - **Exports**: ESM only (no CommonJS)
1012
+ - **React**: Functional components with hooks
1013
+ - **State**: Zustand for global state
1014
+ - **API Calls**: Axios with interceptors
1015
+
1016
+ ### Adding a New Hook
1017
+
1018
+ 1. Create the hook file in `src/hooks/`:
1019
+
1020
+ ```tsx
1021
+ // src/hooks/useMyFeature.ts
1022
+ import { useCallback } from 'react';
1023
+ import { useUserData } from '../store/userDataStore';
1024
+ import { usePearHyperliquid } from '../provider';
1025
+
1026
+ export function useMyFeature() {
1027
+ const { apiBaseUrl } = usePearHyperliquid();
1028
+ const address = useUserData((state) => state.address);
1029
+
1030
+ const myFunction = useCallback(async () => {
1031
+ // Implementation
1032
+ }, [apiBaseUrl, address]);
1033
+
1034
+ return { myFunction };
1035
+ }
1036
+ ```
1037
+
1038
+ 2. Export from `src/hooks/index.ts`:
1039
+
1040
+ ```tsx
1041
+ export * from './useMyFeature';
1042
+ ```
1043
+
1044
+ ### Adding a New Client Function
1045
+
1046
+ 1. Create or update the client file in `src/clients/`:
1047
+
1048
+ ```tsx
1049
+ // src/clients/myFeature.ts
1050
+ import { apiClient } from '../utils/http';
1051
+ import type { ApiResponse } from '../types';
1052
+
1053
+ export interface MyRequestPayload {
1054
+ // ...
1055
+ }
1056
+
1057
+ export interface MyResponseDto {
1058
+ // ...
1059
+ }
1060
+
1061
+ export async function myApiCall(
1062
+ baseUrl: string,
1063
+ payload: MyRequestPayload
1064
+ ): Promise<ApiResponse<MyResponseDto>> {
1065
+ const response = await apiClient.post(`${baseUrl}/my-endpoint`, payload);
1066
+ return response;
1067
+ }
1068
+ ```
1069
+
1070
+ 2. Export from `src/index.ts`:
1071
+
1072
+ ```tsx
1073
+ export * from './clients/myFeature';
1074
+ ```
1075
+
1076
+ ### Adding New Types
1077
+
1078
+ Add types to `src/types.ts` and export them from `src/index.ts`:
1079
+
1080
+ ```tsx
1081
+ // src/types.ts
1082
+ export interface MyNewType {
1083
+ // ...
1084
+ }
1085
+
1086
+ // src/index.ts
1087
+ export type { MyNewType } from './types';
1088
+ ```
1089
+
1090
+ ### Building
1091
+
1092
+ ```bash
1093
+ # Production build
1094
+ yarn build
1095
+
1096
+ # Type checking only
1097
+ yarn type-check
1098
+ ```
1099
+
1100
+ ### Publishing
1101
+
1102
+ 1. Update version in `package.json`
1103
+ 2. Build the package: `yarn build`
1104
+ 3. Publish to npm: `npm publish`
1105
+
1106
+ The package is published to npm as `@pear-protocol/hyperliquid-sdk`.
1107
+
1108
+ ### Key Design Patterns
1109
+
1110
+ **Composition Pattern**: Multiple stores compose to create computed state. For example, `usePosition()` combines data from `userDataStore`, `hyperliquidDataStore`, and computes enriched position data.
1111
+
1112
+ **Selector Pattern**: Zustand selectors enable granular subscriptions. Only components using specific data re-render when it changes.
1113
+
1114
+ **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.
1115
+
1116
+ **Lazy Initialization**: WebSocket connections wait for `perpMetaAssets` to be available before connecting, preventing premature subscriptions.
1117
+
1118
+ ### Testing
1119
+
1120
+ When implementing tests:
1121
+
1122
+ 1. Use React Testing Library for hook testing
1123
+ 2. Mock WebSocket connections for real-time data tests
1124
+ 3. Mock API responses with MSW or similar
1125
+
1126
+ ### Commit Guidelines
1127
+
1128
+ - Use conventional commits format
1129
+ - Keep commits focused and atomic
1130
+ - Include relevant issue references
1131
+
1132
+ ---
1133
+
1134
+ ## License
1135
+
1136
+ MIT License - see [LICENSE](LICENSE) for details.
1137
+
1138
+ ## Support
1139
+
1140
+ - GitHub Issues: [github.com/pear-protocol/hyperliquid/issues](https://github.com/pear-protocol/hyperliquid/issues)
1141
+ - Documentation: [docs.pearprotocol.io](https://docs.pearprotocol.io)