@pear-protocol/hyperliquid-sdk 0.0.60-beta-usdh-2 → 0.0.60-beta.10
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/clients/hyperliquid.d.ts +1 -1
- package/dist/clients/orders.d.ts +0 -41
- package/dist/clients/positions.d.ts +2 -2
- package/dist/clients/watchlist.d.ts +1 -1
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/useAuth.d.ts +6 -4
- package/dist/hooks/useMarketData.d.ts +7 -9
- package/dist/hooks/useWebData.d.ts +3 -21
- package/dist/index.d.ts +47 -179
- package/dist/index.js +269 -806
- package/dist/provider.d.ts +1 -1
- package/dist/store/historicalPriceDataStore.d.ts +12 -1
- package/dist/store/hyperliquidDataStore.d.ts +25 -1
- package/dist/store/marketDataStore.d.ts +10 -1
- package/dist/store/tokenSelectionMetadataStore.d.ts +2 -2
- package/dist/store/userDataStore.d.ts +30 -1
- package/dist/store/userSelection.d.ts +1 -1
- package/dist/types.d.ts +3 -38
- package/dist/utils/symbol-translator.d.ts +3 -32
- package/dist/utils/token-metadata-extractor.d.ts +5 -9
- package/package.json +3 -2
- package/dist/hooks/useSpotOrder.d.ts +0 -13
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useRef, useCallback, useEffect, useMemo, useContext, createContext } from 'react';
|
|
3
|
-
import { create } from 'zustand';
|
|
2
|
+
import React, { useState, useRef, useCallback, useEffect, useMemo, useContext, createContext } from 'react';
|
|
4
3
|
|
|
5
4
|
// Browser-compatible WebSocket ready state enum (mirrors native values)
|
|
6
5
|
var ReadyState;
|
|
@@ -11,10 +10,52 @@ var ReadyState;
|
|
|
11
10
|
ReadyState[ReadyState["CLOSED"] = 3] = "CLOSED";
|
|
12
11
|
})(ReadyState || (ReadyState = {}));
|
|
13
12
|
|
|
13
|
+
const createStoreImpl = (createState) => {
|
|
14
|
+
let state;
|
|
15
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
16
|
+
const setState = (partial, replace) => {
|
|
17
|
+
const nextState = typeof partial === "function" ? partial(state) : partial;
|
|
18
|
+
if (!Object.is(nextState, state)) {
|
|
19
|
+
const previousState = state;
|
|
20
|
+
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
|
|
21
|
+
listeners.forEach((listener) => listener(state, previousState));
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const getState = () => state;
|
|
25
|
+
const getInitialState = () => initialState;
|
|
26
|
+
const subscribe = (listener) => {
|
|
27
|
+
listeners.add(listener);
|
|
28
|
+
return () => listeners.delete(listener);
|
|
29
|
+
};
|
|
30
|
+
const api = { setState, getState, getInitialState, subscribe };
|
|
31
|
+
const initialState = state = createState(setState, getState, api);
|
|
32
|
+
return api;
|
|
33
|
+
};
|
|
34
|
+
const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
|
|
35
|
+
|
|
36
|
+
const identity = (arg) => arg;
|
|
37
|
+
function useStore(api, selector = identity) {
|
|
38
|
+
const slice = React.useSyncExternalStore(
|
|
39
|
+
api.subscribe,
|
|
40
|
+
React.useCallback(() => selector(api.getState()), [api, selector]),
|
|
41
|
+
React.useCallback(() => selector(api.getInitialState()), [api, selector])
|
|
42
|
+
);
|
|
43
|
+
React.useDebugValue(slice);
|
|
44
|
+
return slice;
|
|
45
|
+
}
|
|
46
|
+
const createImpl = (createState) => {
|
|
47
|
+
const api = createStore(createState);
|
|
48
|
+
const useBoundStore = (selector) => useStore(api, selector);
|
|
49
|
+
Object.assign(useBoundStore, api);
|
|
50
|
+
return useBoundStore;
|
|
51
|
+
};
|
|
52
|
+
const create = ((createState) => createState ? createImpl(createState) : createImpl);
|
|
53
|
+
|
|
14
54
|
const useUserData = create((set) => ({
|
|
15
55
|
accessToken: null,
|
|
16
56
|
refreshToken: null,
|
|
17
57
|
isAuthenticated: false,
|
|
58
|
+
isReady: false,
|
|
18
59
|
address: null,
|
|
19
60
|
tradeHistories: null,
|
|
20
61
|
rawOpenPositions: null,
|
|
@@ -26,17 +67,17 @@ const useUserData = create((set) => ({
|
|
|
26
67
|
setAccessToken: (token) => set({ accessToken: token }),
|
|
27
68
|
setRefreshToken: (token) => set({ refreshToken: token }),
|
|
28
69
|
setIsAuthenticated: (value) => set({ isAuthenticated: value }),
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
}
|
|
70
|
+
setIsReady: (value) => set({ isReady: value }),
|
|
71
|
+
setAddress: (address) => {
|
|
72
|
+
// if (typeof window !== "undefined") {
|
|
73
|
+
// if (address) {
|
|
74
|
+
// window.localStorage.setItem("address", address);
|
|
75
|
+
// } else {
|
|
76
|
+
// window.localStorage.removeItem("address");
|
|
77
|
+
// }
|
|
78
|
+
// }
|
|
79
|
+
set({ address });
|
|
80
|
+
},
|
|
40
81
|
setTradeHistories: (value) => set({ tradeHistories: value }),
|
|
41
82
|
setRawOpenPositions: (value) => set({ rawOpenPositions: value }),
|
|
42
83
|
setOpenOrders: (value) => set({ openOrders: value }),
|
|
@@ -47,6 +88,7 @@ const useUserData = create((set) => ({
|
|
|
47
88
|
accessToken: null,
|
|
48
89
|
refreshToken: null,
|
|
49
90
|
isAuthenticated: false,
|
|
91
|
+
isReady: false,
|
|
50
92
|
address: null,
|
|
51
93
|
tradeHistories: null,
|
|
52
94
|
rawOpenPositions: null,
|
|
@@ -71,71 +113,18 @@ const useMarketData = create((set) => ({
|
|
|
71
113
|
* Convert a full/prefixed symbol (e.g., "xyz:XYZ100") to a display symbol (e.g., "XYZ100").
|
|
72
114
|
*/
|
|
73
115
|
function toDisplaySymbol(symbol) {
|
|
74
|
-
const parts = symbol.split(
|
|
116
|
+
const parts = symbol.split(":");
|
|
75
117
|
return parts.length > 1 ? parts.slice(-1)[0] : symbol;
|
|
76
118
|
}
|
|
77
119
|
/**
|
|
78
120
|
* Convert a display symbol back to backend form using a provided map.
|
|
79
121
|
* If mapping is missing, returns the original symbol.
|
|
80
|
-
*
|
|
81
|
-
* @param
|
|
82
|
-
* @param hip3Assets map of display -> all full market names (e.g., "TSLA" -> ["xyz:TSLA", "flx:TSLA"])
|
|
122
|
+
* @param displaySymbol e.g., "XYZ100"
|
|
123
|
+
* @param displayToFull map of display -> full (e.g., "XYZ100" -> "xyz:XYZ100")
|
|
83
124
|
*/
|
|
84
|
-
function toBackendSymbol(displaySymbol,
|
|
85
|
-
const markets = hip3Assets.get(displaySymbol);
|
|
86
|
-
// Return first market if available, otherwise return original symbol
|
|
87
|
-
return markets && markets.length > 0 ? markets[0] : displaySymbol;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Convert a display symbol to backend form for a specific market prefix.
|
|
91
|
-
* This is useful when an asset is available on multiple markets (e.g., xyz:TSLA and flx:TSLA).
|
|
92
|
-
* @param displaySymbol e.g., "TSLA"
|
|
93
|
-
* @param marketPrefix e.g., "xyz" or "flx"
|
|
94
|
-
* @param hip3Assets map of display -> all full market names
|
|
95
|
-
* @returns Full market name if found, null if prefix not specified for multi-market asset, otherwise displaySymbol with prefix
|
|
96
|
-
*/
|
|
97
|
-
function toBackendSymbolWithMarket(displaySymbol, marketPrefix, hip3Assets) {
|
|
98
|
-
const availableMarkets = hip3Assets.get(displaySymbol);
|
|
99
|
-
if (!availableMarkets || availableMarkets.length === 0) {
|
|
100
|
-
// Not a HIP-3 asset, return as-is or with prefix if provided
|
|
101
|
-
return marketPrefix ? `${marketPrefix}:${displaySymbol}` : displaySymbol;
|
|
102
|
-
}
|
|
103
|
-
if (marketPrefix) {
|
|
104
|
-
// Find the market with the specified prefix
|
|
105
|
-
const targetMarket = availableMarkets.find((market) => market.toLowerCase().startsWith(`${marketPrefix.toLowerCase()}:`));
|
|
106
|
-
if (targetMarket) {
|
|
107
|
-
return targetMarket;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// No prefix specified or not found, return null to force explicit market selection
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Get all available markets for a display symbol.
|
|
115
|
-
* @param displaySymbol e.g., "TSLA"
|
|
116
|
-
* @param hip3Assets map of display -> all full market names
|
|
117
|
-
* @returns Array of full market names, e.g., ["xyz:TSLA", "flx:TSLA"]
|
|
118
|
-
*/
|
|
119
|
-
function getAvailableMarkets(displaySymbol, hip3Assets) {
|
|
125
|
+
function toBackendSymbol(displaySymbol, displayToFull) {
|
|
120
126
|
var _a;
|
|
121
|
-
return (_a =
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Extract the market prefix from a full market name.
|
|
125
|
-
* @param fullSymbol e.g., "xyz:TSLA"
|
|
126
|
-
* @returns The prefix (e.g., "xyz") or undefined if no prefix
|
|
127
|
-
*/
|
|
128
|
-
function getMarketPrefix(fullSymbol) {
|
|
129
|
-
const parts = fullSymbol.split(':');
|
|
130
|
-
return parts.length > 1 ? parts[0] : undefined;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Check if a symbol is a HIP-3 market (has a prefix).
|
|
134
|
-
* @param symbol e.g., "xyz:TSLA" or "TSLA"
|
|
135
|
-
* @returns true if the symbol has a market prefix
|
|
136
|
-
*/
|
|
137
|
-
function isHip3Market(symbol) {
|
|
138
|
-
return symbol.includes(':');
|
|
127
|
+
return (_a = displayToFull.get(displaySymbol)) !== null && _a !== void 0 ? _a : displaySymbol;
|
|
139
128
|
}
|
|
140
129
|
|
|
141
130
|
const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
@@ -371,11 +360,10 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
371
360
|
finalAtOICaps: null,
|
|
372
361
|
aggregatedClearingHouseState: null,
|
|
373
362
|
perpMetaAssets: null,
|
|
374
|
-
|
|
375
|
-
hip3MarketPrefixes: new Map(),
|
|
363
|
+
hip3DisplayToFull: new Map(),
|
|
376
364
|
setAllMids: (value) => set({ allMids: value }),
|
|
377
365
|
setActiveAssetData: (value) => set((state) => ({
|
|
378
|
-
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value
|
|
366
|
+
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value
|
|
379
367
|
})),
|
|
380
368
|
deleteActiveAssetData: (key) => {
|
|
381
369
|
set((state) => {
|
|
@@ -410,14 +398,13 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
410
398
|
activeAssetData: {
|
|
411
399
|
...state.activeAssetData,
|
|
412
400
|
[key]: value,
|
|
413
|
-
}
|
|
401
|
+
}
|
|
414
402
|
})),
|
|
415
403
|
setFinalAssetContexts: (value) => set({ finalAssetContexts: value }),
|
|
416
404
|
setFinalAtOICaps: (value) => set({ finalAtOICaps: value }),
|
|
417
405
|
setAggregatedClearingHouseState: (value) => set({ aggregatedClearingHouseState: value }),
|
|
418
406
|
setPerpMetaAssets: (value) => set({ perpMetaAssets: value }),
|
|
419
|
-
|
|
420
|
-
setHip3MarketPrefixes: (value) => set({ hip3MarketPrefixes: value }),
|
|
407
|
+
setHip3DisplayToFull: (value) => set({ hip3DisplayToFull: value })
|
|
421
408
|
}));
|
|
422
409
|
|
|
423
410
|
const DEFAULT_STATE = {
|
|
@@ -558,11 +545,11 @@ const useUserSelection$1 = create((set, get) => ({
|
|
|
558
545
|
}));
|
|
559
546
|
|
|
560
547
|
const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
561
|
-
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState
|
|
548
|
+
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState } = useHyperliquidData();
|
|
562
549
|
const { candleInterval } = useUserSelection$1();
|
|
563
550
|
const longTokens = useUserSelection$1((s) => s.longTokens);
|
|
564
551
|
const shortTokens = useUserSelection$1((s) => s.shortTokens);
|
|
565
|
-
const selectedTokenSymbols = useMemo(() => [...longTokens, ...shortTokens].map((t) => t.symbol), [longTokens, shortTokens]);
|
|
552
|
+
const selectedTokenSymbols = useMemo(() => ([...longTokens, ...shortTokens].map((t) => t.symbol)), [longTokens, shortTokens]);
|
|
566
553
|
const [lastError, setLastError] = useState(null);
|
|
567
554
|
const [subscribedAddress, setSubscribedAddress] = useState(null);
|
|
568
555
|
const [subscribedTokens, setSubscribedTokens] = useState([]);
|
|
@@ -600,7 +587,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
600
587
|
.map((dex) => dex.clearinghouseState)
|
|
601
588
|
.filter(Boolean);
|
|
602
589
|
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || '0') || 0), 0);
|
|
603
|
-
const toStr = (n) => Number.isFinite(n) ? n.toString() : '0';
|
|
590
|
+
const toStr = (n) => (Number.isFinite(n) ? n.toString() : '0');
|
|
604
591
|
const assetPositions = states.flatMap((s) => s.assetPositions || []);
|
|
605
592
|
const crossMaintenanceMarginUsed = toStr(sum(states.map((s) => s.crossMaintenanceMarginUsed)));
|
|
606
593
|
const crossMarginSummary = {
|
|
@@ -633,42 +620,17 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
633
620
|
case 'allMids':
|
|
634
621
|
{
|
|
635
622
|
const data = response.data;
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
Object.entries(data.mids || {}).forEach(([k, v]) => {
|
|
641
|
-
// Normalize prefixed keys to lowercase prefix (e.g., "XYZ:TSLA" -> "xyz:TSLA")
|
|
642
|
-
// This matches how we look up tokens in the SDK
|
|
643
|
-
let normalizedKey = k;
|
|
644
|
-
if (k.includes(':')) {
|
|
645
|
-
const [prefix, ...rest] = k.split(':');
|
|
646
|
-
normalizedKey = `${prefix.toLowerCase()}:${rest.join(':')}`;
|
|
647
|
-
}
|
|
648
|
-
// Store with normalized key
|
|
649
|
-
mids[normalizedKey] = v;
|
|
650
|
-
// Also store with original key for backward compatibility
|
|
651
|
-
if (k !== normalizedKey) {
|
|
652
|
-
mids[k] = v;
|
|
653
|
-
}
|
|
654
|
-
// Also store with display symbol for backward compatibility
|
|
655
|
-
const displayKey = toDisplaySymbol(k);
|
|
656
|
-
// Only set display key if it doesn't already exist (avoid overwriting market-specific prices)
|
|
657
|
-
if (!(displayKey in mids)) {
|
|
658
|
-
mids[displayKey] = v;
|
|
659
|
-
}
|
|
660
|
-
});
|
|
661
|
-
setAllMids({ mids });
|
|
623
|
+
const remapped = {
|
|
624
|
+
mids: Object.fromEntries(Object.entries(data.mids || {}).map(([k, v]) => [toDisplaySymbol(k), v]))
|
|
625
|
+
};
|
|
626
|
+
setAllMids(remapped);
|
|
662
627
|
}
|
|
663
628
|
break;
|
|
664
629
|
case 'activeAssetData':
|
|
665
630
|
{
|
|
666
631
|
const assetData = response.data;
|
|
667
632
|
const symbol = toDisplaySymbol(assetData.coin);
|
|
668
|
-
const normalized = {
|
|
669
|
-
...assetData,
|
|
670
|
-
coin: symbol,
|
|
671
|
-
};
|
|
633
|
+
const normalized = { ...assetData, coin: symbol };
|
|
672
634
|
upsertActiveAssetData(symbol, normalized);
|
|
673
635
|
}
|
|
674
636
|
break;
|
|
@@ -690,14 +652,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
690
652
|
console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', event.data);
|
|
691
653
|
setLastError(errorMessage);
|
|
692
654
|
}
|
|
693
|
-
}, [
|
|
694
|
-
setAllMids,
|
|
695
|
-
upsertActiveAssetData,
|
|
696
|
-
addCandleData,
|
|
697
|
-
setFinalAssetContexts,
|
|
698
|
-
setFinalAtOICaps,
|
|
699
|
-
setAggregatedClearingHouseState,
|
|
700
|
-
]);
|
|
655
|
+
}, [setAllMids, upsertActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState]);
|
|
701
656
|
const connect = useCallback(() => {
|
|
702
657
|
if (!enabled)
|
|
703
658
|
return;
|
|
@@ -820,13 +775,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
820
775
|
// clear aggregatedClearingHouseState
|
|
821
776
|
setAggregatedClearingHouseState(null);
|
|
822
777
|
}
|
|
823
|
-
}, [
|
|
824
|
-
isConnected,
|
|
825
|
-
address,
|
|
826
|
-
subscribedAddress,
|
|
827
|
-
sendJsonMessage,
|
|
828
|
-
setAggregatedClearingHouseState,
|
|
829
|
-
]);
|
|
778
|
+
}, [isConnected, address, subscribedAddress, sendJsonMessage, setAggregatedClearingHouseState]);
|
|
830
779
|
// Handle token subscriptions for activeAssetData
|
|
831
780
|
useEffect(() => {
|
|
832
781
|
if (!isConnected || !address)
|
|
@@ -835,7 +784,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
835
784
|
const tokensToSubscribe = effectiveTokens.filter((token) => token && !subscribedTokens.includes(token));
|
|
836
785
|
const tokensToUnsubscribe = subscribedTokens.filter((token) => !effectiveTokens.includes(token));
|
|
837
786
|
// Unsubscribe from tokens no longer in the list
|
|
838
|
-
tokensToUnsubscribe.forEach(
|
|
787
|
+
tokensToUnsubscribe.forEach(token => {
|
|
839
788
|
const unsubscribeMessage = {
|
|
840
789
|
method: 'unsubscribe',
|
|
841
790
|
subscription: {
|
|
@@ -847,7 +796,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
847
796
|
sendJsonMessage(unsubscribeMessage);
|
|
848
797
|
});
|
|
849
798
|
// Subscribe to new tokens
|
|
850
|
-
tokensToSubscribe.forEach(
|
|
799
|
+
tokensToSubscribe.forEach(token => {
|
|
851
800
|
const subscribeMessage = {
|
|
852
801
|
method: 'subscribe',
|
|
853
802
|
subscription: {
|
|
@@ -862,14 +811,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
862
811
|
setSubscribedTokens(effectiveTokens.filter((token) => token));
|
|
863
812
|
tokensToSubscribe.forEach((token) => deleteActiveAssetData(token));
|
|
864
813
|
}
|
|
865
|
-
}, [
|
|
866
|
-
isConnected,
|
|
867
|
-
address,
|
|
868
|
-
selectedTokenSymbols,
|
|
869
|
-
subscribedTokens,
|
|
870
|
-
sendJsonMessage,
|
|
871
|
-
setActiveAssetData,
|
|
872
|
-
]);
|
|
814
|
+
}, [isConnected, address, selectedTokenSymbols, subscribedTokens, sendJsonMessage, setActiveAssetData]);
|
|
873
815
|
// Handle candle subscriptions for tokens and interval changes
|
|
874
816
|
useEffect(() => {
|
|
875
817
|
if (!isConnected)
|
|
@@ -878,7 +820,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
878
820
|
// Unsubscribe from previous candle subscriptions if interval changed
|
|
879
821
|
const prevInterval = prevCandleIntervalRef.current;
|
|
880
822
|
if (prevInterval && prevInterval !== candleInterval) {
|
|
881
|
-
subscribedCandleTokens.forEach(
|
|
823
|
+
subscribedCandleTokens.forEach(token => {
|
|
882
824
|
const unsubscribeMessage = {
|
|
883
825
|
method: 'unsubscribe',
|
|
884
826
|
subscription: {
|
|
@@ -919,21 +861,12 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
919
861
|
sendJsonMessage(subscribeMessage);
|
|
920
862
|
});
|
|
921
863
|
// Update subscribed state
|
|
922
|
-
if (tokensToSubscribe.length > 0 ||
|
|
923
|
-
tokensToUnsubscribe.length > 0 ||
|
|
924
|
-
prevInterval !== candleInterval) {
|
|
864
|
+
if (tokensToSubscribe.length > 0 || tokensToUnsubscribe.length > 0 || prevInterval !== candleInterval) {
|
|
925
865
|
setSubscribedCandleTokens(effectiveTokens.filter((token) => token));
|
|
926
866
|
prevCandleIntervalRef.current = candleInterval;
|
|
927
867
|
tokensToUnsubscribe.forEach((token) => deleteCandleSymbol(token));
|
|
928
868
|
}
|
|
929
|
-
}, [
|
|
930
|
-
isConnected,
|
|
931
|
-
selectedTokenSymbols,
|
|
932
|
-
candleInterval,
|
|
933
|
-
subscribedCandleTokens,
|
|
934
|
-
sendJsonMessage,
|
|
935
|
-
setCandleData,
|
|
936
|
-
]);
|
|
869
|
+
}, [isConnected, selectedTokenSymbols, candleInterval, subscribedCandleTokens, sendJsonMessage, setCandleData]);
|
|
937
870
|
return {
|
|
938
871
|
isConnected,
|
|
939
872
|
lastError,
|
|
@@ -1013,69 +946,16 @@ const useAccountSummary = () => {
|
|
|
1013
946
|
return { data: calculated, isLoading };
|
|
1014
947
|
};
|
|
1015
948
|
|
|
1016
|
-
// Helper to find asset metadata from perpMetaAssets
|
|
1017
|
-
function findAssetMeta$2(coinName, perpMetaAssets) {
|
|
1018
|
-
var _a, _b, _c, _d;
|
|
1019
|
-
if (!perpMetaAssets) {
|
|
1020
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
1021
|
-
}
|
|
1022
|
-
// Try exact match first (for prefixed assets like "xyz:TSLA")
|
|
1023
|
-
const exactMatch = perpMetaAssets.find((a) => a.name === coinName);
|
|
1024
|
-
if (exactMatch) {
|
|
1025
|
-
return {
|
|
1026
|
-
collateralToken: (_a = exactMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
1027
|
-
marketPrefix: (_b = exactMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
1028
|
-
};
|
|
1029
|
-
}
|
|
1030
|
-
// Try matching by base symbol (for non-prefixed names in data)
|
|
1031
|
-
const baseMatch = perpMetaAssets.find((a) => {
|
|
1032
|
-
const baseName = a.name.includes(':') ? a.name.split(':')[1] : a.name;
|
|
1033
|
-
return baseName === coinName;
|
|
1034
|
-
});
|
|
1035
|
-
if (baseMatch) {
|
|
1036
|
-
return {
|
|
1037
|
-
collateralToken: (_c = baseMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
1038
|
-
marketPrefix: (_d = baseMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
1039
|
-
};
|
|
1040
|
-
}
|
|
1041
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
1042
|
-
}
|
|
1043
|
-
// Enrich trade history assets with market prefix and collateral token
|
|
1044
|
-
function enrichTradeHistoryAssets(assets, perpMetaAssets) {
|
|
1045
|
-
return assets.map((asset) => {
|
|
1046
|
-
const meta = findAssetMeta$2(asset.coin, perpMetaAssets);
|
|
1047
|
-
return {
|
|
1048
|
-
...asset,
|
|
1049
|
-
marketPrefix: meta.marketPrefix,
|
|
1050
|
-
collateralToken: meta.collateralToken,
|
|
1051
|
-
};
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
// Enrich all trade histories with market metadata
|
|
1055
|
-
function enrichTradeHistories(histories, perpMetaAssets) {
|
|
1056
|
-
return histories.map((history) => ({
|
|
1057
|
-
...history,
|
|
1058
|
-
closedLongAssets: enrichTradeHistoryAssets(history.closedLongAssets, perpMetaAssets),
|
|
1059
|
-
closedShortAssets: enrichTradeHistoryAssets(history.closedShortAssets, perpMetaAssets),
|
|
1060
|
-
}));
|
|
1061
|
-
}
|
|
1062
949
|
const useTradeHistories = () => {
|
|
1063
950
|
const context = useContext(PearHyperliquidContext);
|
|
1064
951
|
if (!context) {
|
|
1065
952
|
throw new Error('useTradeHistories must be used within a PearHyperliquidProvider');
|
|
1066
953
|
}
|
|
1067
954
|
const tradeHistories = useUserData((state) => state.tradeHistories);
|
|
1068
|
-
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
1069
955
|
const isLoading = useMemo(() => {
|
|
1070
956
|
return tradeHistories === null && context.isConnected;
|
|
1071
957
|
}, [tradeHistories, context.isConnected]);
|
|
1072
|
-
|
|
1073
|
-
const enrichedTradeHistories = useMemo(() => {
|
|
1074
|
-
if (!tradeHistories)
|
|
1075
|
-
return null;
|
|
1076
|
-
return enrichTradeHistories(tradeHistories, perpMetaAssets);
|
|
1077
|
-
}, [tradeHistories, perpMetaAssets]);
|
|
1078
|
-
return { data: enrichedTradeHistories, isLoading };
|
|
958
|
+
return { data: tradeHistories, isLoading };
|
|
1079
959
|
};
|
|
1080
960
|
/**
|
|
1081
961
|
* Hook to access open orders with loading state
|
|
@@ -1108,51 +988,21 @@ const useWebData = () => {
|
|
|
1108
988
|
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
1109
989
|
const aggregatedClearinghouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
1110
990
|
const finalAtOICaps = useHyperliquidData((state) => state.finalAtOICaps);
|
|
1111
|
-
const hip3Assets = useHyperliquidData((state) => state.
|
|
1112
|
-
const hip3MarketPrefixes = useHyperliquidData((state) => state.hip3MarketPrefixes);
|
|
991
|
+
const hip3Assets = useHyperliquidData((state) => state.hip3DisplayToFull);
|
|
1113
992
|
let marketDataBySymbol = {};
|
|
1114
993
|
if (finalAssetContexts && perpMetaAssets) {
|
|
1115
994
|
const result = {};
|
|
1116
|
-
// Build a map of display name -> asset context index (for unique display names)
|
|
1117
|
-
const displayNameToContextIndex = new Map();
|
|
1118
|
-
const seenNames = new Set();
|
|
1119
|
-
let contextIndex = 0;
|
|
1120
|
-
// First pass: map unique display names to their context index
|
|
1121
995
|
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1122
996
|
const name = perpMetaAssets[index].name;
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
contextIndex++;
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
// Second pass: create nested entries for all market variants
|
|
1132
|
-
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1133
|
-
const universeAsset = perpMetaAssets[index];
|
|
1134
|
-
const displayName = universeAsset.name;
|
|
1135
|
-
const marketPrefix = universeAsset.marketPrefix;
|
|
1136
|
-
const ctxIndex = displayNameToContextIndex.get(displayName);
|
|
1137
|
-
if (ctxIndex !== undefined) {
|
|
1138
|
-
const assetContext = finalAssetContexts[ctxIndex];
|
|
1139
|
-
// Initialize the symbol entry if it doesn't exist
|
|
1140
|
-
if (!result[displayName]) {
|
|
1141
|
-
result[displayName] = {};
|
|
1142
|
-
}
|
|
1143
|
-
// Use marketPrefix as key for HIP-3 assets, "default" for regular assets
|
|
1144
|
-
const variantKey = marketPrefix || 'default';
|
|
1145
|
-
result[displayName][variantKey] = {
|
|
1146
|
-
asset: assetContext,
|
|
1147
|
-
universe: universeAsset,
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
997
|
+
result[name] = {
|
|
998
|
+
asset: finalAssetContexts[index],
|
|
999
|
+
universe: perpMetaAssets[index],
|
|
1000
|
+
};
|
|
1150
1001
|
}
|
|
1151
1002
|
marketDataBySymbol = result;
|
|
1152
1003
|
}
|
|
1153
1004
|
return {
|
|
1154
1005
|
hip3Assets,
|
|
1155
|
-
hip3MarketPrefixes,
|
|
1156
1006
|
clearinghouseState: aggregatedClearinghouseState,
|
|
1157
1007
|
perpsAtOpenInterestCap: finalAtOICaps,
|
|
1158
1008
|
marketDataBySymbol,
|
|
@@ -1167,60 +1017,30 @@ const useWebData = () => {
|
|
|
1167
1017
|
class TokenMetadataExtractor {
|
|
1168
1018
|
/**
|
|
1169
1019
|
* Extracts comprehensive token metadata
|
|
1170
|
-
* @param symbol - Token symbol
|
|
1020
|
+
* @param symbol - Token symbol
|
|
1171
1021
|
* @param perpMetaAssets - Aggregated universe assets (flattened across dexes)
|
|
1172
1022
|
* @param finalAssetContexts - Aggregated asset contexts (flattened across dexes)
|
|
1173
1023
|
* @param allMids - AllMids data containing current prices
|
|
1174
1024
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1175
|
-
* @param marketPrefix - Optional market prefix (e.g., "xyz", "flx") for HIP3 multi-market assets
|
|
1176
1025
|
* @returns TokenMetadata or null if token not found
|
|
1177
1026
|
*/
|
|
1178
|
-
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData
|
|
1027
|
+
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
1179
1028
|
if (!perpMetaAssets || !finalAssetContexts || !allMids) {
|
|
1180
1029
|
return null;
|
|
1181
1030
|
}
|
|
1182
1031
|
// Find token index in aggregated universe
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
if (asset.name !== symbol)
|
|
1186
|
-
return false;
|
|
1187
|
-
// If marketPrefix is specified, match it; otherwise match assets without prefix
|
|
1188
|
-
if (marketPrefix) {
|
|
1189
|
-
return asset.marketPrefix === marketPrefix;
|
|
1190
|
-
}
|
|
1191
|
-
// No prefix specified - match non-HIP3 asset (no marketPrefix) or first matching asset
|
|
1192
|
-
return !asset.marketPrefix;
|
|
1193
|
-
});
|
|
1194
|
-
// If no exact match found and prefix was specified, try finding the specific market variant
|
|
1195
|
-
const finalIndex = universeIndex === -1 && marketPrefix
|
|
1196
|
-
? perpMetaAssets.findIndex((asset) => asset.name === symbol && asset.marketPrefix === marketPrefix)
|
|
1197
|
-
: universeIndex;
|
|
1198
|
-
// Fallback: if still not found and no prefix, find first matching by name (for backward compatibility)
|
|
1199
|
-
const resolvedIndex = finalIndex === -1
|
|
1200
|
-
? perpMetaAssets.findIndex((asset) => asset.name === symbol)
|
|
1201
|
-
: finalIndex;
|
|
1202
|
-
if (resolvedIndex === -1) {
|
|
1032
|
+
const universeIndex = perpMetaAssets.findIndex(asset => asset.name === symbol);
|
|
1033
|
+
if (universeIndex === -1) {
|
|
1203
1034
|
return null;
|
|
1204
1035
|
}
|
|
1205
|
-
const universeAsset = perpMetaAssets[
|
|
1206
|
-
const assetCtx = finalAssetContexts[
|
|
1036
|
+
const universeAsset = perpMetaAssets[universeIndex];
|
|
1037
|
+
const assetCtx = finalAssetContexts[universeIndex];
|
|
1207
1038
|
if (!assetCtx) {
|
|
1208
1039
|
return null;
|
|
1209
1040
|
}
|
|
1210
|
-
// Get current price
|
|
1211
|
-
|
|
1212
|
-
const
|
|
1213
|
-
let currentPrice = 0;
|
|
1214
|
-
// Primary source: assetCtx.midPx (already properly indexed)
|
|
1215
|
-
if (assetCtx.midPx) {
|
|
1216
|
-
currentPrice = parseFloat(assetCtx.midPx);
|
|
1217
|
-
}
|
|
1218
|
-
// Fallback: allMids lookup with multiple key formats for HIP3 markets
|
|
1219
|
-
if (!currentPrice || isNaN(currentPrice)) {
|
|
1220
|
-
const currentPriceStr = (prefixedKeyColon && allMids.mids[prefixedKeyColon]) ||
|
|
1221
|
-
allMids.mids[symbol];
|
|
1222
|
-
currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
1223
|
-
}
|
|
1041
|
+
// Get current price from allMids
|
|
1042
|
+
const currentPriceStr = allMids.mids[symbol];
|
|
1043
|
+
const currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
1224
1044
|
// Get previous day price
|
|
1225
1045
|
const prevDayPrice = parseFloat(assetCtx.prevDayPx);
|
|
1226
1046
|
// Calculate 24h price change
|
|
@@ -1231,11 +1051,7 @@ class TokenMetadataExtractor {
|
|
|
1231
1051
|
const markPrice = parseFloat(assetCtx.markPx);
|
|
1232
1052
|
const oraclePrice = parseFloat(assetCtx.oraclePx);
|
|
1233
1053
|
// Extract leverage info from activeAssetData if available
|
|
1234
|
-
|
|
1235
|
-
const activeDataKey = prefixedKeyColon && (activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[prefixedKeyColon])
|
|
1236
|
-
? prefixedKeyColon
|
|
1237
|
-
: symbol;
|
|
1238
|
-
const tokenActiveData = activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[activeDataKey];
|
|
1054
|
+
const tokenActiveData = activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[symbol];
|
|
1239
1055
|
const leverage = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.leverage;
|
|
1240
1056
|
const maxTradeSzs = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.maxTradeSzs;
|
|
1241
1057
|
const availableToTrade = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.availableToTrade;
|
|
@@ -1253,27 +1069,21 @@ class TokenMetadataExtractor {
|
|
|
1253
1069
|
leverage,
|
|
1254
1070
|
maxTradeSzs,
|
|
1255
1071
|
availableToTrade,
|
|
1256
|
-
collateralToken: universeAsset.collateralToken,
|
|
1257
1072
|
};
|
|
1258
1073
|
}
|
|
1259
1074
|
/**
|
|
1260
1075
|
* Extracts metadata for multiple tokens
|
|
1261
|
-
* @param
|
|
1076
|
+
* @param symbols - Array of token symbols
|
|
1262
1077
|
* @param perpMetaAssets - Aggregated universe assets
|
|
1263
1078
|
* @param finalAssetContexts - Aggregated asset contexts
|
|
1264
1079
|
* @param allMids - AllMids data
|
|
1265
1080
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1266
|
-
* @returns Record of
|
|
1081
|
+
* @returns Record of symbol to TokenMetadata
|
|
1267
1082
|
*/
|
|
1268
|
-
static extractMultipleTokensMetadata(
|
|
1083
|
+
static extractMultipleTokensMetadata(symbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
1269
1084
|
const result = {};
|
|
1270
|
-
for (const
|
|
1271
|
-
|
|
1272
|
-
// This ensures xyz:TSLA and flx:TSLA get separate entries
|
|
1273
|
-
const resultKey = token.marketPrefix
|
|
1274
|
-
? `${token.marketPrefix}:${token.symbol}`
|
|
1275
|
-
: token.symbol;
|
|
1276
|
-
result[resultKey] = this.extractTokenMetadata(token.symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData, token.marketPrefix);
|
|
1085
|
+
for (const symbol of symbols) {
|
|
1086
|
+
result[symbol] = this.extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData);
|
|
1277
1087
|
}
|
|
1278
1088
|
return result;
|
|
1279
1089
|
}
|
|
@@ -1286,30 +1096,10 @@ class TokenMetadataExtractor {
|
|
|
1286
1096
|
static isTokenAvailable(symbol, perpMetaAssets) {
|
|
1287
1097
|
if (!perpMetaAssets)
|
|
1288
1098
|
return false;
|
|
1289
|
-
return perpMetaAssets.some(
|
|
1099
|
+
return perpMetaAssets.some(asset => asset.name === symbol);
|
|
1290
1100
|
}
|
|
1291
1101
|
}
|
|
1292
1102
|
|
|
1293
|
-
/**
|
|
1294
|
-
* Parse a token string that may have a market prefix (e.g., "xyz:GOOGL" -> { prefix: "xyz", symbol: "GOOGL" })
|
|
1295
|
-
* This allows us to keep the full name (xyz:GOOGL) for URLs/tags while extracting just the symbol for SDK lookups.
|
|
1296
|
-
*/
|
|
1297
|
-
function parseTokenWithPrefix(token) {
|
|
1298
|
-
if (token.includes(':')) {
|
|
1299
|
-
const [prefix, ...rest] = token.split(':');
|
|
1300
|
-
const symbol = rest.join(':').toUpperCase();
|
|
1301
|
-
return {
|
|
1302
|
-
prefix: prefix.toLowerCase(),
|
|
1303
|
-
symbol,
|
|
1304
|
-
fullName: `${prefix.toLowerCase()}:${symbol}`,
|
|
1305
|
-
};
|
|
1306
|
-
}
|
|
1307
|
-
return {
|
|
1308
|
-
prefix: null,
|
|
1309
|
-
symbol: token.toUpperCase(),
|
|
1310
|
-
fullName: token.toUpperCase(),
|
|
1311
|
-
};
|
|
1312
|
-
}
|
|
1313
1103
|
const useTokenSelectionMetadataStore = create((set) => ({
|
|
1314
1104
|
isPriceDataReady: false,
|
|
1315
1105
|
isLoading: true,
|
|
@@ -1319,65 +1109,23 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1319
1109
|
weightedRatio24h: 1,
|
|
1320
1110
|
priceRatio: 1,
|
|
1321
1111
|
priceRatio24h: 1,
|
|
1322
|
-
openInterest:
|
|
1323
|
-
volume:
|
|
1112
|
+
openInterest: "0",
|
|
1113
|
+
volume: "0",
|
|
1324
1114
|
sumNetFunding: 0,
|
|
1325
1115
|
maxLeverage: 0,
|
|
1326
1116
|
minMargin: 0,
|
|
1327
1117
|
leverageMatched: true,
|
|
1328
|
-
recompute: ({ perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketData, longTokens, shortTokens
|
|
1329
|
-
const isPriceDataReady = !!(perpMetaAssets &&
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
...t,
|
|
1336
|
-
parsed: parseTokenWithPrefix(t.symbol),
|
|
1337
|
-
}));
|
|
1338
|
-
const parsedShortTokens = shortTokens.map((t) => ({
|
|
1339
|
-
...t,
|
|
1340
|
-
parsed: parseTokenWithPrefix(t.symbol),
|
|
1341
|
-
}));
|
|
1342
|
-
// Extract base symbols with their market prefixes for SDK lookups
|
|
1343
|
-
// This ensures xyz:TSLA and flx:TSLA get different market data
|
|
1344
|
-
const longTokensForLookup = parsedLongTokens.map((t) => ({
|
|
1345
|
-
symbol: t.parsed.symbol,
|
|
1346
|
-
marketPrefix: t.parsed.prefix,
|
|
1347
|
-
}));
|
|
1348
|
-
const shortTokensForLookup = parsedShortTokens.map((t) => ({
|
|
1349
|
-
symbol: t.parsed.symbol,
|
|
1350
|
-
marketPrefix: t.parsed.prefix,
|
|
1351
|
-
}));
|
|
1352
|
-
// Also extract just the base symbols (without prefix) for lookups that don't support prefixes
|
|
1353
|
-
const longBaseSymbols = longTokensForLookup.map((t) => t.symbol);
|
|
1354
|
-
const shortBaseSymbols = shortTokensForLookup.map((t) => t.symbol);
|
|
1355
|
-
// Get metadata using base symbols with market prefix for proper market differentiation
|
|
1356
|
-
const longBaseMetadata = isPriceDataReady
|
|
1357
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(longTokensForLookup, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1118
|
+
recompute: ({ perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketData, longTokens, shortTokens }) => {
|
|
1119
|
+
const isPriceDataReady = !!(perpMetaAssets && finalAssetContexts && allMids);
|
|
1120
|
+
// Compute metadata when ready
|
|
1121
|
+
const longSymbols = longTokens.map((t) => t.symbol);
|
|
1122
|
+
const shortSymbols = shortTokens.map((t) => t.symbol);
|
|
1123
|
+
const longTokensMetadata = isPriceDataReady
|
|
1124
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(longSymbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1358
1125
|
: {};
|
|
1359
|
-
const
|
|
1360
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(
|
|
1126
|
+
const shortTokensMetadata = isPriceDataReady
|
|
1127
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(shortSymbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1361
1128
|
: {};
|
|
1362
|
-
// Re-map metadata using original full names (with prefix) as keys for UI consistency
|
|
1363
|
-
// The extractor now keys by "{prefix}:{symbol}" for prefixed tokens, which matches our parsed.fullName
|
|
1364
|
-
const longTokensMetadata = {};
|
|
1365
|
-
parsedLongTokens.forEach((t) => {
|
|
1366
|
-
var _a;
|
|
1367
|
-
// Use the full name (e.g., "xyz:TSLA") as the lookup key since extractor uses the same format
|
|
1368
|
-
const lookupKey = t.parsed.prefix
|
|
1369
|
-
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1370
|
-
: t.parsed.symbol;
|
|
1371
|
-
longTokensMetadata[t.symbol] = (_a = longBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1372
|
-
});
|
|
1373
|
-
const shortTokensMetadata = {};
|
|
1374
|
-
parsedShortTokens.forEach((t) => {
|
|
1375
|
-
var _a;
|
|
1376
|
-
const lookupKey = t.parsed.prefix
|
|
1377
|
-
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1378
|
-
: t.parsed.symbol;
|
|
1379
|
-
shortTokensMetadata[t.symbol] = (_a = shortBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1380
|
-
});
|
|
1381
1129
|
// Determine loading state
|
|
1382
1130
|
const allTokens = [...longTokens, ...shortTokens];
|
|
1383
1131
|
const isLoading = (() => {
|
|
@@ -1385,33 +1133,26 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1385
1133
|
return true;
|
|
1386
1134
|
if (allTokens.length === 0)
|
|
1387
1135
|
return false;
|
|
1388
|
-
const allMetadata = {
|
|
1389
|
-
...longTokensMetadata,
|
|
1390
|
-
...shortTokensMetadata,
|
|
1391
|
-
};
|
|
1136
|
+
const allMetadata = { ...longTokensMetadata, ...shortTokensMetadata };
|
|
1392
1137
|
return allTokens.some((token) => !allMetadata[token.symbol]);
|
|
1393
1138
|
})();
|
|
1394
1139
|
// Open interest and volume (from market data for matching asset basket)
|
|
1395
|
-
// Use base symbols (without prefix) for matching against market data
|
|
1396
1140
|
const { openInterest, volume } = (() => {
|
|
1397
|
-
const empty = { openInterest:
|
|
1141
|
+
const empty = { openInterest: "0", volume: "0" };
|
|
1398
1142
|
if (!(marketData === null || marketData === void 0 ? void 0 : marketData.active) || (!longTokens.length && !shortTokens.length))
|
|
1399
1143
|
return empty;
|
|
1400
|
-
const selectedLong =
|
|
1401
|
-
const selectedShort =
|
|
1144
|
+
const selectedLong = longTokens.map((t) => t.symbol).sort();
|
|
1145
|
+
const selectedShort = shortTokens.map((t) => t.symbol).sort();
|
|
1402
1146
|
const match = marketData.active.find((item) => {
|
|
1403
1147
|
const longs = [...item.longAssets].sort();
|
|
1404
1148
|
const shorts = [...item.shortAssets].sort();
|
|
1405
|
-
if (longs.length !== selectedLong.length ||
|
|
1406
|
-
shorts.length !== selectedShort.length)
|
|
1149
|
+
if (longs.length !== selectedLong.length || shorts.length !== selectedShort.length)
|
|
1407
1150
|
return false;
|
|
1408
1151
|
const longsEqual = longs.every((s, i) => s.asset === selectedLong[i]);
|
|
1409
1152
|
const shortsEqual = shorts.every((s, i) => s.asset === selectedShort[i]);
|
|
1410
1153
|
return longsEqual && shortsEqual;
|
|
1411
1154
|
});
|
|
1412
|
-
return match
|
|
1413
|
-
? { openInterest: match.openInterest, volume: match.volume }
|
|
1414
|
-
: empty;
|
|
1155
|
+
return match ? { openInterest: match.openInterest, volume: match.volume } : empty;
|
|
1415
1156
|
})();
|
|
1416
1157
|
// Price ratio (only when exactly one long and one short)
|
|
1417
1158
|
const { priceRatio, priceRatio24h } = (() => {
|
|
@@ -1491,27 +1232,17 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1491
1232
|
return totalFunding;
|
|
1492
1233
|
})();
|
|
1493
1234
|
// Max leverage (minimum across all tokens)
|
|
1494
|
-
// Use tokens with their market prefixes for proper lookup in perpMetaAssets
|
|
1495
1235
|
const maxLeverage = (() => {
|
|
1496
1236
|
if (!perpMetaAssets)
|
|
1497
1237
|
return 0;
|
|
1498
|
-
const
|
|
1499
|
-
|
|
1500
|
-
...shortTokensForLookup,
|
|
1501
|
-
];
|
|
1502
|
-
if (allTokensForLookup.length === 0)
|
|
1238
|
+
const allTokenSymbols = [...longTokens, ...shortTokens].map((t) => t.symbol);
|
|
1239
|
+
if (allTokenSymbols.length === 0)
|
|
1503
1240
|
return 0;
|
|
1504
1241
|
let minLev = Infinity;
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
(
|
|
1509
|
-
? u.marketPrefix === marketPrefix
|
|
1510
|
-
: !u.marketPrefix));
|
|
1511
|
-
// Fallback to just matching by name if no exact match
|
|
1512
|
-
const fallbackUniverse = tokenUniverse || perpMetaAssets.find((u) => u.name === symbol);
|
|
1513
|
-
if (fallbackUniverse === null || fallbackUniverse === void 0 ? void 0 : fallbackUniverse.maxLeverage)
|
|
1514
|
-
minLev = Math.min(minLev, fallbackUniverse.maxLeverage);
|
|
1242
|
+
allTokenSymbols.forEach((symbol) => {
|
|
1243
|
+
const tokenUniverse = perpMetaAssets.find((u) => u.name === symbol);
|
|
1244
|
+
if (tokenUniverse === null || tokenUniverse === void 0 ? void 0 : tokenUniverse.maxLeverage)
|
|
1245
|
+
minLev = Math.min(minLev, tokenUniverse.maxLeverage);
|
|
1515
1246
|
});
|
|
1516
1247
|
return minLev === Infinity ? 0 : minLev;
|
|
1517
1248
|
})();
|
|
@@ -1523,10 +1254,7 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1523
1254
|
// Whether all tokens have matching leverage
|
|
1524
1255
|
const leverageMatched = (() => {
|
|
1525
1256
|
const allTokensArr = [...longTokens, ...shortTokens];
|
|
1526
|
-
const allMetadata = {
|
|
1527
|
-
...longTokensMetadata,
|
|
1528
|
-
...shortTokensMetadata,
|
|
1529
|
-
};
|
|
1257
|
+
const allMetadata = { ...longTokensMetadata, ...shortTokensMetadata };
|
|
1530
1258
|
if (allTokensArr.length === 0)
|
|
1531
1259
|
return true;
|
|
1532
1260
|
const tokensWithLev = allTokensArr.filter((token) => { var _a; return (_a = allMetadata[token.symbol]) === null || _a === void 0 ? void 0 : _a.leverage; });
|
|
@@ -5711,8 +5439,8 @@ function addAuthInterceptors(params) {
|
|
|
5711
5439
|
/**
|
|
5712
5440
|
* Fetch historical candle data from HyperLiquid API
|
|
5713
5441
|
*/
|
|
5714
|
-
const fetchHistoricalCandles = async (coin, startTime, endTime, interval,
|
|
5715
|
-
const backendCoin = toBackendSymbol(coin,
|
|
5442
|
+
const fetchHistoricalCandles = async (coin, startTime, endTime, interval, displayToFull) => {
|
|
5443
|
+
const backendCoin = toBackendSymbol(coin, displayToFull);
|
|
5716
5444
|
const request = {
|
|
5717
5445
|
req: { coin: backendCoin, startTime, endTime, interval },
|
|
5718
5446
|
type: 'candleSnapshot',
|
|
@@ -5871,10 +5599,10 @@ const useHistoricalPriceData = () => {
|
|
|
5871
5599
|
setTokenLoading(token.symbol, true);
|
|
5872
5600
|
});
|
|
5873
5601
|
try {
|
|
5874
|
-
const
|
|
5602
|
+
const displayToFull = useHyperliquidData.getState().hip3DisplayToFull;
|
|
5875
5603
|
const fetchPromises = tokensToFetch.map(async (token) => {
|
|
5876
5604
|
try {
|
|
5877
|
-
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval,
|
|
5605
|
+
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval, displayToFull);
|
|
5878
5606
|
addHistoricalPriceData(token.symbol, interval, response.data, { start: startTime, end: endTime });
|
|
5879
5607
|
return { symbol: token.symbol, candles: response.data, success: true };
|
|
5880
5608
|
}
|
|
@@ -6643,12 +6371,12 @@ function validatePositionSize(usdValue, longAssets, shortAssets) {
|
|
|
6643
6371
|
* Authorization is derived from headers (Axios defaults or browser localStorage fallback)
|
|
6644
6372
|
* @throws MinimumPositionSizeError if any asset has less than $11 USD value
|
|
6645
6373
|
*/
|
|
6646
|
-
async function createPosition(baseUrl, payload,
|
|
6374
|
+
async function createPosition(baseUrl, payload, displayToFull) {
|
|
6647
6375
|
// Validate minimum asset size before creating position
|
|
6648
6376
|
validateMinimumAssetSize(payload.usdValue, payload.longAssets, payload.shortAssets);
|
|
6649
6377
|
const url = joinUrl(baseUrl, "/positions");
|
|
6650
6378
|
// Translate display symbols to backend format
|
|
6651
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset,
|
|
6379
|
+
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
6652
6380
|
const translatedPayload = {
|
|
6653
6381
|
...payload,
|
|
6654
6382
|
longAssets: mapAssets(payload.longAssets),
|
|
@@ -6747,9 +6475,9 @@ async function adjustPosition(baseUrl, positionId, payload) {
|
|
|
6747
6475
|
throw toApiError(error);
|
|
6748
6476
|
}
|
|
6749
6477
|
}
|
|
6750
|
-
async function adjustAdvancePosition(baseUrl, positionId, payload,
|
|
6478
|
+
async function adjustAdvancePosition(baseUrl, positionId, payload, displayToFull) {
|
|
6751
6479
|
const url = joinUrl(baseUrl, `/positions/${positionId}/adjust-advance`);
|
|
6752
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset,
|
|
6480
|
+
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
6753
6481
|
const translatedPayload = (payload || []).map((item) => ({
|
|
6754
6482
|
longAssets: mapAssets(item.longAssets),
|
|
6755
6483
|
shortAssets: mapAssets(item.shortAssets),
|
|
@@ -6874,62 +6602,16 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
6874
6602
|
});
|
|
6875
6603
|
};
|
|
6876
6604
|
|
|
6877
|
-
// Helper to find asset metadata from perpMetaAssets
|
|
6878
|
-
function findAssetMeta$1(coinName, perpMetaAssets) {
|
|
6879
|
-
var _a, _b, _c, _d;
|
|
6880
|
-
if (!perpMetaAssets) {
|
|
6881
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
6882
|
-
}
|
|
6883
|
-
// Try exact match first (for prefixed assets like "xyz:TSLA")
|
|
6884
|
-
const exactMatch = perpMetaAssets.find((a) => a.name === coinName);
|
|
6885
|
-
if (exactMatch) {
|
|
6886
|
-
return {
|
|
6887
|
-
collateralToken: (_a = exactMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
6888
|
-
marketPrefix: (_b = exactMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
6889
|
-
};
|
|
6890
|
-
}
|
|
6891
|
-
// Try matching by base symbol (for non-prefixed names in data)
|
|
6892
|
-
const baseMatch = perpMetaAssets.find((a) => {
|
|
6893
|
-
const baseName = a.name.includes(':') ? a.name.split(':')[1] : a.name;
|
|
6894
|
-
return baseName === coinName;
|
|
6895
|
-
});
|
|
6896
|
-
if (baseMatch) {
|
|
6897
|
-
return {
|
|
6898
|
-
collateralToken: (_c = baseMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
6899
|
-
marketPrefix: (_d = baseMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
6900
|
-
};
|
|
6901
|
-
}
|
|
6902
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
6903
|
-
}
|
|
6904
|
-
// Enrich position assets with market prefix and collateral token
|
|
6905
|
-
function enrichPositionAssets(assets, perpMetaAssets) {
|
|
6906
|
-
return assets.map((asset) => {
|
|
6907
|
-
const meta = findAssetMeta$1(asset.coin, perpMetaAssets);
|
|
6908
|
-
return {
|
|
6909
|
-
...asset,
|
|
6910
|
-
marketPrefix: meta.marketPrefix,
|
|
6911
|
-
collateralToken: meta.collateralToken,
|
|
6912
|
-
};
|
|
6913
|
-
});
|
|
6914
|
-
}
|
|
6915
|
-
// Enrich all positions with market metadata
|
|
6916
|
-
function enrichPositions(positions, perpMetaAssets) {
|
|
6917
|
-
return positions.map((position) => ({
|
|
6918
|
-
...position,
|
|
6919
|
-
longAssets: enrichPositionAssets(position.longAssets, perpMetaAssets),
|
|
6920
|
-
shortAssets: enrichPositionAssets(position.shortAssets, perpMetaAssets),
|
|
6921
|
-
}));
|
|
6922
|
-
}
|
|
6923
6605
|
function usePosition() {
|
|
6924
6606
|
const context = useContext(PearHyperliquidContext);
|
|
6925
6607
|
if (!context) {
|
|
6926
6608
|
throw new Error('usePosition must be used within a PearHyperliquidProvider');
|
|
6927
6609
|
}
|
|
6928
6610
|
const { apiBaseUrl, isConnected } = context;
|
|
6929
|
-
const
|
|
6611
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
6930
6612
|
// Create position API action
|
|
6931
6613
|
const createPosition$1 = async (payload) => {
|
|
6932
|
-
return createPosition(apiBaseUrl, payload,
|
|
6614
|
+
return createPosition(apiBaseUrl, payload, displayToFull);
|
|
6933
6615
|
};
|
|
6934
6616
|
// Update TP/SL risk parameters for a position
|
|
6935
6617
|
const updateRiskParameters$1 = async (positionId, payload) => {
|
|
@@ -6949,47 +6631,28 @@ function usePosition() {
|
|
|
6949
6631
|
};
|
|
6950
6632
|
// Adjust to absolute target sizes per asset, optionally adding new assets
|
|
6951
6633
|
const adjustAdvancePosition$1 = async (positionId, payload) => {
|
|
6952
|
-
return adjustAdvancePosition(apiBaseUrl, positionId, payload,
|
|
6634
|
+
return adjustAdvancePosition(apiBaseUrl, positionId, payload, displayToFull);
|
|
6953
6635
|
};
|
|
6954
6636
|
// Open positions using WS data, with derived values
|
|
6955
6637
|
const userOpenPositions = useUserData((state) => state.rawOpenPositions);
|
|
6956
6638
|
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
6957
6639
|
const allMids = useHyperliquidData((state) => state.allMids);
|
|
6958
|
-
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
6959
6640
|
const isLoading = useMemo(() => {
|
|
6960
6641
|
return userOpenPositions === null && isConnected;
|
|
6961
6642
|
}, [userOpenPositions, isConnected]);
|
|
6962
6643
|
const openPositions = useMemo(() => {
|
|
6963
6644
|
if (!userOpenPositions || !aggregatedClearingHouseState || !allMids)
|
|
6964
6645
|
return null;
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
}, [userOpenPositions, aggregatedClearingHouseState, allMids, perpMetaAssets]);
|
|
6969
|
-
return {
|
|
6970
|
-
createPosition: createPosition$1,
|
|
6971
|
-
updateRiskParameters: updateRiskParameters$1,
|
|
6972
|
-
closePosition: closePosition$1,
|
|
6973
|
-
closeAllPositions: closeAllPositions$1,
|
|
6974
|
-
adjustPosition: adjustPosition$1,
|
|
6975
|
-
adjustAdvancePosition: adjustAdvancePosition$1,
|
|
6976
|
-
openPositions,
|
|
6977
|
-
isLoading,
|
|
6978
|
-
};
|
|
6646
|
+
return buildPositionValue(userOpenPositions, aggregatedClearingHouseState, allMids);
|
|
6647
|
+
}, [userOpenPositions, aggregatedClearingHouseState, allMids]);
|
|
6648
|
+
return { createPosition: createPosition$1, updateRiskParameters: updateRiskParameters$1, closePosition: closePosition$1, closeAllPositions: closeAllPositions$1, adjustPosition: adjustPosition$1, adjustAdvancePosition: adjustAdvancePosition$1, openPositions, isLoading };
|
|
6979
6649
|
}
|
|
6980
6650
|
|
|
6981
6651
|
async function adjustOrder(baseUrl, orderId, payload) {
|
|
6982
6652
|
const url = joinUrl(baseUrl, `/orders/${orderId}/adjust`);
|
|
6983
6653
|
try {
|
|
6984
|
-
const resp = await apiClient.put(url, payload, {
|
|
6985
|
-
|
|
6986
|
-
timeout: 60000,
|
|
6987
|
-
});
|
|
6988
|
-
return {
|
|
6989
|
-
data: resp.data,
|
|
6990
|
-
status: resp.status,
|
|
6991
|
-
headers: resp.headers,
|
|
6992
|
-
};
|
|
6654
|
+
const resp = await apiClient.put(url, payload, { headers: { 'Content-Type': 'application/json' }, timeout: 60000 });
|
|
6655
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
6993
6656
|
}
|
|
6994
6657
|
catch (error) {
|
|
6995
6658
|
throw toApiError(error);
|
|
@@ -6998,14 +6661,8 @@ async function adjustOrder(baseUrl, orderId, payload) {
|
|
|
6998
6661
|
async function cancelOrder(baseUrl, orderId) {
|
|
6999
6662
|
const url = joinUrl(baseUrl, `/orders/${orderId}/cancel`);
|
|
7000
6663
|
try {
|
|
7001
|
-
const resp = await apiClient.delete(url, {
|
|
7002
|
-
|
|
7003
|
-
});
|
|
7004
|
-
return {
|
|
7005
|
-
data: resp.data,
|
|
7006
|
-
status: resp.status,
|
|
7007
|
-
headers: resp.headers,
|
|
7008
|
-
};
|
|
6664
|
+
const resp = await apiClient.delete(url, { timeout: 60000 });
|
|
6665
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7009
6666
|
}
|
|
7010
6667
|
catch (error) {
|
|
7011
6668
|
throw toApiError(error);
|
|
@@ -7015,32 +6672,7 @@ async function cancelTwapOrder(baseUrl, orderId) {
|
|
|
7015
6672
|
const url = joinUrl(baseUrl, `/orders/${orderId}/twap/cancel`);
|
|
7016
6673
|
try {
|
|
7017
6674
|
const resp = await apiClient.post(url, {}, { headers: { 'Content-Type': 'application/json' }, timeout: 60000 });
|
|
7018
|
-
return {
|
|
7019
|
-
data: resp.data,
|
|
7020
|
-
status: resp.status,
|
|
7021
|
-
headers: resp.headers,
|
|
7022
|
-
};
|
|
7023
|
-
}
|
|
7024
|
-
catch (error) {
|
|
7025
|
-
throw toApiError(error);
|
|
7026
|
-
}
|
|
7027
|
-
}
|
|
7028
|
-
/**
|
|
7029
|
-
* Execute a spot order (swap) using Pear Hyperliquid service
|
|
7030
|
-
* POST /orders/spot
|
|
7031
|
-
*/
|
|
7032
|
-
async function executeSpotOrder(baseUrl, payload) {
|
|
7033
|
-
const url = joinUrl(baseUrl, '/orders/spot');
|
|
7034
|
-
try {
|
|
7035
|
-
const resp = await apiClient.post(url, payload, {
|
|
7036
|
-
headers: { 'Content-Type': 'application/json' },
|
|
7037
|
-
timeout: 60000,
|
|
7038
|
-
});
|
|
7039
|
-
return {
|
|
7040
|
-
data: resp.data,
|
|
7041
|
-
status: resp.status,
|
|
7042
|
-
headers: resp.headers,
|
|
7043
|
-
};
|
|
6675
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7044
6676
|
}
|
|
7045
6677
|
catch (error) {
|
|
7046
6678
|
throw toApiError(error);
|
|
@@ -7096,45 +6728,6 @@ function useOrders() {
|
|
|
7096
6728
|
return { adjustOrder: adjustOrder$1, cancelOrder: cancelOrder$1, cancelTwapOrder: cancelTwapOrder$1, openOrders: enrichedOpenOrders, isLoading };
|
|
7097
6729
|
}
|
|
7098
6730
|
|
|
7099
|
-
/**
|
|
7100
|
-
* Hook for executing spot orders (swaps) on Hyperliquid
|
|
7101
|
-
* Use this to swap between USDC and USDH or other spot assets
|
|
7102
|
-
*/
|
|
7103
|
-
function useSpotOrder() {
|
|
7104
|
-
const context = useContext(PearHyperliquidContext);
|
|
7105
|
-
if (!context) {
|
|
7106
|
-
throw new Error('useSpotOrder must be used within a PearHyperliquidProvider');
|
|
7107
|
-
}
|
|
7108
|
-
const { apiBaseUrl } = context;
|
|
7109
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
7110
|
-
const [error, setError] = useState(null);
|
|
7111
|
-
const resetError = useCallback(() => {
|
|
7112
|
-
setError(null);
|
|
7113
|
-
}, []);
|
|
7114
|
-
const executeSpotOrder$1 = useCallback(async (payload) => {
|
|
7115
|
-
setIsLoading(true);
|
|
7116
|
-
setError(null);
|
|
7117
|
-
try {
|
|
7118
|
-
const response = await executeSpotOrder(apiBaseUrl, payload);
|
|
7119
|
-
return response;
|
|
7120
|
-
}
|
|
7121
|
-
catch (err) {
|
|
7122
|
-
const apiError = err;
|
|
7123
|
-
setError(apiError);
|
|
7124
|
-
throw apiError;
|
|
7125
|
-
}
|
|
7126
|
-
finally {
|
|
7127
|
-
setIsLoading(false);
|
|
7128
|
-
}
|
|
7129
|
-
}, [apiBaseUrl]);
|
|
7130
|
-
return {
|
|
7131
|
-
executeSpotOrder: executeSpotOrder$1,
|
|
7132
|
-
isLoading,
|
|
7133
|
-
error,
|
|
7134
|
-
resetError,
|
|
7135
|
-
};
|
|
7136
|
-
}
|
|
7137
|
-
|
|
7138
6731
|
function useTwap() {
|
|
7139
6732
|
const twapDetails = useUserData(state => state.twapDetails);
|
|
7140
6733
|
const context = useContext(PearHyperliquidContext);
|
|
@@ -7224,170 +6817,59 @@ function useNotifications() {
|
|
|
7224
6817
|
};
|
|
7225
6818
|
}
|
|
7226
6819
|
|
|
7227
|
-
//
|
|
7228
|
-
function findAssetMeta(assetName, perpMetaAssets) {
|
|
7229
|
-
var _a, _b, _c, _d;
|
|
7230
|
-
if (!perpMetaAssets) {
|
|
7231
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7232
|
-
}
|
|
7233
|
-
// Try exact match first (for prefixed assets like "xyz:TSLA")
|
|
7234
|
-
const exactMatch = perpMetaAssets.find((a) => a.name === assetName);
|
|
7235
|
-
if (exactMatch) {
|
|
7236
|
-
return {
|
|
7237
|
-
collateralToken: (_a = exactMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7238
|
-
marketPrefix: (_b = exactMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7239
|
-
};
|
|
7240
|
-
}
|
|
7241
|
-
// Try matching by base symbol (for non-prefixed names in data)
|
|
7242
|
-
const baseMatch = perpMetaAssets.find((a) => {
|
|
7243
|
-
const baseName = a.name.includes(':') ? a.name.split(':')[1] : a.name;
|
|
7244
|
-
return baseName === assetName;
|
|
7245
|
-
});
|
|
7246
|
-
if (baseMatch) {
|
|
7247
|
-
return {
|
|
7248
|
-
collateralToken: (_c = baseMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7249
|
-
marketPrefix: (_d = baseMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7250
|
-
};
|
|
7251
|
-
}
|
|
7252
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7253
|
-
}
|
|
7254
|
-
// Enrich a single asset with metadata
|
|
7255
|
-
function enrichAsset(asset, perpMetaAssets) {
|
|
7256
|
-
const meta = findAssetMeta(asset.asset, perpMetaAssets);
|
|
7257
|
-
return {
|
|
7258
|
-
...asset,
|
|
7259
|
-
collateralToken: meta.collateralToken,
|
|
7260
|
-
marketPrefix: meta.marketPrefix,
|
|
7261
|
-
};
|
|
7262
|
-
}
|
|
7263
|
-
// Enrich a basket item with collateral info
|
|
7264
|
-
function enrichBasketItem(item, perpMetaAssets) {
|
|
7265
|
-
const enrichedLongs = item.longAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7266
|
-
const enrichedShorts = item.shortAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7267
|
-
// Determine collateral type
|
|
7268
|
-
const allAssets = [...enrichedLongs, ...enrichedShorts];
|
|
7269
|
-
const hasUsdc = allAssets.some((a) => a.collateralToken === 'USDC');
|
|
7270
|
-
const hasUsdh = allAssets.some((a) => a.collateralToken === 'USDH');
|
|
7271
|
-
let collateralType = 'USDC';
|
|
7272
|
-
if (hasUsdc && hasUsdh) {
|
|
7273
|
-
collateralType = 'MIXED';
|
|
7274
|
-
}
|
|
7275
|
-
else if (hasUsdh) {
|
|
7276
|
-
collateralType = 'USDH';
|
|
7277
|
-
}
|
|
7278
|
-
return {
|
|
7279
|
-
...item,
|
|
7280
|
-
longAssets: enrichedLongs,
|
|
7281
|
-
shortAssets: enrichedShorts,
|
|
7282
|
-
collateralType,
|
|
7283
|
-
};
|
|
7284
|
-
}
|
|
7285
|
-
/**
|
|
7286
|
-
* Filter baskets by collateral type
|
|
7287
|
-
* - 'USDC': Only baskets where ALL assets use USDC (collateralType === 'USDC')
|
|
7288
|
-
* - 'USDH': Only baskets where ALL assets use USDH (collateralType === 'USDH')
|
|
7289
|
-
* - 'ALL' or undefined: No filtering, returns all baskets
|
|
7290
|
-
*/
|
|
7291
|
-
function filterByCollateral(baskets, filter) {
|
|
7292
|
-
if (!filter || filter === 'ALL') {
|
|
7293
|
-
return baskets;
|
|
7294
|
-
}
|
|
7295
|
-
return baskets.filter((basket) => {
|
|
7296
|
-
if (filter === 'USDC') {
|
|
7297
|
-
// Include baskets that are purely USDC or have USDC assets
|
|
7298
|
-
return (basket.collateralType === 'USDC' || basket.collateralType === 'MIXED');
|
|
7299
|
-
}
|
|
7300
|
-
if (filter === 'USDH') {
|
|
7301
|
-
// Include baskets that are purely USDH or have USDH assets
|
|
7302
|
-
return (basket.collateralType === 'USDH' || basket.collateralType === 'MIXED');
|
|
7303
|
-
}
|
|
7304
|
-
return true;
|
|
7305
|
-
});
|
|
7306
|
-
}
|
|
7307
|
-
// Base selector for the full market-data payload (raw from WS)
|
|
6820
|
+
// Base selector for the full market-data payload
|
|
7308
6821
|
const useMarketDataPayload = () => {
|
|
7309
6822
|
return useMarketData((s) => s.marketData);
|
|
7310
6823
|
};
|
|
7311
|
-
// Full payload for 'market-data-all' channel
|
|
6824
|
+
// Full payload for 'market-data-all' channel
|
|
7312
6825
|
const useMarketDataAllPayload = () => {
|
|
7313
6826
|
return useMarketData((s) => s.marketDataAll);
|
|
7314
6827
|
};
|
|
7315
|
-
//
|
|
7316
|
-
const
|
|
7317
|
-
|
|
7318
|
-
};
|
|
7319
|
-
// Active baskets (with collateral and market prefix info)
|
|
7320
|
-
const useActiveBaskets = (collateralFilter) => {
|
|
6828
|
+
// Active baskets
|
|
6829
|
+
const useActiveBaskets = () => {
|
|
6830
|
+
var _a;
|
|
7321
6831
|
const data = useMarketDataPayload();
|
|
7322
|
-
|
|
7323
|
-
return useMemo(() => {
|
|
7324
|
-
if (!(data === null || data === void 0 ? void 0 : data.active))
|
|
7325
|
-
return [];
|
|
7326
|
-
const enriched = data.active.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7327
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7328
|
-
}, [data, perpMetaAssets, collateralFilter]);
|
|
6832
|
+
return (_a = data === null || data === void 0 ? void 0 : data.active) !== null && _a !== void 0 ? _a : [];
|
|
7329
6833
|
};
|
|
7330
|
-
// Top gainers (
|
|
7331
|
-
const useTopGainers = (limit
|
|
6834
|
+
// Top gainers (optional limit override)
|
|
6835
|
+
const useTopGainers = (limit) => {
|
|
7332
6836
|
const data = useMarketDataPayload();
|
|
7333
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7334
6837
|
return useMemo(() => {
|
|
7335
6838
|
var _a;
|
|
7336
6839
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topGainers) !== null && _a !== void 0 ? _a : [];
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7340
|
-
}, [data, perpMetaAssets, limit, collateralFilter]);
|
|
6840
|
+
return typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
6841
|
+
}, [data, limit]);
|
|
7341
6842
|
};
|
|
7342
|
-
// Top losers (
|
|
7343
|
-
const useTopLosers = (limit
|
|
6843
|
+
// Top losers (optional limit override)
|
|
6844
|
+
const useTopLosers = (limit) => {
|
|
7344
6845
|
const data = useMarketDataPayload();
|
|
7345
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7346
6846
|
return useMemo(() => {
|
|
7347
6847
|
var _a;
|
|
7348
6848
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topLosers) !== null && _a !== void 0 ? _a : [];
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7352
|
-
}, [data, perpMetaAssets, limit, collateralFilter]);
|
|
6849
|
+
return typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
6850
|
+
}, [data, limit]);
|
|
7353
6851
|
};
|
|
7354
|
-
// Highlighted baskets
|
|
7355
|
-
const useHighlightedBaskets = (
|
|
6852
|
+
// Highlighted baskets
|
|
6853
|
+
const useHighlightedBaskets = () => {
|
|
6854
|
+
var _a;
|
|
7356
6855
|
const data = useMarketDataPayload();
|
|
7357
|
-
|
|
7358
|
-
return useMemo(() => {
|
|
7359
|
-
if (!(data === null || data === void 0 ? void 0 : data.highlighted))
|
|
7360
|
-
return [];
|
|
7361
|
-
const enriched = data.highlighted.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7362
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7363
|
-
}, [data, perpMetaAssets, collateralFilter]);
|
|
6856
|
+
return (_a = data === null || data === void 0 ? void 0 : data.highlighted) !== null && _a !== void 0 ? _a : [];
|
|
7364
6857
|
};
|
|
7365
|
-
// Watchlist baskets (
|
|
7366
|
-
const useWatchlistBaskets = (
|
|
6858
|
+
// Watchlist baskets (from market-data payload when subscribed with address)
|
|
6859
|
+
const useWatchlistBaskets = () => {
|
|
6860
|
+
var _a;
|
|
7367
6861
|
const data = useMarketDataPayload();
|
|
7368
|
-
|
|
7369
|
-
return useMemo(() => {
|
|
7370
|
-
if (!(data === null || data === void 0 ? void 0 : data.watchlist))
|
|
7371
|
-
return [];
|
|
7372
|
-
const enriched = data.watchlist.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7373
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7374
|
-
}, [data, perpMetaAssets, collateralFilter]);
|
|
6862
|
+
return (_a = data === null || data === void 0 ? void 0 : data.watchlist) !== null && _a !== void 0 ? _a : [];
|
|
7375
6863
|
};
|
|
7376
|
-
// All baskets (
|
|
7377
|
-
const useAllBaskets = (
|
|
6864
|
+
// All baskets (from market-data-all)
|
|
6865
|
+
const useAllBaskets = () => {
|
|
6866
|
+
var _a;
|
|
7378
6867
|
const dataAll = useMarketDataAllPayload();
|
|
7379
|
-
|
|
7380
|
-
return useMemo(() => {
|
|
7381
|
-
if (!(dataAll === null || dataAll === void 0 ? void 0 : dataAll.all))
|
|
7382
|
-
return [];
|
|
7383
|
-
const enriched = dataAll.all.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7384
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7385
|
-
}, [dataAll, perpMetaAssets, collateralFilter]);
|
|
6868
|
+
return (_a = dataAll === null || dataAll === void 0 ? void 0 : dataAll.all) !== null && _a !== void 0 ? _a : [];
|
|
7386
6869
|
};
|
|
7387
6870
|
// Find a basket by its exact asset composition (order-insensitive)
|
|
7388
6871
|
const useFindBasket = (longs, shorts) => {
|
|
7389
6872
|
const data = useMarketDataPayload();
|
|
7390
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7391
6873
|
return useMemo(() => {
|
|
7392
6874
|
if (!data)
|
|
7393
6875
|
return undefined;
|
|
@@ -7401,28 +6883,17 @@ const useFindBasket = (longs, shorts) => {
|
|
|
7401
6883
|
: '';
|
|
7402
6884
|
const lKey = normalize(longs);
|
|
7403
6885
|
const sKey = normalize(shorts);
|
|
7404
|
-
const match = (item) => normalize(item.longAssets) === lKey &&
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
return found
|
|
7408
|
-
? enrichBasketItem(found, perpMetaAssets)
|
|
7409
|
-
: undefined;
|
|
7410
|
-
}, [data, longs, shorts, perpMetaAssets]);
|
|
6886
|
+
const match = (item) => normalize(item.longAssets) === lKey && normalize(item.shortAssets) === sKey;
|
|
6887
|
+
return data.active.find(match) || data.highlighted.find(match);
|
|
6888
|
+
}, [data, longs, shorts]);
|
|
7411
6889
|
};
|
|
7412
6890
|
|
|
7413
|
-
async function toggleWatchlist(baseUrl, longAssets, shortAssets,
|
|
6891
|
+
async function toggleWatchlist(baseUrl, longAssets, shortAssets, displayToFull) {
|
|
7414
6892
|
const url = joinUrl(baseUrl, '/watchlist');
|
|
7415
|
-
const mapAssets = (arr) => arr.map(
|
|
6893
|
+
const mapAssets = (arr) => arr.map(a => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
7416
6894
|
try {
|
|
7417
|
-
const response = await apiClient.post(url, {
|
|
7418
|
-
|
|
7419
|
-
shortAssets: mapAssets(shortAssets),
|
|
7420
|
-
}, { headers: { 'Content-Type': 'application/json' } });
|
|
7421
|
-
return {
|
|
7422
|
-
data: response.data,
|
|
7423
|
-
status: response.status,
|
|
7424
|
-
headers: response.headers,
|
|
7425
|
-
};
|
|
6895
|
+
const response = await apiClient.post(url, { longAssets: mapAssets(longAssets), shortAssets: mapAssets(shortAssets) }, { headers: { 'Content-Type': 'application/json' } });
|
|
6896
|
+
return { data: response.data, status: response.status, headers: response.headers };
|
|
7426
6897
|
}
|
|
7427
6898
|
catch (error) {
|
|
7428
6899
|
throw toApiError(error);
|
|
@@ -7434,11 +6905,11 @@ function useWatchlist() {
|
|
|
7434
6905
|
if (!context)
|
|
7435
6906
|
throw new Error('useWatchlist must be used within a PearHyperliquidProvider');
|
|
7436
6907
|
const { apiBaseUrl, isConnected } = context;
|
|
7437
|
-
const
|
|
6908
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
7438
6909
|
const marketData = useMarketDataPayload();
|
|
7439
6910
|
const isLoading = useMemo(() => !marketData && isConnected, [marketData, isConnected]);
|
|
7440
6911
|
const toggle = async (longAssets, shortAssets) => {
|
|
7441
|
-
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets,
|
|
6912
|
+
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets, displayToFull);
|
|
7442
6913
|
// Server will push updated market-data over WS; nothing to set here
|
|
7443
6914
|
return resp;
|
|
7444
6915
|
};
|
|
@@ -7560,36 +7031,47 @@ async function logout(baseUrl, refreshTokenVal) {
|
|
|
7560
7031
|
function useAuth() {
|
|
7561
7032
|
const context = useContext(PearHyperliquidContext);
|
|
7562
7033
|
if (!context) {
|
|
7563
|
-
throw new Error(
|
|
7034
|
+
throw new Error("useAuth must be used within a PearHyperliquidProvider");
|
|
7564
7035
|
}
|
|
7565
7036
|
const { apiBaseUrl, clientId } = context;
|
|
7566
|
-
const [isReady, setIsReady] = useState(false);
|
|
7567
7037
|
const accessToken = useUserData((s) => s.accessToken);
|
|
7568
7038
|
const refreshToken$1 = useUserData((s) => s.refreshToken);
|
|
7039
|
+
const isReady = useUserData((s) => s.isReady);
|
|
7040
|
+
const isAuthenticated = useUserData((s) => s.isAuthenticated);
|
|
7041
|
+
const address = useUserData((s) => s.address);
|
|
7569
7042
|
const setAccessToken = useUserData((s) => s.setAccessToken);
|
|
7570
7043
|
const setRefreshToken = useUserData((s) => s.setRefreshToken);
|
|
7571
|
-
const
|
|
7044
|
+
const setIsReady = useUserData((s) => s.setIsReady);
|
|
7572
7045
|
const setIsAuthenticated = useUserData((s) => s.setIsAuthenticated);
|
|
7573
7046
|
const setAddress = useUserData((s) => s.setAddress);
|
|
7047
|
+
console.log("sdk", { sdkAddress: address });
|
|
7574
7048
|
useEffect(() => {
|
|
7575
|
-
if (typeof window ==
|
|
7049
|
+
if (typeof window == "undefined") {
|
|
7576
7050
|
return;
|
|
7577
7051
|
}
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7052
|
+
if (address) {
|
|
7053
|
+
// If we already have an address in state, use it to load the session
|
|
7054
|
+
const accessTokenKey = `${address}_accessToken`;
|
|
7055
|
+
const refreshTokenKey = `${address}_refreshToken`;
|
|
7056
|
+
const storedAccessToken = localStorage.getItem(accessTokenKey);
|
|
7057
|
+
const storedRefreshToken = localStorage.getItem(refreshTokenKey);
|
|
7058
|
+
console.log({ storedAccessToken, storedRefreshToken });
|
|
7059
|
+
if (storedAccessToken && storedRefreshToken) {
|
|
7060
|
+
setAccessToken(storedAccessToken);
|
|
7061
|
+
setRefreshToken(storedRefreshToken);
|
|
7062
|
+
setIsAuthenticated(true);
|
|
7063
|
+
}
|
|
7064
|
+
}
|
|
7586
7065
|
setIsReady(true);
|
|
7587
|
-
}, [
|
|
7066
|
+
}, [address]);
|
|
7588
7067
|
useEffect(() => {
|
|
7589
7068
|
const cleanup = addAuthInterceptors({
|
|
7590
7069
|
apiBaseUrl,
|
|
7591
7070
|
getAccessToken: () => {
|
|
7592
|
-
|
|
7071
|
+
if (typeof window === "undefined")
|
|
7072
|
+
return null;
|
|
7073
|
+
// Read from Zustand state as single source of truth
|
|
7074
|
+
return useUserData.getState().accessToken;
|
|
7593
7075
|
},
|
|
7594
7076
|
refreshTokens: async () => {
|
|
7595
7077
|
const data = await refreshTokens();
|
|
@@ -7610,17 +7092,18 @@ function useAuth() {
|
|
|
7610
7092
|
async function loginWithSignedMessage(address, signature, timestamp) {
|
|
7611
7093
|
try {
|
|
7612
7094
|
const { data } = await authenticate(apiBaseUrl, {
|
|
7613
|
-
method:
|
|
7095
|
+
method: "eip712",
|
|
7614
7096
|
address,
|
|
7615
7097
|
clientId,
|
|
7616
7098
|
details: { signature, timestamp },
|
|
7617
7099
|
});
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
window.localStorage.setItem(
|
|
7100
|
+
const accessTokenKey = `${address}_accessToken`;
|
|
7101
|
+
const refreshTokenKey = `${address}_refreshToken`;
|
|
7102
|
+
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7103
|
+
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
7621
7104
|
setAccessToken(data.accessToken);
|
|
7622
7105
|
setRefreshToken(data.refreshToken);
|
|
7623
|
-
setAddress(address);
|
|
7106
|
+
// setAddress(address);
|
|
7624
7107
|
setIsAuthenticated(true);
|
|
7625
7108
|
}
|
|
7626
7109
|
catch (e) {
|
|
@@ -7629,13 +7112,19 @@ function useAuth() {
|
|
|
7629
7112
|
}
|
|
7630
7113
|
async function loginWithPrivyToken(address, appId, privyAccessToken) {
|
|
7631
7114
|
try {
|
|
7632
|
-
const { data } = await authenticateWithPrivy(apiBaseUrl, {
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7115
|
+
const { data } = await authenticateWithPrivy(apiBaseUrl, {
|
|
7116
|
+
address,
|
|
7117
|
+
clientId,
|
|
7118
|
+
appId,
|
|
7119
|
+
accessToken: privyAccessToken,
|
|
7120
|
+
});
|
|
7121
|
+
const accessTokenKey = `${address}_accessToken`;
|
|
7122
|
+
const refreshTokenKey = `${address}_refreshToken`;
|
|
7123
|
+
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7124
|
+
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
7636
7125
|
setAccessToken(data.accessToken);
|
|
7637
7126
|
setRefreshToken(data.refreshToken);
|
|
7638
|
-
setAddress(address);
|
|
7127
|
+
// setAddress(address);
|
|
7639
7128
|
setIsAuthenticated(true);
|
|
7640
7129
|
}
|
|
7641
7130
|
catch (e) {
|
|
@@ -7643,31 +7132,41 @@ function useAuth() {
|
|
|
7643
7132
|
}
|
|
7644
7133
|
}
|
|
7645
7134
|
async function refreshTokens() {
|
|
7646
|
-
const
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7135
|
+
const currentAddress = address;
|
|
7136
|
+
const currentRefresh = refreshToken$1;
|
|
7137
|
+
if (!currentRefresh || !currentAddress)
|
|
7138
|
+
throw new Error("No refresh token");
|
|
7139
|
+
const { data } = await refreshToken(apiBaseUrl, currentRefresh);
|
|
7140
|
+
// Update tokens in localStorage
|
|
7141
|
+
const accessTokenKey = `${currentAddress}_accessToken`;
|
|
7142
|
+
const refreshTokenKey = `${currentAddress}_refreshToken`;
|
|
7143
|
+
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7144
|
+
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
7652
7145
|
setAccessToken(data.accessToken);
|
|
7653
7146
|
setRefreshToken(data.refreshToken);
|
|
7654
7147
|
setIsAuthenticated(true);
|
|
7655
7148
|
return data;
|
|
7656
7149
|
}
|
|
7657
7150
|
async function logout$1() {
|
|
7658
|
-
const
|
|
7659
|
-
|
|
7151
|
+
const currentAddress = address;
|
|
7152
|
+
const currentRefresh = refreshToken$1;
|
|
7153
|
+
if (currentRefresh) {
|
|
7660
7154
|
try {
|
|
7661
|
-
await logout(apiBaseUrl,
|
|
7155
|
+
await logout(apiBaseUrl, currentRefresh);
|
|
7662
7156
|
}
|
|
7663
|
-
catch (
|
|
7157
|
+
catch (_a) {
|
|
7158
|
+
/* ignore */
|
|
7159
|
+
}
|
|
7160
|
+
}
|
|
7161
|
+
if (currentAddress) {
|
|
7162
|
+
const accessTokenKey = `${currentAddress}_accessToken`;
|
|
7163
|
+
const refreshTokenKey = `${currentAddress}_refreshToken`;
|
|
7164
|
+
window.localStorage.removeItem(accessTokenKey);
|
|
7165
|
+
window.localStorage.removeItem(refreshTokenKey);
|
|
7664
7166
|
}
|
|
7665
|
-
window.localStorage.removeItem('accessToken');
|
|
7666
|
-
window.localStorage.removeItem('refreshToken');
|
|
7667
|
-
window.localStorage.removeItem('address');
|
|
7668
7167
|
setAccessToken(null);
|
|
7669
7168
|
setRefreshToken(null);
|
|
7670
|
-
setAddress(null);
|
|
7169
|
+
// setAddress(null);
|
|
7671
7170
|
setIsAuthenticated(false);
|
|
7672
7171
|
}
|
|
7673
7172
|
return {
|
|
@@ -7680,6 +7179,8 @@ function useAuth() {
|
|
|
7680
7179
|
loginWithPrivyToken,
|
|
7681
7180
|
refreshTokens,
|
|
7682
7181
|
logout: logout$1,
|
|
7182
|
+
setAddress,
|
|
7183
|
+
address,
|
|
7683
7184
|
};
|
|
7684
7185
|
}
|
|
7685
7186
|
|
|
@@ -7687,13 +7188,11 @@ const PearHyperliquidContext = createContext(undefined);
|
|
|
7687
7188
|
/**
|
|
7688
7189
|
* React Provider for PearHyperliquidClient
|
|
7689
7190
|
*/
|
|
7690
|
-
const PearHyperliquidProvider = ({ children, apiBaseUrl =
|
|
7191
|
+
const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-v2.pearprotocol.io", clientId = "PEARPROTOCOLUI", wsUrl = "wss://hl-v2.pearprotocol.io/ws", }) => {
|
|
7691
7192
|
const address = useUserData((s) => s.address);
|
|
7692
|
-
const setAddress = useUserData((s) => s.setAddress);
|
|
7693
7193
|
const perpsMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
7694
7194
|
const setPerpMetaAssets = useHyperliquidData((state) => state.setPerpMetaAssets);
|
|
7695
|
-
const
|
|
7696
|
-
const setHip3MarketPrefixes = useHyperliquidData((state) => state.setHip3MarketPrefixes);
|
|
7195
|
+
const setHip3DisplayToFull = useHyperliquidData((state) => state.setHip3DisplayToFull);
|
|
7697
7196
|
const websocketsEnabled = useMemo(() => Array.isArray(perpsMetaAssets) && perpsMetaAssets.length > 0, [perpsMetaAssets]);
|
|
7698
7197
|
const { isConnected, lastError } = useHyperliquidWebSocket({
|
|
7699
7198
|
wsUrl,
|
|
@@ -7708,62 +7207,28 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
7708
7207
|
if (perpsMetaAssets === null) {
|
|
7709
7208
|
fetchAllPerpMetas()
|
|
7710
7209
|
.then((res) => {
|
|
7711
|
-
|
|
7712
|
-
const
|
|
7713
|
-
const
|
|
7714
|
-
const cleanedPerpMetas =
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
const fullName = `${prefix}:${displayName}`;
|
|
7727
|
-
// Store full market name with prefix
|
|
7728
|
-
marketPrefixes.set(fullName, prefix);
|
|
7729
|
-
// Track all markets for this asset
|
|
7730
|
-
const existingMarkets = (_a = assetToMarkets.get(displayName)) !== null && _a !== void 0 ? _a : [];
|
|
7731
|
-
if (!existingMarkets.includes(fullName)) {
|
|
7732
|
-
assetToMarkets.set(displayName, [
|
|
7733
|
-
...existingMarkets,
|
|
7734
|
-
fullName,
|
|
7735
|
-
]);
|
|
7736
|
-
}
|
|
7737
|
-
// Add asset with all metadata INCLUDING collateral token for THIS specific market
|
|
7738
|
-
// Important: We keep ALL variants so each market+collateral combo is tracked
|
|
7739
|
-
cleanedPerpMetas.push({
|
|
7740
|
-
...asset,
|
|
7741
|
-
name: displayName, // Use display name for UI
|
|
7742
|
-
marketPrefix: prefix, // Which market (xyz, flx, etc)
|
|
7743
|
-
collateralToken, // "USDC" or "USDH"
|
|
7744
|
-
});
|
|
7745
|
-
}
|
|
7746
|
-
else {
|
|
7747
|
-
// Regular market without prefix
|
|
7748
|
-
cleanedPerpMetas.push({
|
|
7749
|
-
...asset,
|
|
7750
|
-
collateralToken, // "USDC" or "USDH"
|
|
7751
|
-
});
|
|
7752
|
-
}
|
|
7753
|
-
});
|
|
7210
|
+
const aggregatedPerpMetas = res.data.flatMap((item) => item.universe);
|
|
7211
|
+
const hip3Map = new Map();
|
|
7212
|
+
const displayToFull = new Map();
|
|
7213
|
+
const cleanedPerpMetas = aggregatedPerpMetas.map((asset) => {
|
|
7214
|
+
var _a;
|
|
7215
|
+
const [maybePrefix, maybeMarket] = asset.name.split(":");
|
|
7216
|
+
if (maybeMarket) {
|
|
7217
|
+
const prefix = maybePrefix.toLowerCase();
|
|
7218
|
+
const market = maybeMarket;
|
|
7219
|
+
const existing = (_a = hip3Map.get(prefix)) !== null && _a !== void 0 ? _a : [];
|
|
7220
|
+
hip3Map.set(prefix, [...existing, market]);
|
|
7221
|
+
displayToFull.set(market, `${prefix}:${market}`);
|
|
7222
|
+
return { ...asset, name: market };
|
|
7223
|
+
}
|
|
7224
|
+
return asset;
|
|
7754
7225
|
});
|
|
7755
|
-
|
|
7756
|
-
setHip3MarketPrefixes(marketPrefixes);
|
|
7226
|
+
setHip3DisplayToFull(displayToFull);
|
|
7757
7227
|
setPerpMetaAssets(cleanedPerpMetas);
|
|
7758
7228
|
})
|
|
7759
7229
|
.catch(() => { });
|
|
7760
7230
|
}
|
|
7761
|
-
}, [
|
|
7762
|
-
perpsMetaAssets,
|
|
7763
|
-
setPerpMetaAssets,
|
|
7764
|
-
setHip3Assets,
|
|
7765
|
-
setHip3MarketPrefixes,
|
|
7766
|
-
]);
|
|
7231
|
+
}, [perpsMetaAssets, setPerpMetaAssets, setHip3DisplayToFull]);
|
|
7767
7232
|
// Auth methods now sourced from useAuth hook
|
|
7768
7233
|
useAutoSyncFills({
|
|
7769
7234
|
baseUrl: apiBaseUrl,
|
|
@@ -7786,8 +7251,6 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
7786
7251
|
}), [
|
|
7787
7252
|
apiBaseUrl,
|
|
7788
7253
|
wsUrl,
|
|
7789
|
-
address,
|
|
7790
|
-
setAddress,
|
|
7791
7254
|
isConnected,
|
|
7792
7255
|
lastError,
|
|
7793
7256
|
nativeIsConnected,
|
|
@@ -7802,7 +7265,7 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
7802
7265
|
function usePearHyperliquid() {
|
|
7803
7266
|
const ctx = useContext(PearHyperliquidContext);
|
|
7804
7267
|
if (!ctx)
|
|
7805
|
-
throw new Error(
|
|
7268
|
+
throw new Error("usePearHyperliquid must be used within a PearHyperliquidProvider");
|
|
7806
7269
|
return ctx;
|
|
7807
7270
|
}
|
|
7808
7271
|
|
|
@@ -7893,4 +7356,4 @@ function mapCandleIntervalToTradingViewInterval(interval) {
|
|
|
7893
7356
|
}
|
|
7894
7357
|
}
|
|
7895
7358
|
|
|
7896
|
-
export { AccountSummaryCalculator, ConflictDetector, MINIMUM_ASSET_USD_VALUE, MinimumPositionSizeError, PearHyperliquidProvider, TokenMetadataExtractor, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition,
|
|
7359
|
+
export { AccountSummaryCalculator, ConflictDetector, MINIMUM_ASSET_USD_VALUE, MinimumPositionSizeError, PearHyperliquidProvider, TokenMetadataExtractor, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, getCompleteTimestamps, getPortfolio, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateRiskParameters, useAccountSummary, useActiveBaskets, useAgentWallet, useAllBaskets, useAuth, useAutoSyncFills, useBasketCandles, useFindBasket, useHighlightedBaskets, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMarketData, useMarketDataAllPayload, useMarketDataPayload, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePortfolio, usePosition, useTokenSelectionMetadata, useTopGainers, useTopLosers, useTradeHistories, useTwap, useUserSelection, useWatchlist, useWatchlistBaskets, useWebData, validateMinimumAssetSize, validatePositionSize };
|