@pear-protocol/hyperliquid-sdk 0.0.10 → 0.0.11
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/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useTokenSelection.d.ts +33 -0
- package/dist/index.d.ts +111 -2
- package/dist/index.esm.js +472 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +473 -1
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +15 -1
- package/dist/types.d.ts +31 -0
- package/dist/utils/conflict-detector.d.ts +14 -0
- package/dist/utils/token-metadata-extractor.d.ts +29 -0
- package/package.json +1 -1
package/dist/hooks/index.d.ts
CHANGED
|
@@ -2,3 +2,5 @@ export { useAddress } from './useAddress';
|
|
|
2
2
|
export { useTradeHistories, useOpenPositions, useOpenOrders, useAccountSummary } from './useTrading';
|
|
3
3
|
export { useCalculatedOpenPositions } from './useCalculatedPositions';
|
|
4
4
|
export { useCalculatedAccountSummary } from './useCalculatedAccountSummary';
|
|
5
|
+
export { useTokenSelection } from './useTokenSelection';
|
|
6
|
+
export type { TokenSelectorConfig, UseTokenSelectionReturn } from './useTokenSelection';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { TokenSelection, TokenConflict } from '../types';
|
|
2
|
+
import { TokenSelectorConfig } from '../provider';
|
|
3
|
+
export type { TokenSelectorConfig };
|
|
4
|
+
export interface UseTokenSelectionReturn {
|
|
5
|
+
longTokens: TokenSelection[];
|
|
6
|
+
shortTokens: TokenSelection[];
|
|
7
|
+
openTokenSelector: boolean;
|
|
8
|
+
selectorConfig: TokenSelectorConfig | null;
|
|
9
|
+
openConflictModal: boolean;
|
|
10
|
+
conflicts: TokenConflict[];
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
isPriceDataReady: boolean;
|
|
13
|
+
weightedRatio: number;
|
|
14
|
+
weightedRatio24h: number;
|
|
15
|
+
sumNetFunding: number;
|
|
16
|
+
maxLeverage: number;
|
|
17
|
+
minMargin: number;
|
|
18
|
+
setLongTokens: (tokens: TokenSelection[]) => void;
|
|
19
|
+
setShortTokens: (tokens: TokenSelection[]) => void;
|
|
20
|
+
updateTokenWeight: (isLong: boolean, index: number, newWeight: number) => void;
|
|
21
|
+
addToken: (isLong: boolean) => void;
|
|
22
|
+
removeToken: (isLong: boolean, index: number) => void;
|
|
23
|
+
handleTokenSelect: (selectedToken: string) => void;
|
|
24
|
+
setOpenTokenSelector: (open: boolean) => void;
|
|
25
|
+
setSelectorConfig: (config: TokenSelectorConfig | null) => void;
|
|
26
|
+
setOpenConflictModal: (open: boolean) => void;
|
|
27
|
+
setConflicts: (conflicts: TokenConflict[]) => void;
|
|
28
|
+
resetToDefaults: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Hook to access token selection state using provider's WebSocket data
|
|
32
|
+
*/
|
|
33
|
+
export declare const useTokenSelection: () => UseTokenSelectionReturn;
|
package/dist/index.d.ts
CHANGED
|
@@ -542,6 +542,37 @@ interface RawPositionDto {
|
|
|
542
542
|
longAssets: RawAssetDto[];
|
|
543
543
|
shortAssets: RawAssetDto[];
|
|
544
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Token metadata from WebData2 and AllMids
|
|
547
|
+
*/
|
|
548
|
+
interface TokenMetadata {
|
|
549
|
+
currentPrice: number;
|
|
550
|
+
prevDayPrice: number;
|
|
551
|
+
priceChange24h: number;
|
|
552
|
+
priceChange24hPercent: number;
|
|
553
|
+
netFunding: number;
|
|
554
|
+
maxLeverage: number;
|
|
555
|
+
markPrice: number;
|
|
556
|
+
oraclePrice: number;
|
|
557
|
+
openInterest: string;
|
|
558
|
+
dayVolume: string;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Enhanced token selection with weight and metadata for basket trading
|
|
562
|
+
*/
|
|
563
|
+
interface TokenSelection {
|
|
564
|
+
symbol: string;
|
|
565
|
+
weight: number;
|
|
566
|
+
metadata?: TokenMetadata;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Token conflict information for position conflicts
|
|
570
|
+
*/
|
|
571
|
+
interface TokenConflict {
|
|
572
|
+
symbol: string;
|
|
573
|
+
conflictType: 'long' | 'short';
|
|
574
|
+
conflictMessage: string;
|
|
575
|
+
}
|
|
545
576
|
|
|
546
577
|
/**
|
|
547
578
|
* Main SDK client for Pear Protocol Hyperliquid API integration
|
|
@@ -644,6 +675,10 @@ declare class PearMigrationSDK {
|
|
|
644
675
|
getBaseUrl(): string;
|
|
645
676
|
}
|
|
646
677
|
|
|
678
|
+
interface TokenSelectorConfig {
|
|
679
|
+
isLong: boolean;
|
|
680
|
+
index: number;
|
|
681
|
+
}
|
|
647
682
|
interface PearHyperliquidProviderProps {
|
|
648
683
|
config: PearHyperliquidConfig;
|
|
649
684
|
/**
|
|
@@ -715,6 +750,37 @@ declare const useCalculatedOpenPositions: (platformPositions: RawPositionDto[] |
|
|
|
715
750
|
*/
|
|
716
751
|
declare const useCalculatedAccountSummary: (platformAccountSummary: AccountSummaryResponseDto | null, platformOpenOrders: OpenLimitOrderDto[] | null, webData2: WebData2Response | null, agentWalletAddress?: string, agentWalletStatus?: string) => AccountSummaryResponseDto | null;
|
|
717
752
|
|
|
753
|
+
interface UseTokenSelectionReturn {
|
|
754
|
+
longTokens: TokenSelection[];
|
|
755
|
+
shortTokens: TokenSelection[];
|
|
756
|
+
openTokenSelector: boolean;
|
|
757
|
+
selectorConfig: TokenSelectorConfig | null;
|
|
758
|
+
openConflictModal: boolean;
|
|
759
|
+
conflicts: TokenConflict[];
|
|
760
|
+
isLoading: boolean;
|
|
761
|
+
isPriceDataReady: boolean;
|
|
762
|
+
weightedRatio: number;
|
|
763
|
+
weightedRatio24h: number;
|
|
764
|
+
sumNetFunding: number;
|
|
765
|
+
maxLeverage: number;
|
|
766
|
+
minMargin: number;
|
|
767
|
+
setLongTokens: (tokens: TokenSelection[]) => void;
|
|
768
|
+
setShortTokens: (tokens: TokenSelection[]) => void;
|
|
769
|
+
updateTokenWeight: (isLong: boolean, index: number, newWeight: number) => void;
|
|
770
|
+
addToken: (isLong: boolean) => void;
|
|
771
|
+
removeToken: (isLong: boolean, index: number) => void;
|
|
772
|
+
handleTokenSelect: (selectedToken: string) => void;
|
|
773
|
+
setOpenTokenSelector: (open: boolean) => void;
|
|
774
|
+
setSelectorConfig: (config: TokenSelectorConfig | null) => void;
|
|
775
|
+
setOpenConflictModal: (open: boolean) => void;
|
|
776
|
+
setConflicts: (conflicts: TokenConflict[]) => void;
|
|
777
|
+
resetToDefaults: () => void;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Hook to access token selection state using provider's WebSocket data
|
|
781
|
+
*/
|
|
782
|
+
declare const useTokenSelection: () => UseTokenSelectionReturn;
|
|
783
|
+
|
|
718
784
|
interface WebSocketData {
|
|
719
785
|
tradeHistories: TradeHistoryDataDto[] | null;
|
|
720
786
|
openPositions: RawPositionDto[] | null;
|
|
@@ -786,5 +852,48 @@ declare class AccountSummaryCalculator {
|
|
|
786
852
|
hasRealTimeData(): boolean;
|
|
787
853
|
}
|
|
788
854
|
|
|
789
|
-
|
|
790
|
-
|
|
855
|
+
/**
|
|
856
|
+
* Detects conflicts between selected tokens and existing positions
|
|
857
|
+
*/
|
|
858
|
+
declare class ConflictDetector {
|
|
859
|
+
/**
|
|
860
|
+
* Detects conflicts between token selections and open positions
|
|
861
|
+
* @param longTokens - Selected long tokens
|
|
862
|
+
* @param shortTokens - Selected short tokens
|
|
863
|
+
* @param openPositions - Current open positions from API
|
|
864
|
+
* @returns Array of detected conflicts
|
|
865
|
+
*/
|
|
866
|
+
static detectConflicts(longTokens: TokenSelection[], shortTokens: TokenSelection[], openPositions: any[] | null): TokenConflict[];
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* Extracts token metadata from WebData2 and AllMids data
|
|
871
|
+
*/
|
|
872
|
+
declare class TokenMetadataExtractor {
|
|
873
|
+
/**
|
|
874
|
+
* Extracts comprehensive token metadata
|
|
875
|
+
* @param symbol - Token symbol
|
|
876
|
+
* @param webData2 - WebData2 response containing asset context and universe data
|
|
877
|
+
* @param allMids - AllMids data containing current prices
|
|
878
|
+
* @returns TokenMetadata or null if token not found
|
|
879
|
+
*/
|
|
880
|
+
static extractTokenMetadata(symbol: string, webData2: WebData2Response | null, allMids: WsAllMidsData | null): TokenMetadata | null;
|
|
881
|
+
/**
|
|
882
|
+
* Extracts metadata for multiple tokens
|
|
883
|
+
* @param symbols - Array of token symbols
|
|
884
|
+
* @param webData2 - WebData2 response
|
|
885
|
+
* @param allMids - AllMids data
|
|
886
|
+
* @returns Record of symbol to TokenMetadata
|
|
887
|
+
*/
|
|
888
|
+
static extractMultipleTokensMetadata(symbols: string[], webData2: WebData2Response | null, allMids: WsAllMidsData | null): Record<string, TokenMetadata | null>;
|
|
889
|
+
/**
|
|
890
|
+
* Checks if token data is available in WebData2
|
|
891
|
+
* @param symbol - Token symbol
|
|
892
|
+
* @param webData2 - WebData2 response
|
|
893
|
+
* @returns boolean indicating if token exists in universe
|
|
894
|
+
*/
|
|
895
|
+
static isTokenAvailable(symbol: string, webData2: WebData2Response | null): boolean;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
export { AccountSummaryCalculator, ConflictDetector, PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, TokenMetadataExtractor, PearHyperliquidClient as default, useAccountSummary, useAddress, useCalculatedAccountSummary, useCalculatedOpenPositions, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, useTokenSelection, useTradeHistories };
|
|
899
|
+
export type { AccountSummaryResponseDto, AgentWalletDto, ApiErrorResponse, ApiResponse, AssetCtx, AssetInformationDetail, AssetPosition, BalanceSummaryDto, CrossMarginSummaryDto, CumFundingDto, MarginSummaryDto, MigrationHookState, MigrationHooks, OpenLimitOrderDto, OpenOrderV1Dto, OpenPositionDto, OpenPositionV1Dto, OrderAssetDto, OrderStatus, PearHyperliquidConfig, PnlDto, PositionAssetDetailDto, PositionSideDto, PositionSyncStatus, RawValueDto, SyncOpenOrderDto, SyncOpenOrderResponseDto, SyncOpenPositionDto, SyncOpenPositionResponseDto, SyncTradeHistoryDto, SyncTradeHistoryResponseDto, TokenConflict, TokenMetadata, TokenSelection, TokenSelectorConfig, TpSlDto, TradeHistoryAssetDataDto, TradeHistoryDataDto, TradeHistoryV1Dto, UniverseAsset, UseTokenSelectionReturn, WebData2Response, WebSocketChannel, WebSocketConnectionState, WebSocketDataMessage, WebSocketMessage, WebSocketResponse, WebSocketSubscribeMessage, WsAllMidsData };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import require$$0, { useState, useEffect, useRef, createContext, useMemo, useContext } from 'react';
|
|
2
|
+
import require$$0, { useState, useEffect, useRef, createContext, useMemo, useContext, useCallback } from 'react';
|
|
3
3
|
import require$$1 from 'react-dom';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -2877,6 +2877,23 @@ const useHyperliquidNativeWebSocket = ({ address }) => {
|
|
|
2877
2877
|
};
|
|
2878
2878
|
};
|
|
2879
2879
|
|
|
2880
|
+
const DEFAULT_TOKEN_SELECTION_STATE = {
|
|
2881
|
+
longTokens: [
|
|
2882
|
+
{ symbol: 'HYPE', weight: 25 },
|
|
2883
|
+
{ symbol: 'BTC', weight: 25 }
|
|
2884
|
+
],
|
|
2885
|
+
shortTokens: [
|
|
2886
|
+
{ symbol: 'AVAX', weight: 10 },
|
|
2887
|
+
{ symbol: 'SEI', weight: 10 },
|
|
2888
|
+
{ symbol: 'ADA', weight: 10 },
|
|
2889
|
+
{ symbol: 'TRUMP', weight: 10 },
|
|
2890
|
+
{ symbol: 'SUI', weight: 10 }
|
|
2891
|
+
],
|
|
2892
|
+
openTokenSelector: false,
|
|
2893
|
+
selectorConfig: null,
|
|
2894
|
+
openConflictModal: false,
|
|
2895
|
+
conflicts: [],
|
|
2896
|
+
};
|
|
2880
2897
|
const PearHyperliquidContext = createContext(undefined);
|
|
2881
2898
|
/**
|
|
2882
2899
|
* React Provider for PearHyperliquidClient
|
|
@@ -2886,6 +2903,8 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
|
|
|
2886
2903
|
const migrationSDK = useMemo(() => new PearMigrationSDK(client), [client]);
|
|
2887
2904
|
// Address state
|
|
2888
2905
|
const [address, setAddress] = useState(null);
|
|
2906
|
+
// Token selection state
|
|
2907
|
+
const [tokenSelection, setTokenSelection] = useState(DEFAULT_TOKEN_SELECTION_STATE);
|
|
2889
2908
|
// WebSocket connection and data (Pear API)
|
|
2890
2909
|
const { data, connectionStatus, isConnected, lastError } = useHyperliquidWebSocket({
|
|
2891
2910
|
wsUrl,
|
|
@@ -2915,7 +2934,10 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
|
|
|
2915
2934
|
// HyperLiquid native WebSocket data
|
|
2916
2935
|
webData2,
|
|
2917
2936
|
allMids,
|
|
2918
|
-
|
|
2937
|
+
// Token selection state
|
|
2938
|
+
tokenSelection,
|
|
2939
|
+
setTokenSelection,
|
|
2940
|
+
}), [client, migrationSDK, address, connectionStatus, isConnected, data, lastError, nativeConnectionStatus, nativeIsConnected, nativeLastError, webData2, allMids, tokenSelection, setTokenSelection]);
|
|
2919
2941
|
return (jsxRuntimeExports.jsx(PearHyperliquidContext.Provider, { value: contextValue, children: children }));
|
|
2920
2942
|
};
|
|
2921
2943
|
/**
|
|
@@ -3435,5 +3457,452 @@ const useAccountSummary = () => {
|
|
|
3435
3457
|
};
|
|
3436
3458
|
};
|
|
3437
3459
|
|
|
3438
|
-
|
|
3460
|
+
/**
|
|
3461
|
+
* Extracts token metadata from WebData2 and AllMids data
|
|
3462
|
+
*/
|
|
3463
|
+
class TokenMetadataExtractor {
|
|
3464
|
+
/**
|
|
3465
|
+
* Extracts comprehensive token metadata
|
|
3466
|
+
* @param symbol - Token symbol
|
|
3467
|
+
* @param webData2 - WebData2 response containing asset context and universe data
|
|
3468
|
+
* @param allMids - AllMids data containing current prices
|
|
3469
|
+
* @returns TokenMetadata or null if token not found
|
|
3470
|
+
*/
|
|
3471
|
+
static extractTokenMetadata(symbol, webData2, allMids) {
|
|
3472
|
+
if (!webData2 || !allMids) {
|
|
3473
|
+
return null;
|
|
3474
|
+
}
|
|
3475
|
+
// Find token index in universe
|
|
3476
|
+
const universeIndex = webData2.meta.universe.findIndex(asset => asset.name === symbol);
|
|
3477
|
+
if (universeIndex === -1) {
|
|
3478
|
+
return null;
|
|
3479
|
+
}
|
|
3480
|
+
const universeAsset = webData2.meta.universe[universeIndex];
|
|
3481
|
+
const assetCtx = webData2.assetCtxs[universeIndex];
|
|
3482
|
+
if (!assetCtx) {
|
|
3483
|
+
return null;
|
|
3484
|
+
}
|
|
3485
|
+
// Get current price from allMids
|
|
3486
|
+
const currentPriceStr = allMids.mids[symbol];
|
|
3487
|
+
const currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
3488
|
+
// Get previous day price
|
|
3489
|
+
const prevDayPrice = parseFloat(assetCtx.prevDayPx);
|
|
3490
|
+
// Calculate 24h price change
|
|
3491
|
+
const priceChange24h = currentPrice - prevDayPrice;
|
|
3492
|
+
const priceChange24hPercent = prevDayPrice !== 0 ? (priceChange24h / prevDayPrice) * 100 : 0;
|
|
3493
|
+
// Parse other metadata
|
|
3494
|
+
const netFunding = parseFloat(assetCtx.funding);
|
|
3495
|
+
const markPrice = parseFloat(assetCtx.markPx);
|
|
3496
|
+
const oraclePrice = parseFloat(assetCtx.oraclePx);
|
|
3497
|
+
return {
|
|
3498
|
+
currentPrice,
|
|
3499
|
+
prevDayPrice,
|
|
3500
|
+
priceChange24h,
|
|
3501
|
+
priceChange24hPercent,
|
|
3502
|
+
netFunding,
|
|
3503
|
+
maxLeverage: universeAsset.maxLeverage,
|
|
3504
|
+
markPrice,
|
|
3505
|
+
oraclePrice,
|
|
3506
|
+
openInterest: assetCtx.openInterest,
|
|
3507
|
+
dayVolume: assetCtx.dayNtlVlm,
|
|
3508
|
+
};
|
|
3509
|
+
}
|
|
3510
|
+
/**
|
|
3511
|
+
* Extracts metadata for multiple tokens
|
|
3512
|
+
* @param symbols - Array of token symbols
|
|
3513
|
+
* @param webData2 - WebData2 response
|
|
3514
|
+
* @param allMids - AllMids data
|
|
3515
|
+
* @returns Record of symbol to TokenMetadata
|
|
3516
|
+
*/
|
|
3517
|
+
static extractMultipleTokensMetadata(symbols, webData2, allMids) {
|
|
3518
|
+
const result = {};
|
|
3519
|
+
for (const symbol of symbols) {
|
|
3520
|
+
result[symbol] = this.extractTokenMetadata(symbol, webData2, allMids);
|
|
3521
|
+
}
|
|
3522
|
+
return result;
|
|
3523
|
+
}
|
|
3524
|
+
/**
|
|
3525
|
+
* Checks if token data is available in WebData2
|
|
3526
|
+
* @param symbol - Token symbol
|
|
3527
|
+
* @param webData2 - WebData2 response
|
|
3528
|
+
* @returns boolean indicating if token exists in universe
|
|
3529
|
+
*/
|
|
3530
|
+
static isTokenAvailable(symbol, webData2) {
|
|
3531
|
+
if (!webData2)
|
|
3532
|
+
return false;
|
|
3533
|
+
return webData2.meta.universe.some(asset => asset.name === symbol);
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3537
|
+
/**
|
|
3538
|
+
* Hook to access token selection state using provider's WebSocket data
|
|
3539
|
+
*/
|
|
3540
|
+
const useTokenSelection = () => {
|
|
3541
|
+
var _a;
|
|
3542
|
+
const context = useContext(PearHyperliquidContext);
|
|
3543
|
+
if (!context) {
|
|
3544
|
+
throw new Error('useTokenSelection must be used within PearHyperliquidProvider');
|
|
3545
|
+
}
|
|
3546
|
+
const { webData2, allMids, tokenSelection, setTokenSelection } = context;
|
|
3547
|
+
// Loading states
|
|
3548
|
+
const isPriceDataReady = useMemo(() => {
|
|
3549
|
+
return !!(webData2 && allMids);
|
|
3550
|
+
}, [webData2, allMids]);
|
|
3551
|
+
const isLoading = useMemo(() => {
|
|
3552
|
+
// Check if any tokens have missing metadata when price data is available
|
|
3553
|
+
if (!isPriceDataReady)
|
|
3554
|
+
return true;
|
|
3555
|
+
const allTokens = [...tokenSelection.longTokens, ...tokenSelection.shortTokens];
|
|
3556
|
+
if (allTokens.length === 0)
|
|
3557
|
+
return false;
|
|
3558
|
+
// Loading if any token is missing metadata
|
|
3559
|
+
return allTokens.some(token => !token.metadata);
|
|
3560
|
+
}, [isPriceDataReady, tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3561
|
+
// Auto-update token metadata when WebSocket data changes
|
|
3562
|
+
useEffect(() => {
|
|
3563
|
+
if (!webData2 || !allMids)
|
|
3564
|
+
return;
|
|
3565
|
+
const allTokenSymbols = [...tokenSelection.longTokens, ...tokenSelection.shortTokens].map(t => t.symbol);
|
|
3566
|
+
if (allTokenSymbols.length === 0)
|
|
3567
|
+
return;
|
|
3568
|
+
const metadataMap = TokenMetadataExtractor.extractMultipleTokensMetadata(allTokenSymbols, webData2, allMids);
|
|
3569
|
+
setTokenSelection(prev => ({
|
|
3570
|
+
...prev,
|
|
3571
|
+
longTokens: prev.longTokens.map(token => ({
|
|
3572
|
+
...token,
|
|
3573
|
+
metadata: metadataMap[token.symbol] || undefined
|
|
3574
|
+
})),
|
|
3575
|
+
shortTokens: prev.shortTokens.map(token => ({
|
|
3576
|
+
...token,
|
|
3577
|
+
metadata: metadataMap[token.symbol] || undefined
|
|
3578
|
+
}))
|
|
3579
|
+
}));
|
|
3580
|
+
}, [webData2, allMids, setTokenSelection]);
|
|
3581
|
+
// Calculate weighted ratio: LONG^WEIGHT * SHORT^-WEIGHT
|
|
3582
|
+
const weightedRatio = useMemo(() => {
|
|
3583
|
+
let longProduct = 1;
|
|
3584
|
+
let shortProduct = 1;
|
|
3585
|
+
// Calculate long side product: PRICE^(WEIGHT/100)
|
|
3586
|
+
tokenSelection.longTokens.forEach(token => {
|
|
3587
|
+
var _a;
|
|
3588
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.currentPrice) && token.weight > 0) {
|
|
3589
|
+
const weightFactor = token.weight / 100;
|
|
3590
|
+
longProduct *= Math.pow(token.metadata.currentPrice, weightFactor);
|
|
3591
|
+
}
|
|
3592
|
+
});
|
|
3593
|
+
// Calculate short side product: PRICE^-(WEIGHT/100)
|
|
3594
|
+
tokenSelection.shortTokens.forEach(token => {
|
|
3595
|
+
var _a;
|
|
3596
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.currentPrice) && token.weight > 0) {
|
|
3597
|
+
const weightFactor = token.weight / 100;
|
|
3598
|
+
shortProduct *= Math.pow(token.metadata.currentPrice, -weightFactor);
|
|
3599
|
+
}
|
|
3600
|
+
});
|
|
3601
|
+
return longProduct * shortProduct;
|
|
3602
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3603
|
+
// Calculate 24h weighted ratio using previous day prices
|
|
3604
|
+
const weightedRatio24h = useMemo(() => {
|
|
3605
|
+
let longProduct = 1;
|
|
3606
|
+
let shortProduct = 1;
|
|
3607
|
+
// Calculate long side product: PREV_PRICE^(WEIGHT/100)
|
|
3608
|
+
tokenSelection.longTokens.forEach(token => {
|
|
3609
|
+
var _a;
|
|
3610
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.prevDayPrice) && token.weight > 0) {
|
|
3611
|
+
const weightFactor = token.weight / 100;
|
|
3612
|
+
longProduct *= Math.pow(token.metadata.prevDayPrice, weightFactor);
|
|
3613
|
+
}
|
|
3614
|
+
});
|
|
3615
|
+
// Calculate short side product: PREV_PRICE^-(WEIGHT/100)
|
|
3616
|
+
tokenSelection.shortTokens.forEach(token => {
|
|
3617
|
+
var _a;
|
|
3618
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.prevDayPrice) && token.weight > 0) {
|
|
3619
|
+
const weightFactor = token.weight / 100;
|
|
3620
|
+
shortProduct *= Math.pow(token.metadata.prevDayPrice, -weightFactor);
|
|
3621
|
+
}
|
|
3622
|
+
});
|
|
3623
|
+
return longProduct * shortProduct;
|
|
3624
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3625
|
+
// Calculate sum of weighted net funding
|
|
3626
|
+
const sumNetFunding = useMemo(() => {
|
|
3627
|
+
let totalFunding = 0;
|
|
3628
|
+
// Add long funding weighted by allocation
|
|
3629
|
+
tokenSelection.longTokens.forEach(token => {
|
|
3630
|
+
var _a;
|
|
3631
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.netFunding) && token.weight > 0) {
|
|
3632
|
+
const weightFactor = token.weight / 100;
|
|
3633
|
+
totalFunding += token.metadata.netFunding * weightFactor;
|
|
3634
|
+
}
|
|
3635
|
+
});
|
|
3636
|
+
// Subtract short funding weighted by allocation (since we're short)
|
|
3637
|
+
tokenSelection.shortTokens.forEach(token => {
|
|
3638
|
+
var _a;
|
|
3639
|
+
if (((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.netFunding) && token.weight > 0) {
|
|
3640
|
+
const weightFactor = token.weight / 100;
|
|
3641
|
+
totalFunding -= token.metadata.netFunding * weightFactor;
|
|
3642
|
+
}
|
|
3643
|
+
});
|
|
3644
|
+
return totalFunding;
|
|
3645
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3646
|
+
// Calculate max leverage (minimum of all token maxLeverages)
|
|
3647
|
+
const maxLeverage = useMemo(() => {
|
|
3648
|
+
var _a;
|
|
3649
|
+
if (!((_a = webData2 === null || webData2 === void 0 ? void 0 : webData2.meta) === null || _a === void 0 ? void 0 : _a.universe))
|
|
3650
|
+
return 0;
|
|
3651
|
+
const allTokenSymbols = [...tokenSelection.longTokens, ...tokenSelection.shortTokens].map(t => t.symbol);
|
|
3652
|
+
if (allTokenSymbols.length === 0)
|
|
3653
|
+
return 0;
|
|
3654
|
+
let minLeverage = Infinity;
|
|
3655
|
+
allTokenSymbols.forEach(symbol => {
|
|
3656
|
+
const tokenUniverse = webData2.meta.universe.find(u => u.name === symbol);
|
|
3657
|
+
if (tokenUniverse === null || tokenUniverse === void 0 ? void 0 : tokenUniverse.maxLeverage) {
|
|
3658
|
+
minLeverage = Math.min(minLeverage, tokenUniverse.maxLeverage);
|
|
3659
|
+
}
|
|
3660
|
+
});
|
|
3661
|
+
return minLeverage === Infinity ? 0 : minLeverage;
|
|
3662
|
+
}, [(_a = webData2 === null || webData2 === void 0 ? void 0 : webData2.meta) === null || _a === void 0 ? void 0 : _a.universe, tokenSelection.longTokens, tokenSelection.shortTokens]);
|
|
3663
|
+
// Calculate minimum margin (10 * total number of tokens)
|
|
3664
|
+
const minMargin = useMemo(() => {
|
|
3665
|
+
const totalTokenCount = tokenSelection.longTokens.length + tokenSelection.shortTokens.length;
|
|
3666
|
+
return 10 * totalTokenCount;
|
|
3667
|
+
}, [tokenSelection.longTokens.length, tokenSelection.shortTokens.length]);
|
|
3668
|
+
// Actions
|
|
3669
|
+
const setLongTokens = useCallback((tokens) => {
|
|
3670
|
+
setTokenSelection(prev => ({ ...prev, longTokens: tokens }));
|
|
3671
|
+
}, [setTokenSelection]);
|
|
3672
|
+
const setShortTokens = useCallback((tokens) => {
|
|
3673
|
+
setTokenSelection(prev => ({ ...prev, shortTokens: tokens }));
|
|
3674
|
+
}, [setTokenSelection]);
|
|
3675
|
+
const updateTokenWeight = useCallback((isLong, index, newWeight) => {
|
|
3676
|
+
const clampedWeight = Math.max(1, Math.min(100, newWeight));
|
|
3677
|
+
setTokenSelection(prev => {
|
|
3678
|
+
var _a, _b;
|
|
3679
|
+
const currentLongTotal = prev.longTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3680
|
+
const currentShortTotal = prev.shortTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3681
|
+
if (isLong) {
|
|
3682
|
+
const oldWeight = ((_a = prev.longTokens[index]) === null || _a === void 0 ? void 0 : _a.weight) || 0;
|
|
3683
|
+
const weightDiff = clampedWeight - oldWeight;
|
|
3684
|
+
const newLongTotal = currentLongTotal + weightDiff;
|
|
3685
|
+
if (newLongTotal + currentShortTotal > 100) {
|
|
3686
|
+
const maxAllowedWeight = Math.max(1, 100 - currentShortTotal - (currentLongTotal - oldWeight));
|
|
3687
|
+
const updated = [...prev.longTokens];
|
|
3688
|
+
updated[index] = { ...updated[index], weight: maxAllowedWeight };
|
|
3689
|
+
return { ...prev, longTokens: updated };
|
|
3690
|
+
}
|
|
3691
|
+
else {
|
|
3692
|
+
const updated = [...prev.longTokens];
|
|
3693
|
+
updated[index] = { ...updated[index], weight: clampedWeight };
|
|
3694
|
+
return { ...prev, longTokens: updated };
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
else {
|
|
3698
|
+
const oldWeight = ((_b = prev.shortTokens[index]) === null || _b === void 0 ? void 0 : _b.weight) || 0;
|
|
3699
|
+
const weightDiff = clampedWeight - oldWeight;
|
|
3700
|
+
const newShortTotal = currentShortTotal + weightDiff;
|
|
3701
|
+
if (currentLongTotal + newShortTotal > 100) {
|
|
3702
|
+
const maxAllowedWeight = Math.max(1, 100 - currentLongTotal - (currentShortTotal - oldWeight));
|
|
3703
|
+
const updated = [...prev.shortTokens];
|
|
3704
|
+
updated[index] = { ...updated[index], weight: maxAllowedWeight };
|
|
3705
|
+
return { ...prev, shortTokens: updated };
|
|
3706
|
+
}
|
|
3707
|
+
else {
|
|
3708
|
+
const updated = [...prev.shortTokens];
|
|
3709
|
+
updated[index] = { ...updated[index], weight: clampedWeight };
|
|
3710
|
+
return { ...prev, shortTokens: updated };
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
});
|
|
3714
|
+
}, [setTokenSelection]);
|
|
3715
|
+
const addToken = useCallback((isLong) => {
|
|
3716
|
+
const currentTokens = isLong ? tokenSelection.longTokens : tokenSelection.shortTokens;
|
|
3717
|
+
const newIndex = currentTokens.length;
|
|
3718
|
+
setTokenSelection(prev => ({
|
|
3719
|
+
...prev,
|
|
3720
|
+
selectorConfig: { isLong, index: newIndex },
|
|
3721
|
+
openTokenSelector: true,
|
|
3722
|
+
}));
|
|
3723
|
+
}, [tokenSelection.longTokens, tokenSelection.shortTokens, setTokenSelection]);
|
|
3724
|
+
const removeToken = useCallback((isLong, index) => {
|
|
3725
|
+
setTokenSelection(prev => {
|
|
3726
|
+
if (isLong) {
|
|
3727
|
+
const updated = prev.longTokens.filter((_, i) => i !== index);
|
|
3728
|
+
return { ...prev, longTokens: updated };
|
|
3729
|
+
}
|
|
3730
|
+
else {
|
|
3731
|
+
const updated = prev.shortTokens.filter((_, i) => i !== index);
|
|
3732
|
+
return { ...prev, shortTokens: updated };
|
|
3733
|
+
}
|
|
3734
|
+
});
|
|
3735
|
+
}, [setTokenSelection]);
|
|
3736
|
+
const setOpenTokenSelector = useCallback((open) => {
|
|
3737
|
+
setTokenSelection(prev => ({ ...prev, openTokenSelector: open }));
|
|
3738
|
+
}, [setTokenSelection]);
|
|
3739
|
+
const setSelectorConfig = useCallback((config) => {
|
|
3740
|
+
setTokenSelection(prev => ({ ...prev, selectorConfig: config }));
|
|
3741
|
+
}, [setTokenSelection]);
|
|
3742
|
+
const setOpenConflictModal = useCallback((open) => {
|
|
3743
|
+
setTokenSelection(prev => ({ ...prev, openConflictModal: open }));
|
|
3744
|
+
}, [setTokenSelection]);
|
|
3745
|
+
const setConflicts = useCallback((conflicts) => {
|
|
3746
|
+
setTokenSelection(prev => ({ ...prev, conflicts }));
|
|
3747
|
+
}, [setTokenSelection]);
|
|
3748
|
+
const resetToDefaults = useCallback(() => {
|
|
3749
|
+
setTokenSelection(prev => ({
|
|
3750
|
+
...prev,
|
|
3751
|
+
longTokens: [
|
|
3752
|
+
{ symbol: 'HYPE', weight: 25 },
|
|
3753
|
+
{ symbol: 'BTC', weight: 25 }
|
|
3754
|
+
],
|
|
3755
|
+
shortTokens: [
|
|
3756
|
+
{ symbol: 'AVAX', weight: 10 },
|
|
3757
|
+
{ symbol: 'SEI', weight: 10 },
|
|
3758
|
+
{ symbol: 'ADA', weight: 10 },
|
|
3759
|
+
{ symbol: 'TRUMP', weight: 10 },
|
|
3760
|
+
{ symbol: 'SUI', weight: 10 }
|
|
3761
|
+
],
|
|
3762
|
+
openTokenSelector: false,
|
|
3763
|
+
selectorConfig: null,
|
|
3764
|
+
openConflictModal: false,
|
|
3765
|
+
}));
|
|
3766
|
+
}, [setTokenSelection]);
|
|
3767
|
+
const handleTokenSelect = useCallback((selectedToken) => {
|
|
3768
|
+
if (!tokenSelection.selectorConfig)
|
|
3769
|
+
return;
|
|
3770
|
+
const { isLong, index } = tokenSelection.selectorConfig;
|
|
3771
|
+
const existingTokens = isLong ? tokenSelection.longTokens : tokenSelection.shortTokens;
|
|
3772
|
+
// Check if token already exists
|
|
3773
|
+
if (existingTokens.some(t => t.symbol === selectedToken))
|
|
3774
|
+
return;
|
|
3775
|
+
// Get metadata for new token
|
|
3776
|
+
const metadata = TokenMetadataExtractor.extractTokenMetadata(selectedToken, webData2, allMids);
|
|
3777
|
+
setTokenSelection(prev => {
|
|
3778
|
+
if (index >= existingTokens.length) {
|
|
3779
|
+
// Adding new token - calculate safe weight
|
|
3780
|
+
const currentLongTotal = prev.longTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3781
|
+
const currentShortTotal = prev.shortTokens.reduce((sum, token) => sum + token.weight, 0);
|
|
3782
|
+
const currentTotal = currentLongTotal + currentShortTotal;
|
|
3783
|
+
const maxAvailableWeight = Math.max(1, 100 - currentTotal);
|
|
3784
|
+
const safeWeight = Math.min(20, maxAvailableWeight);
|
|
3785
|
+
const newToken = {
|
|
3786
|
+
symbol: selectedToken,
|
|
3787
|
+
weight: safeWeight,
|
|
3788
|
+
metadata: metadata || undefined
|
|
3789
|
+
};
|
|
3790
|
+
if (isLong) {
|
|
3791
|
+
return { ...prev, longTokens: [...prev.longTokens, newToken] };
|
|
3792
|
+
}
|
|
3793
|
+
else {
|
|
3794
|
+
return { ...prev, shortTokens: [...prev.shortTokens, newToken] };
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
else {
|
|
3798
|
+
// Replacing existing token
|
|
3799
|
+
if (isLong) {
|
|
3800
|
+
const updated = [...prev.longTokens];
|
|
3801
|
+
updated[index] = {
|
|
3802
|
+
...updated[index],
|
|
3803
|
+
symbol: selectedToken,
|
|
3804
|
+
metadata: metadata || undefined
|
|
3805
|
+
};
|
|
3806
|
+
return { ...prev, longTokens: updated };
|
|
3807
|
+
}
|
|
3808
|
+
else {
|
|
3809
|
+
const updated = [...prev.shortTokens];
|
|
3810
|
+
updated[index] = {
|
|
3811
|
+
...updated[index],
|
|
3812
|
+
symbol: selectedToken,
|
|
3813
|
+
metadata: metadata || undefined
|
|
3814
|
+
};
|
|
3815
|
+
return { ...prev, shortTokens: updated };
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
});
|
|
3819
|
+
}, [tokenSelection.selectorConfig, tokenSelection.longTokens, tokenSelection.shortTokens, webData2, allMids, setTokenSelection]);
|
|
3820
|
+
// updateTokenMetadata is now handled automatically by the useEffect above
|
|
3821
|
+
return {
|
|
3822
|
+
// State
|
|
3823
|
+
longTokens: tokenSelection.longTokens,
|
|
3824
|
+
shortTokens: tokenSelection.shortTokens,
|
|
3825
|
+
openTokenSelector: tokenSelection.openTokenSelector,
|
|
3826
|
+
selectorConfig: tokenSelection.selectorConfig,
|
|
3827
|
+
openConflictModal: tokenSelection.openConflictModal,
|
|
3828
|
+
conflicts: tokenSelection.conflicts,
|
|
3829
|
+
// Loading states
|
|
3830
|
+
isLoading,
|
|
3831
|
+
isPriceDataReady,
|
|
3832
|
+
// Calculated values
|
|
3833
|
+
weightedRatio,
|
|
3834
|
+
weightedRatio24h,
|
|
3835
|
+
sumNetFunding,
|
|
3836
|
+
maxLeverage,
|
|
3837
|
+
minMargin,
|
|
3838
|
+
// Actions
|
|
3839
|
+
setLongTokens,
|
|
3840
|
+
setShortTokens,
|
|
3841
|
+
updateTokenWeight,
|
|
3842
|
+
addToken,
|
|
3843
|
+
removeToken,
|
|
3844
|
+
handleTokenSelect,
|
|
3845
|
+
setOpenTokenSelector,
|
|
3846
|
+
setSelectorConfig,
|
|
3847
|
+
setOpenConflictModal,
|
|
3848
|
+
setConflicts,
|
|
3849
|
+
resetToDefaults,
|
|
3850
|
+
};
|
|
3851
|
+
};
|
|
3852
|
+
|
|
3853
|
+
/**
|
|
3854
|
+
* Detects conflicts between selected tokens and existing positions
|
|
3855
|
+
*/
|
|
3856
|
+
class ConflictDetector {
|
|
3857
|
+
/**
|
|
3858
|
+
* Detects conflicts between token selections and open positions
|
|
3859
|
+
* @param longTokens - Selected long tokens
|
|
3860
|
+
* @param shortTokens - Selected short tokens
|
|
3861
|
+
* @param openPositions - Current open positions from API
|
|
3862
|
+
* @returns Array of detected conflicts
|
|
3863
|
+
*/
|
|
3864
|
+
static detectConflicts(longTokens, shortTokens, openPositions) {
|
|
3865
|
+
const detectedConflicts = [];
|
|
3866
|
+
if (!openPositions) {
|
|
3867
|
+
return detectedConflicts;
|
|
3868
|
+
}
|
|
3869
|
+
// Check long tokens against existing short positions
|
|
3870
|
+
longTokens.forEach((token) => {
|
|
3871
|
+
const existingShortPosition = openPositions.find((pos) => {
|
|
3872
|
+
var _a;
|
|
3873
|
+
// Check multiple possible property names and side values
|
|
3874
|
+
const symbol = pos.coin || pos.symbol || pos.asset;
|
|
3875
|
+
const side = (_a = pos.side) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
3876
|
+
return symbol === token.symbol && (side === 'short' || side === 'sell');
|
|
3877
|
+
});
|
|
3878
|
+
if (existingShortPosition) {
|
|
3879
|
+
detectedConflicts.push({
|
|
3880
|
+
symbol: token.symbol,
|
|
3881
|
+
conflictType: 'short',
|
|
3882
|
+
conflictMessage: `${token.symbol} Long conflicts with existing ${token.symbol} Short position`
|
|
3883
|
+
});
|
|
3884
|
+
}
|
|
3885
|
+
});
|
|
3886
|
+
// Check short tokens against existing long positions
|
|
3887
|
+
shortTokens.forEach((token) => {
|
|
3888
|
+
const existingLongPosition = openPositions.find((pos) => {
|
|
3889
|
+
var _a;
|
|
3890
|
+
// Check multiple possible property names and side values
|
|
3891
|
+
const symbol = pos.coin || pos.symbol || pos.asset;
|
|
3892
|
+
const side = (_a = pos.side) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
3893
|
+
return symbol === token.symbol && (side === 'long' || side === 'buy');
|
|
3894
|
+
});
|
|
3895
|
+
if (existingLongPosition) {
|
|
3896
|
+
detectedConflicts.push({
|
|
3897
|
+
symbol: token.symbol,
|
|
3898
|
+
conflictType: 'long',
|
|
3899
|
+
conflictMessage: `${token.symbol} Short conflicts with existing ${token.symbol} Long position`
|
|
3900
|
+
});
|
|
3901
|
+
}
|
|
3902
|
+
});
|
|
3903
|
+
return detectedConflicts;
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
|
|
3907
|
+
export { AccountSummaryCalculator, ConflictDetector, PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, TokenMetadataExtractor, PearHyperliquidClient as default, useAccountSummary, useAddress, useCalculatedAccountSummary, useCalculatedOpenPositions, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, useTokenSelection, useTradeHistories };
|
|
3439
3908
|
//# sourceMappingURL=index.esm.js.map
|