@pear-protocol/hyperliquid-sdk 0.0.7-2.1 → 0.0.7-3.beta
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 -2
- package/dist/hooks/useAuth.d.ts +5 -3
- package/dist/hooks/useMarketData.d.ts +7 -9
- package/dist/hooks/useTrading.d.ts +3 -0
- package/dist/hooks/useWebData.d.ts +3 -21
- package/dist/index.d.ts +66 -223
- package/dist/index.js +309 -1324
- 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 +20 -74
- 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/useAllUserBalances.d.ts +0 -9
- 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,
|
|
@@ -23,40 +64,38 @@ const useUserData = create((set) => ({
|
|
|
23
64
|
twapDetails: null,
|
|
24
65
|
notifications: null,
|
|
25
66
|
userExtraAgents: null,
|
|
26
|
-
spotState: null,
|
|
27
67
|
setAccessToken: (token) => set({ accessToken: token }),
|
|
28
68
|
setRefreshToken: (token) => set({ refreshToken: token }),
|
|
29
69
|
setIsAuthenticated: (value) => set({ isAuthenticated: value }),
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
}
|
|
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
|
+
},
|
|
41
81
|
setTradeHistories: (value) => set({ tradeHistories: value }),
|
|
42
82
|
setRawOpenPositions: (value) => set({ rawOpenPositions: value }),
|
|
43
83
|
setOpenOrders: (value) => set({ openOrders: value }),
|
|
44
84
|
setAccountSummary: (value) => set({ accountSummary: value }),
|
|
45
85
|
setTwapDetails: (value) => set({ twapDetails: value }),
|
|
46
86
|
setNotifications: (value) => set({ notifications: value }),
|
|
47
|
-
setSpotState: (value) => set({ spotState: value }),
|
|
48
87
|
clean: () => set({
|
|
49
|
-
accessToken: null,
|
|
50
|
-
refreshToken: null,
|
|
51
|
-
isAuthenticated: false,
|
|
52
|
-
|
|
88
|
+
// accessToken: null,
|
|
89
|
+
// refreshToken: null,
|
|
90
|
+
// isAuthenticated: false,
|
|
91
|
+
// isReady: false,
|
|
92
|
+
// address: null,
|
|
53
93
|
tradeHistories: null,
|
|
54
94
|
rawOpenPositions: null,
|
|
55
95
|
openOrders: null,
|
|
56
96
|
accountSummary: null,
|
|
57
97
|
twapDetails: null,
|
|
58
98
|
notifications: null,
|
|
59
|
-
spotState: null,
|
|
60
99
|
}),
|
|
61
100
|
setUserExtraAgents: (value) => set({ userExtraAgents: value }),
|
|
62
101
|
}));
|
|
@@ -74,71 +113,18 @@ const useMarketData = create((set) => ({
|
|
|
74
113
|
* Convert a full/prefixed symbol (e.g., "xyz:XYZ100") to a display symbol (e.g., "XYZ100").
|
|
75
114
|
*/
|
|
76
115
|
function toDisplaySymbol(symbol) {
|
|
77
|
-
const parts = symbol.split(
|
|
116
|
+
const parts = symbol.split(":");
|
|
78
117
|
return parts.length > 1 ? parts.slice(-1)[0] : symbol;
|
|
79
118
|
}
|
|
80
119
|
/**
|
|
81
120
|
* Convert a display symbol back to backend form using a provided map.
|
|
82
121
|
* If mapping is missing, returns the original symbol.
|
|
83
|
-
*
|
|
84
|
-
* @param
|
|
85
|
-
* @param hip3Assets map of display -> all full market names (e.g., "TSLA" -> ["xyz:TSLA", "flx:TSLA"])
|
|
86
|
-
*/
|
|
87
|
-
function toBackendSymbol(displaySymbol, hip3Assets) {
|
|
88
|
-
const markets = hip3Assets.get(displaySymbol);
|
|
89
|
-
// Return first market if available, otherwise return original symbol
|
|
90
|
-
return markets && markets.length > 0 ? markets[0] : displaySymbol;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Convert a display symbol to backend form for a specific market prefix.
|
|
94
|
-
* This is useful when an asset is available on multiple markets (e.g., xyz:TSLA and flx:TSLA).
|
|
95
|
-
* @param displaySymbol e.g., "TSLA"
|
|
96
|
-
* @param marketPrefix e.g., "xyz" or "flx"
|
|
97
|
-
* @param hip3Assets map of display -> all full market names
|
|
98
|
-
* @returns Full market name if found, null if prefix not specified for multi-market asset, otherwise displaySymbol with prefix
|
|
99
|
-
*/
|
|
100
|
-
function toBackendSymbolWithMarket(displaySymbol, marketPrefix, hip3Assets) {
|
|
101
|
-
const availableMarkets = hip3Assets.get(displaySymbol);
|
|
102
|
-
if (!availableMarkets || availableMarkets.length === 0) {
|
|
103
|
-
// Not a HIP-3 asset, return as-is or with prefix if provided
|
|
104
|
-
return marketPrefix ? `${marketPrefix}:${displaySymbol}` : displaySymbol;
|
|
105
|
-
}
|
|
106
|
-
if (marketPrefix) {
|
|
107
|
-
// Find the market with the specified prefix
|
|
108
|
-
const targetMarket = availableMarkets.find((market) => market.toLowerCase().startsWith(`${marketPrefix.toLowerCase()}:`));
|
|
109
|
-
if (targetMarket) {
|
|
110
|
-
return targetMarket;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// No prefix specified or not found, return null to force explicit market selection
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Get all available markets for a display symbol.
|
|
118
|
-
* @param displaySymbol e.g., "TSLA"
|
|
119
|
-
* @param hip3Assets map of display -> all full market names
|
|
120
|
-
* @returns Array of full market names, e.g., ["xyz:TSLA", "flx:TSLA"]
|
|
122
|
+
* @param displaySymbol e.g., "XYZ100"
|
|
123
|
+
* @param displayToFull map of display -> full (e.g., "XYZ100" -> "xyz:XYZ100")
|
|
121
124
|
*/
|
|
122
|
-
function
|
|
125
|
+
function toBackendSymbol(displaySymbol, displayToFull) {
|
|
123
126
|
var _a;
|
|
124
|
-
return (_a =
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Extract the market prefix from a full market name.
|
|
128
|
-
* @param fullSymbol e.g., "xyz:TSLA"
|
|
129
|
-
* @returns The prefix (e.g., "xyz") or undefined if no prefix
|
|
130
|
-
*/
|
|
131
|
-
function getMarketPrefix(fullSymbol) {
|
|
132
|
-
const parts = fullSymbol.split(':');
|
|
133
|
-
return parts.length > 1 ? parts[0] : undefined;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Check if a symbol is a HIP-3 market (has a prefix).
|
|
137
|
-
* @param symbol e.g., "xyz:TSLA" or "TSLA"
|
|
138
|
-
* @returns true if the symbol has a market prefix
|
|
139
|
-
*/
|
|
140
|
-
function isHip3Market(symbol) {
|
|
141
|
-
return symbol.includes(':');
|
|
127
|
+
return (_a = displayToFull.get(displaySymbol)) !== null && _a !== void 0 ? _a : displaySymbol;
|
|
142
128
|
}
|
|
143
129
|
|
|
144
130
|
const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
@@ -155,8 +141,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
155
141
|
try {
|
|
156
142
|
const message = JSON.parse(event.data);
|
|
157
143
|
// Handle subscription responses (only if they don't have channel data)
|
|
158
|
-
if (('success' in message || 'error' in message) &&
|
|
159
|
-
!('channel' in message)) {
|
|
144
|
+
if (('success' in message || 'error' in message) && !('channel' in message)) {
|
|
160
145
|
if (message.error) {
|
|
161
146
|
setLastError(message.error);
|
|
162
147
|
}
|
|
@@ -175,21 +160,12 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
175
160
|
switch (dataMessage.channel) {
|
|
176
161
|
case 'trade-histories':
|
|
177
162
|
{
|
|
178
|
-
const mapAsset = (a) => {
|
|
179
|
-
var _a, _b;
|
|
180
|
-
const extractedPrefix = getMarketPrefix(a.coin);
|
|
181
|
-
return {
|
|
182
|
-
...a,
|
|
183
|
-
coin: toDisplaySymbol(a.coin),
|
|
184
|
-
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
185
|
-
};
|
|
186
|
-
};
|
|
187
163
|
const list = dataMessage.data.map((item) => {
|
|
188
164
|
var _a, _b;
|
|
189
165
|
return ({
|
|
190
166
|
...item,
|
|
191
|
-
closedLongAssets: item.closedLongAssets.map(
|
|
192
|
-
closedShortAssets: item.closedShortAssets.map(
|
|
167
|
+
closedLongAssets: item.closedLongAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
168
|
+
closedShortAssets: item.closedShortAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
193
169
|
positionLongAssets: (_a = item.positionLongAssets) === null || _a === void 0 ? void 0 : _a.map((a) => toDisplaySymbol(a)),
|
|
194
170
|
positionShortAssets: (_b = item.positionShortAssets) === null || _b === void 0 ? void 0 : _b.map((a) => toDisplaySymbol(a)),
|
|
195
171
|
});
|
|
@@ -199,19 +175,10 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
199
175
|
break;
|
|
200
176
|
case 'open-positions':
|
|
201
177
|
{
|
|
202
|
-
const enrichAsset = (a) => {
|
|
203
|
-
var _a, _b;
|
|
204
|
-
const extractedPrefix = getMarketPrefix(a.coin);
|
|
205
|
-
return {
|
|
206
|
-
...a,
|
|
207
|
-
coin: toDisplaySymbol(a.coin),
|
|
208
|
-
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
209
|
-
};
|
|
210
|
-
};
|
|
211
178
|
const list = dataMessage.data.map((pos) => ({
|
|
212
179
|
...pos,
|
|
213
|
-
longAssets: pos.longAssets.map(
|
|
214
|
-
shortAssets: pos.shortAssets.map(
|
|
180
|
+
longAssets: pos.longAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
181
|
+
shortAssets: pos.shortAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
215
182
|
}));
|
|
216
183
|
setRawOpenPositions(list);
|
|
217
184
|
}
|
|
@@ -220,14 +187,8 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
220
187
|
{
|
|
221
188
|
const list = dataMessage.data.map((order) => ({
|
|
222
189
|
...order,
|
|
223
|
-
longAssets: order.longAssets.map((a) => ({
|
|
224
|
-
|
|
225
|
-
asset: toDisplaySymbol(a.asset),
|
|
226
|
-
})),
|
|
227
|
-
shortAssets: order.shortAssets.map((a) => ({
|
|
228
|
-
...a,
|
|
229
|
-
asset: toDisplaySymbol(a.asset),
|
|
230
|
-
})),
|
|
190
|
+
longAssets: order.longAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
191
|
+
shortAssets: order.shortAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
231
192
|
}));
|
|
232
193
|
setOpenOrders(list);
|
|
233
194
|
}
|
|
@@ -237,20 +198,10 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
237
198
|
break;
|
|
238
199
|
case 'twap-details':
|
|
239
200
|
{
|
|
240
|
-
const mapTwapAsset = (a) => {
|
|
241
|
-
var _a, _b, _c;
|
|
242
|
-
const extractedPrefix = getMarketPrefix(a.asset);
|
|
243
|
-
return {
|
|
244
|
-
...a,
|
|
245
|
-
asset: toDisplaySymbol(a.asset),
|
|
246
|
-
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
247
|
-
collateralToken: (_c = a.collateralToken) !== null && _c !== void 0 ? _c : undefined,
|
|
248
|
-
};
|
|
249
|
-
};
|
|
250
201
|
const list = dataMessage.data.map((twap) => ({
|
|
251
202
|
...twap,
|
|
252
|
-
longAssets: twap.longAssets.map(
|
|
253
|
-
shortAssets: twap.shortAssets.map(
|
|
203
|
+
longAssets: twap.longAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
204
|
+
shortAssets: twap.shortAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
254
205
|
}));
|
|
255
206
|
setTwapDetails(list);
|
|
256
207
|
}
|
|
@@ -263,14 +214,8 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
263
214
|
const md = dataMessage.data;
|
|
264
215
|
const mapGroup = (g) => ({
|
|
265
216
|
...g,
|
|
266
|
-
longAssets: g.longAssets.map((a) => ({
|
|
267
|
-
|
|
268
|
-
asset: toDisplaySymbol(a.asset),
|
|
269
|
-
})),
|
|
270
|
-
shortAssets: g.shortAssets.map((a) => ({
|
|
271
|
-
...a,
|
|
272
|
-
asset: toDisplaySymbol(a.asset),
|
|
273
|
-
})),
|
|
217
|
+
longAssets: g.longAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
218
|
+
shortAssets: g.shortAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
274
219
|
});
|
|
275
220
|
const mapped = {
|
|
276
221
|
active: md.active.map(mapGroup),
|
|
@@ -288,15 +233,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
288
233
|
catch (error) {
|
|
289
234
|
setLastError(`Failed to parse message: ${error instanceof Error ? error.message : String(error)}`);
|
|
290
235
|
}
|
|
291
|
-
}, [
|
|
292
|
-
setTradeHistories,
|
|
293
|
-
setRawOpenPositions,
|
|
294
|
-
setOpenOrders,
|
|
295
|
-
setAccountSummary,
|
|
296
|
-
setTwapDetails,
|
|
297
|
-
setNotifications,
|
|
298
|
-
setMarketData,
|
|
299
|
-
]);
|
|
236
|
+
}, [setTradeHistories, setRawOpenPositions, setOpenOrders, setAccountSummary, setTwapDetails, setNotifications, setMarketData]);
|
|
300
237
|
const connect = useCallback(() => {
|
|
301
238
|
if (!enabled || !wsUrl)
|
|
302
239
|
return;
|
|
@@ -365,7 +302,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
365
302
|
'open-orders',
|
|
366
303
|
'twap-details',
|
|
367
304
|
'fills-checkpoint',
|
|
368
|
-
'notifications'
|
|
305
|
+
'notifications'
|
|
369
306
|
];
|
|
370
307
|
const globalChannels = ['market-data'];
|
|
371
308
|
if (address && address !== lastSubscribedAddress) {
|
|
@@ -374,14 +311,14 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
374
311
|
sendMessage(JSON.stringify({
|
|
375
312
|
action: 'unsubscribe',
|
|
376
313
|
address: lastSubscribedAddress,
|
|
377
|
-
channels: addressSpecificChannels
|
|
314
|
+
channels: addressSpecificChannels
|
|
378
315
|
}));
|
|
379
316
|
}
|
|
380
317
|
// Subscribe to all channels (global + address-specific)
|
|
381
318
|
sendMessage(JSON.stringify({
|
|
382
319
|
action: 'subscribe',
|
|
383
320
|
address: address,
|
|
384
|
-
channels: [...globalChannels, ...addressSpecificChannels]
|
|
321
|
+
channels: [...globalChannels, ...addressSpecificChannels]
|
|
385
322
|
}));
|
|
386
323
|
setLastSubscribedAddress(address);
|
|
387
324
|
setLastError(null);
|
|
@@ -391,7 +328,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
391
328
|
sendMessage(JSON.stringify({
|
|
392
329
|
action: 'unsubscribe',
|
|
393
330
|
address: lastSubscribedAddress,
|
|
394
|
-
channels: addressSpecificChannels
|
|
331
|
+
channels: addressSpecificChannels
|
|
395
332
|
}));
|
|
396
333
|
setLastSubscribedAddress(null);
|
|
397
334
|
}
|
|
@@ -399,7 +336,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
399
336
|
// If no address but connected, subscribe to global channels only
|
|
400
337
|
sendMessage(JSON.stringify({
|
|
401
338
|
action: 'subscribe',
|
|
402
|
-
channels: globalChannels
|
|
339
|
+
channels: globalChannels
|
|
403
340
|
}));
|
|
404
341
|
}
|
|
405
342
|
}, [isConnected, address, lastSubscribedAddress, sendMessage]);
|
|
@@ -422,14 +359,11 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
422
359
|
finalAssetContexts: null,
|
|
423
360
|
finalAtOICaps: null,
|
|
424
361
|
aggregatedClearingHouseState: null,
|
|
425
|
-
rawClearinghouseStates: null,
|
|
426
362
|
perpMetaAssets: null,
|
|
427
|
-
|
|
428
|
-
hip3Assets: new Map(),
|
|
429
|
-
hip3MarketPrefixes: new Map(),
|
|
363
|
+
hip3DisplayToFull: new Map(),
|
|
430
364
|
setAllMids: (value) => set({ allMids: value }),
|
|
431
365
|
setActiveAssetData: (value) => set((state) => ({
|
|
432
|
-
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value
|
|
366
|
+
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value
|
|
433
367
|
})),
|
|
434
368
|
deleteActiveAssetData: (key) => {
|
|
435
369
|
set((state) => {
|
|
@@ -464,16 +398,13 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
464
398
|
activeAssetData: {
|
|
465
399
|
...state.activeAssetData,
|
|
466
400
|
[key]: value,
|
|
467
|
-
}
|
|
401
|
+
}
|
|
468
402
|
})),
|
|
469
403
|
setFinalAssetContexts: (value) => set({ finalAssetContexts: value }),
|
|
470
404
|
setFinalAtOICaps: (value) => set({ finalAtOICaps: value }),
|
|
471
405
|
setAggregatedClearingHouseState: (value) => set({ aggregatedClearingHouseState: value }),
|
|
472
|
-
setRawClearinghouseStates: (value) => set({ rawClearinghouseStates: value }),
|
|
473
406
|
setPerpMetaAssets: (value) => set({ perpMetaAssets: value }),
|
|
474
|
-
|
|
475
|
-
setHip3Assets: (value) => set({ hip3Assets: value }),
|
|
476
|
-
setHip3MarketPrefixes: (value) => set({ hip3MarketPrefixes: value }),
|
|
407
|
+
setHip3DisplayToFull: (value) => set({ hip3DisplayToFull: value })
|
|
477
408
|
}));
|
|
478
409
|
|
|
479
410
|
/**
|
|
@@ -736,8 +667,7 @@ const useUserSelection$1 = create((set, get) => ({
|
|
|
736
667
|
}));
|
|
737
668
|
|
|
738
669
|
const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
739
|
-
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState,
|
|
740
|
-
const { setSpotState } = useUserData();
|
|
670
|
+
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState, } = useHyperliquidData();
|
|
741
671
|
const { candleInterval } = useUserSelection$1();
|
|
742
672
|
const longTokens = useUserSelection$1((s) => s.longTokens);
|
|
743
673
|
const shortTokens = useUserSelection$1((s) => s.shortTokens);
|
|
@@ -756,9 +686,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
756
686
|
try {
|
|
757
687
|
const message = JSON.parse(event.data);
|
|
758
688
|
// Handle subscription responses
|
|
759
|
-
if (
|
|
689
|
+
if ("success" in message || "error" in message) {
|
|
760
690
|
if (message.error) {
|
|
761
|
-
console.error(
|
|
691
|
+
console.error("[HyperLiquid WS] Subscription error:", message.error);
|
|
762
692
|
setLastError(message.error);
|
|
763
693
|
}
|
|
764
694
|
else {
|
|
@@ -767,44 +697,30 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
767
697
|
return;
|
|
768
698
|
}
|
|
769
699
|
// Handle channel data messages
|
|
770
|
-
if (
|
|
700
|
+
if ("channel" in message && "data" in message) {
|
|
771
701
|
const response = message;
|
|
772
702
|
switch (response.channel) {
|
|
773
|
-
case
|
|
703
|
+
case "webData3":
|
|
774
704
|
const webData3 = response.data;
|
|
775
705
|
// finalAssetContexts now sourced from allDexsAssetCtxs channel
|
|
776
706
|
const finalAtOICaps = webData3.perpDexStates.flatMap((dex) => dex.perpsAtOpenInterestCap);
|
|
777
707
|
setFinalAtOICaps(finalAtOICaps);
|
|
778
708
|
break;
|
|
779
|
-
case
|
|
709
|
+
case "allDexsAssetCtxs":
|
|
780
710
|
{
|
|
781
711
|
const data = response.data;
|
|
782
|
-
|
|
783
|
-
const FILTERED_DEX_PREFIXES = ['hyna'];
|
|
784
|
-
const filtered = (data.ctxs || [])
|
|
785
|
-
.filter(([prefix]) => !FILTERED_DEX_PREFIXES.includes((prefix || '').toLowerCase()))
|
|
786
|
-
.sort((a, b) => {
|
|
787
|
-
// Sort to match perpMetaAssets order: default market first, then alphabetically
|
|
788
|
-
const prefixA = a[0] || '';
|
|
789
|
-
const prefixB = b[0] || '';
|
|
790
|
-
if (prefixA === '' && prefixB !== '')
|
|
791
|
-
return -1;
|
|
792
|
-
if (prefixA !== '' && prefixB === '')
|
|
793
|
-
return 1;
|
|
794
|
-
return prefixA.localeCompare(prefixB);
|
|
795
|
-
});
|
|
796
|
-
const finalAssetContexts = filtered.flatMap(([, ctxs]) => ctxs || []);
|
|
712
|
+
const finalAssetContexts = (data.ctxs || []).flatMap(([, ctxs]) => ctxs || []);
|
|
797
713
|
setFinalAssetContexts(finalAssetContexts);
|
|
798
714
|
}
|
|
799
715
|
break;
|
|
800
|
-
case
|
|
716
|
+
case "allDexsClearinghouseState":
|
|
801
717
|
{
|
|
802
718
|
const data = response.data;
|
|
803
719
|
const states = (data.clearinghouseStates || [])
|
|
804
720
|
.map(([, s]) => s)
|
|
805
721
|
.filter(Boolean);
|
|
806
|
-
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v ||
|
|
807
|
-
const toStr = (n) => Number.isFinite(n) ? n.toString() :
|
|
722
|
+
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || "0") || 0), 0);
|
|
723
|
+
const toStr = (n) => Number.isFinite(n) ? n.toString() : "0";
|
|
808
724
|
const assetPositions = states.flatMap((s) => s.assetPositions || []);
|
|
809
725
|
const crossMaintenanceMarginUsed = toStr(sum(states.map((s) => s.crossMaintenanceMarginUsed)));
|
|
810
726
|
const crossMarginSummary = {
|
|
@@ -830,41 +746,22 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
830
746
|
withdrawable,
|
|
831
747
|
};
|
|
832
748
|
setAggregatedClearingHouseState(aggregatedClearingHouseState);
|
|
833
|
-
setRawClearinghouseStates(data.clearinghouseStates || null);
|
|
834
749
|
}
|
|
835
750
|
break;
|
|
836
|
-
case
|
|
751
|
+
case "allMids":
|
|
837
752
|
{
|
|
838
753
|
const data = response.data;
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
if (k.includes(':')) {
|
|
848
|
-
const [prefix, ...rest] = k.split(':');
|
|
849
|
-
normalizedKey = `${prefix.toLowerCase()}:${rest.join(':')}`;
|
|
850
|
-
}
|
|
851
|
-
// Store with normalized key
|
|
852
|
-
mids[normalizedKey] = v;
|
|
853
|
-
// Also store with original key for backward compatibility
|
|
854
|
-
if (k !== normalizedKey) {
|
|
855
|
-
mids[k] = v;
|
|
856
|
-
}
|
|
857
|
-
// Also store with display symbol for backward compatibility
|
|
858
|
-
const displayKey = toDisplaySymbol(k);
|
|
859
|
-
// Only set display key if it doesn't already exist (avoid overwriting market-specific prices)
|
|
860
|
-
if (!(displayKey in mids)) {
|
|
861
|
-
mids[displayKey] = v;
|
|
862
|
-
}
|
|
863
|
-
});
|
|
864
|
-
setAllMids({ mids });
|
|
754
|
+
const remapped = {
|
|
755
|
+
mids: Object.fromEntries(
|
|
756
|
+
// only support non hip-3 and xyz market
|
|
757
|
+
Object.entries(data.mids || {})
|
|
758
|
+
.filter(([k, v]) => !k.includes(":") || k.includes("xyz:"))
|
|
759
|
+
.map(([k, v]) => [toDisplaySymbol(k), v])),
|
|
760
|
+
};
|
|
761
|
+
setAllMids(remapped);
|
|
865
762
|
}
|
|
866
763
|
break;
|
|
867
|
-
case
|
|
764
|
+
case "activeAssetData":
|
|
868
765
|
{
|
|
869
766
|
const assetData = response.data;
|
|
870
767
|
const symbol = toDisplaySymbol(assetData.coin);
|
|
@@ -875,22 +772,14 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
875
772
|
upsertActiveAssetData(symbol, normalized);
|
|
876
773
|
}
|
|
877
774
|
break;
|
|
878
|
-
case
|
|
775
|
+
case "candle":
|
|
879
776
|
{
|
|
880
777
|
const candleDataItem = response.data;
|
|
881
|
-
const symbol = toDisplaySymbol(candleDataItem.s ||
|
|
778
|
+
const symbol = toDisplaySymbol(candleDataItem.s || "");
|
|
882
779
|
const normalized = { ...candleDataItem, s: symbol };
|
|
883
780
|
addCandleData(symbol, normalized);
|
|
884
781
|
}
|
|
885
782
|
break;
|
|
886
|
-
case 'spotState':
|
|
887
|
-
{
|
|
888
|
-
const spotStateData = response.data;
|
|
889
|
-
if (spotStateData === null || spotStateData === void 0 ? void 0 : spotStateData.spotState) {
|
|
890
|
-
setSpotState(spotStateData.spotState);
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
break;
|
|
894
783
|
default:
|
|
895
784
|
console.warn(`[HyperLiquid WS] Unknown channel: ${response.channel}`);
|
|
896
785
|
}
|
|
@@ -898,7 +787,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
898
787
|
}
|
|
899
788
|
catch (error) {
|
|
900
789
|
const errorMessage = `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`;
|
|
901
|
-
console.error(
|
|
790
|
+
console.error("[HyperLiquid WS] Parse error:", errorMessage, "Raw message:", event.data);
|
|
902
791
|
setLastError(errorMessage);
|
|
903
792
|
}
|
|
904
793
|
}, [
|
|
@@ -908,8 +797,6 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
908
797
|
setFinalAssetContexts,
|
|
909
798
|
setFinalAtOICaps,
|
|
910
799
|
setAggregatedClearingHouseState,
|
|
911
|
-
setRawClearinghouseStates,
|
|
912
|
-
setSpotState,
|
|
913
800
|
]);
|
|
914
801
|
const connect = useCallback(() => {
|
|
915
802
|
if (!enabled)
|
|
@@ -940,7 +827,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
940
827
|
if (!manualCloseRef.current && reconnectAttemptsRef.current < 5) {
|
|
941
828
|
reconnectAttemptsRef.current += 1;
|
|
942
829
|
if (reconnectAttemptsRef.current === 5) {
|
|
943
|
-
console.error(
|
|
830
|
+
console.error("[HyperLiquid WS] Reconnection stopped after 5 attempts");
|
|
944
831
|
}
|
|
945
832
|
setTimeout(() => connect(), 3000);
|
|
946
833
|
}
|
|
@@ -1008,17 +895,6 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
1008
895
|
},
|
|
1009
896
|
};
|
|
1010
897
|
sendJsonMessage(unsubscribeMessage);
|
|
1011
|
-
// Unsubscribe from spotState for previous address
|
|
1012
|
-
if (subscribedAddress !== DEFAULT_ADDRESS) {
|
|
1013
|
-
const unsubscribeSpotState = {
|
|
1014
|
-
method: 'unsubscribe',
|
|
1015
|
-
subscription: {
|
|
1016
|
-
type: 'spotState',
|
|
1017
|
-
user: subscribedAddress,
|
|
1018
|
-
},
|
|
1019
|
-
};
|
|
1020
|
-
sendJsonMessage(unsubscribeSpotState);
|
|
1021
|
-
}
|
|
1022
898
|
const unsubscribeAllDexsClearinghouseState = {
|
|
1023
899
|
method: "unsubscribe",
|
|
1024
900
|
subscription: {
|
|
@@ -1062,26 +938,11 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
1062
938
|
sendJsonMessage(subscribeAllDexsClearinghouseState);
|
|
1063
939
|
sendJsonMessage(subscribeAllMids);
|
|
1064
940
|
sendJsonMessage(subscribeAllDexsAssetCtxs);
|
|
1065
|
-
// Subscribe to spotState for real-time spot balances (USDH, USDC, etc.)
|
|
1066
|
-
// Only subscribe if we have a real user address (not the default)
|
|
1067
|
-
if (userAddress !== DEFAULT_ADDRESS) {
|
|
1068
|
-
const subscribeSpotState = {
|
|
1069
|
-
method: 'subscribe',
|
|
1070
|
-
subscription: {
|
|
1071
|
-
type: 'spotState',
|
|
1072
|
-
user: userAddress,
|
|
1073
|
-
},
|
|
1074
|
-
};
|
|
1075
|
-
sendJsonMessage(subscribeSpotState);
|
|
1076
|
-
}
|
|
1077
941
|
setSubscribedAddress(userAddress);
|
|
1078
942
|
// Clear previous data when address changes
|
|
1079
943
|
if (subscribedAddress && subscribedAddress !== userAddress) {
|
|
1080
944
|
// clear aggregatedClearingHouseState
|
|
1081
945
|
setAggregatedClearingHouseState(null);
|
|
1082
|
-
setRawClearinghouseStates(null);
|
|
1083
|
-
// clear spotState
|
|
1084
|
-
setSpotState(null);
|
|
1085
946
|
}
|
|
1086
947
|
}, [
|
|
1087
948
|
isConnected,
|
|
@@ -1089,8 +950,6 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
1089
950
|
subscribedAddress,
|
|
1090
951
|
sendJsonMessage,
|
|
1091
952
|
setAggregatedClearingHouseState,
|
|
1092
|
-
setRawClearinghouseStates,
|
|
1093
|
-
setSpotState,
|
|
1094
953
|
]);
|
|
1095
954
|
// Handle token subscriptions for activeAssetData
|
|
1096
955
|
useEffect(() => {
|
|
@@ -1287,112 +1146,20 @@ const useAccountSummary = () => {
|
|
|
1287
1146
|
return { data: calculated, isLoading };
|
|
1288
1147
|
};
|
|
1289
1148
|
|
|
1290
|
-
function findAssetMeta$4(coinName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
1291
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
1292
|
-
if (!perpMetaAssets) {
|
|
1293
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
1294
|
-
}
|
|
1295
|
-
if (desiredCollateral) {
|
|
1296
|
-
const collateralMatch = perpMetaAssets.find((a) => a.name === coinName && a.collateralToken === desiredCollateral);
|
|
1297
|
-
if (collateralMatch) {
|
|
1298
|
-
return {
|
|
1299
|
-
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
1300
|
-
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
1301
|
-
};
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
if (coinName.includes(':')) {
|
|
1305
|
-
const [prefix, symbol] = coinName.split(':');
|
|
1306
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
1307
|
-
var _a;
|
|
1308
|
-
return a.name === symbol &&
|
|
1309
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
1310
|
-
});
|
|
1311
|
-
if (exactMatch) {
|
|
1312
|
-
return {
|
|
1313
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
1314
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
1315
|
-
};
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
if (knownPrefix) {
|
|
1319
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
1320
|
-
var _a;
|
|
1321
|
-
return a.name === coinName &&
|
|
1322
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
1323
|
-
});
|
|
1324
|
-
if (exactMatch) {
|
|
1325
|
-
return {
|
|
1326
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
1327
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
1328
|
-
};
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
const exactMatch = perpMetaAssets.find((a) => a.name === coinName && !a.marketPrefix);
|
|
1332
|
-
if (exactMatch) {
|
|
1333
|
-
return {
|
|
1334
|
-
collateralToken: (_g = exactMatch.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
1335
|
-
marketPrefix: (_h = exactMatch.marketPrefix) !== null && _h !== void 0 ? _h : null,
|
|
1336
|
-
};
|
|
1337
|
-
}
|
|
1338
|
-
const hip3Matches = perpMetaAssets.filter((a) => a.name === coinName && a.marketPrefix);
|
|
1339
|
-
if (hip3Matches.length > 0) {
|
|
1340
|
-
if (desiredCollateral) {
|
|
1341
|
-
const collateralMatch = hip3Matches.find((a) => a.collateralToken === desiredCollateral);
|
|
1342
|
-
if (collateralMatch) {
|
|
1343
|
-
return {
|
|
1344
|
-
collateralToken: (_j = collateralMatch.collateralToken) !== null && _j !== void 0 ? _j : 'USDC',
|
|
1345
|
-
marketPrefix: (_k = collateralMatch.marketPrefix) !== null && _k !== void 0 ? _k : null,
|
|
1346
|
-
};
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
const usdHMatch = hip3Matches.find((a) => a.collateralToken === 'USDH');
|
|
1350
|
-
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Matches[0];
|
|
1351
|
-
return {
|
|
1352
|
-
collateralToken: (_l = chosen.collateralToken) !== null && _l !== void 0 ? _l : 'USDC',
|
|
1353
|
-
marketPrefix: (_m = chosen.marketPrefix) !== null && _m !== void 0 ? _m : null,
|
|
1354
|
-
};
|
|
1355
|
-
}
|
|
1356
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
1357
|
-
}
|
|
1358
|
-
function enrichTradeHistoryAssets(assets, perpMetaAssets) {
|
|
1359
|
-
return assets.map((asset) => {
|
|
1360
|
-
var _a;
|
|
1361
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
1362
|
-
return asset;
|
|
1363
|
-
}
|
|
1364
|
-
const meta = findAssetMeta$4(asset.coin, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
1365
|
-
return {
|
|
1366
|
-
...asset,
|
|
1367
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
1368
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
1369
|
-
};
|
|
1370
|
-
});
|
|
1371
|
-
}
|
|
1372
|
-
function enrichTradeHistories(histories, perpMetaAssets) {
|
|
1373
|
-
return histories.map((history) => ({
|
|
1374
|
-
...history,
|
|
1375
|
-
closedLongAssets: enrichTradeHistoryAssets(history.closedLongAssets, perpMetaAssets),
|
|
1376
|
-
closedShortAssets: enrichTradeHistoryAssets(history.closedShortAssets, perpMetaAssets),
|
|
1377
|
-
}));
|
|
1378
|
-
}
|
|
1379
1149
|
const useTradeHistories = () => {
|
|
1380
1150
|
const context = useContext(PearHyperliquidContext);
|
|
1381
1151
|
if (!context) {
|
|
1382
1152
|
throw new Error('useTradeHistories must be used within a PearHyperliquidProvider');
|
|
1383
1153
|
}
|
|
1384
1154
|
const tradeHistories = useUserData((state) => state.tradeHistories);
|
|
1385
|
-
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
1386
1155
|
const isLoading = useMemo(() => {
|
|
1387
1156
|
return tradeHistories === null && context.isConnected;
|
|
1388
1157
|
}, [tradeHistories, context.isConnected]);
|
|
1389
|
-
|
|
1390
|
-
if (!tradeHistories)
|
|
1391
|
-
return null;
|
|
1392
|
-
return enrichTradeHistories(tradeHistories, allPerpMetaAssets);
|
|
1393
|
-
}, [tradeHistories, allPerpMetaAssets]);
|
|
1394
|
-
return { data: enrichedTradeHistories, isLoading };
|
|
1158
|
+
return { data: tradeHistories, isLoading };
|
|
1395
1159
|
};
|
|
1160
|
+
/**
|
|
1161
|
+
* Hook to access open orders with loading state
|
|
1162
|
+
*/
|
|
1396
1163
|
const useOpenOrders = () => {
|
|
1397
1164
|
const context = useContext(PearHyperliquidContext);
|
|
1398
1165
|
if (!context) {
|
|
@@ -1421,51 +1188,21 @@ const useWebData = () => {
|
|
|
1421
1188
|
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
1422
1189
|
const aggregatedClearinghouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
1423
1190
|
const finalAtOICaps = useHyperliquidData((state) => state.finalAtOICaps);
|
|
1424
|
-
const hip3Assets = useHyperliquidData((state) => state.
|
|
1425
|
-
const hip3MarketPrefixes = useHyperliquidData((state) => state.hip3MarketPrefixes);
|
|
1191
|
+
const hip3Assets = useHyperliquidData((state) => state.hip3DisplayToFull);
|
|
1426
1192
|
let marketDataBySymbol = {};
|
|
1427
1193
|
if (finalAssetContexts && perpMetaAssets) {
|
|
1428
1194
|
const result = {};
|
|
1429
|
-
// Build a map of display name -> asset context index (for unique display names)
|
|
1430
|
-
const displayNameToContextIndex = new Map();
|
|
1431
|
-
const seenNames = new Set();
|
|
1432
|
-
let contextIndex = 0;
|
|
1433
|
-
// First pass: map unique display names to their context index
|
|
1434
1195
|
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1435
1196
|
const name = perpMetaAssets[index].name;
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
contextIndex++;
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1444
|
-
// Second pass: create nested entries for all market variants
|
|
1445
|
-
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1446
|
-
const universeAsset = perpMetaAssets[index];
|
|
1447
|
-
const displayName = universeAsset.name;
|
|
1448
|
-
const marketPrefix = universeAsset.marketPrefix;
|
|
1449
|
-
const ctxIndex = displayNameToContextIndex.get(displayName);
|
|
1450
|
-
if (ctxIndex !== undefined) {
|
|
1451
|
-
const assetContext = finalAssetContexts[ctxIndex];
|
|
1452
|
-
// Initialize the symbol entry if it doesn't exist
|
|
1453
|
-
if (!result[displayName]) {
|
|
1454
|
-
result[displayName] = {};
|
|
1455
|
-
}
|
|
1456
|
-
// Use marketPrefix as key for HIP-3 assets, "default" for regular assets
|
|
1457
|
-
const variantKey = marketPrefix || 'default';
|
|
1458
|
-
result[displayName][variantKey] = {
|
|
1459
|
-
asset: assetContext,
|
|
1460
|
-
universe: universeAsset,
|
|
1461
|
-
};
|
|
1462
|
-
}
|
|
1197
|
+
result[name] = {
|
|
1198
|
+
asset: finalAssetContexts[index],
|
|
1199
|
+
universe: perpMetaAssets[index],
|
|
1200
|
+
};
|
|
1463
1201
|
}
|
|
1464
1202
|
marketDataBySymbol = result;
|
|
1465
1203
|
}
|
|
1466
1204
|
return {
|
|
1467
1205
|
hip3Assets,
|
|
1468
|
-
hip3MarketPrefixes,
|
|
1469
1206
|
clearinghouseState: aggregatedClearinghouseState,
|
|
1470
1207
|
perpsAtOpenInterestCap: finalAtOICaps,
|
|
1471
1208
|
marketDataBySymbol,
|
|
@@ -1480,30 +1217,19 @@ const useWebData = () => {
|
|
|
1480
1217
|
class TokenMetadataExtractor {
|
|
1481
1218
|
/**
|
|
1482
1219
|
* Extracts comprehensive token metadata
|
|
1483
|
-
* @param symbol - Token symbol
|
|
1220
|
+
* @param symbol - Token symbol
|
|
1484
1221
|
* @param perpMetaAssets - Aggregated universe assets (flattened across dexes)
|
|
1485
1222
|
* @param finalAssetContexts - Aggregated asset contexts (flattened across dexes)
|
|
1486
1223
|
* @param allMids - AllMids data containing current prices
|
|
1487
1224
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1488
|
-
* @param marketPrefix - Optional market prefix (e.g., "xyz", "flx") for HIP3 multi-market assets
|
|
1489
1225
|
* @returns TokenMetadata or null if token not found
|
|
1490
1226
|
*/
|
|
1491
|
-
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData
|
|
1227
|
+
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
1492
1228
|
if (!perpMetaAssets || !finalAssetContexts || !allMids) {
|
|
1493
1229
|
return null;
|
|
1494
1230
|
}
|
|
1495
1231
|
// Find token index in aggregated universe
|
|
1496
|
-
|
|
1497
|
-
const universeIndex = perpMetaAssets.findIndex((asset) => {
|
|
1498
|
-
if (asset.name !== symbol)
|
|
1499
|
-
return false;
|
|
1500
|
-
// If marketPrefix is specified, match it; otherwise match assets without prefix
|
|
1501
|
-
if (marketPrefix) {
|
|
1502
|
-
return asset.marketPrefix === marketPrefix;
|
|
1503
|
-
}
|
|
1504
|
-
// No prefix specified - match non-HIP3 asset (no marketPrefix) or first matching asset
|
|
1505
|
-
return !asset.marketPrefix;
|
|
1506
|
-
});
|
|
1232
|
+
const universeIndex = perpMetaAssets.findIndex(asset => asset.name === symbol);
|
|
1507
1233
|
if (universeIndex === -1) {
|
|
1508
1234
|
return null;
|
|
1509
1235
|
}
|
|
@@ -1512,20 +1238,9 @@ class TokenMetadataExtractor {
|
|
|
1512
1238
|
if (!assetCtx) {
|
|
1513
1239
|
return null;
|
|
1514
1240
|
}
|
|
1515
|
-
// Get current price
|
|
1516
|
-
|
|
1517
|
-
const
|
|
1518
|
-
let currentPrice = 0;
|
|
1519
|
-
// Primary source: assetCtx.midPx (already properly indexed)
|
|
1520
|
-
if (assetCtx.midPx) {
|
|
1521
|
-
currentPrice = parseFloat(assetCtx.midPx);
|
|
1522
|
-
}
|
|
1523
|
-
// Fallback: allMids lookup with multiple key formats for HIP3 markets
|
|
1524
|
-
if (!currentPrice || isNaN(currentPrice)) {
|
|
1525
|
-
const currentPriceStr = (prefixedKeyColon && allMids.mids[prefixedKeyColon]) ||
|
|
1526
|
-
allMids.mids[symbol];
|
|
1527
|
-
currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
1528
|
-
}
|
|
1241
|
+
// Get current price from allMids
|
|
1242
|
+
const currentPriceStr = allMids.mids[symbol];
|
|
1243
|
+
const currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
1529
1244
|
// Get previous day price
|
|
1530
1245
|
const prevDayPrice = parseFloat(assetCtx.prevDayPx);
|
|
1531
1246
|
// Calculate 24h price change
|
|
@@ -1536,11 +1251,7 @@ class TokenMetadataExtractor {
|
|
|
1536
1251
|
const markPrice = parseFloat(assetCtx.markPx);
|
|
1537
1252
|
const oraclePrice = parseFloat(assetCtx.oraclePx);
|
|
1538
1253
|
// Extract leverage info from activeAssetData if available
|
|
1539
|
-
|
|
1540
|
-
const activeDataKey = prefixedKeyColon && (activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[prefixedKeyColon])
|
|
1541
|
-
? prefixedKeyColon
|
|
1542
|
-
: symbol;
|
|
1543
|
-
const tokenActiveData = activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[activeDataKey];
|
|
1254
|
+
const tokenActiveData = activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[symbol];
|
|
1544
1255
|
const leverage = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.leverage;
|
|
1545
1256
|
const maxTradeSzs = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.maxTradeSzs;
|
|
1546
1257
|
const availableToTrade = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.availableToTrade;
|
|
@@ -1558,27 +1269,21 @@ class TokenMetadataExtractor {
|
|
|
1558
1269
|
leverage,
|
|
1559
1270
|
maxTradeSzs,
|
|
1560
1271
|
availableToTrade,
|
|
1561
|
-
collateralToken: universeAsset.collateralToken,
|
|
1562
1272
|
};
|
|
1563
1273
|
}
|
|
1564
1274
|
/**
|
|
1565
1275
|
* Extracts metadata for multiple tokens
|
|
1566
|
-
* @param
|
|
1276
|
+
* @param symbols - Array of token symbols
|
|
1567
1277
|
* @param perpMetaAssets - Aggregated universe assets
|
|
1568
1278
|
* @param finalAssetContexts - Aggregated asset contexts
|
|
1569
1279
|
* @param allMids - AllMids data
|
|
1570
1280
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1571
|
-
* @returns Record of
|
|
1281
|
+
* @returns Record of symbol to TokenMetadata
|
|
1572
1282
|
*/
|
|
1573
|
-
static extractMultipleTokensMetadata(
|
|
1283
|
+
static extractMultipleTokensMetadata(symbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
1574
1284
|
const result = {};
|
|
1575
|
-
for (const
|
|
1576
|
-
|
|
1577
|
-
// This ensures xyz:TSLA and flx:TSLA get separate entries
|
|
1578
|
-
const resultKey = token.marketPrefix
|
|
1579
|
-
? `${token.marketPrefix}:${token.symbol}`
|
|
1580
|
-
: token.symbol;
|
|
1581
|
-
result[resultKey] = this.extractTokenMetadata(token.symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData, token.marketPrefix);
|
|
1285
|
+
for (const symbol of symbols) {
|
|
1286
|
+
result[symbol] = this.extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData);
|
|
1582
1287
|
}
|
|
1583
1288
|
return result;
|
|
1584
1289
|
}
|
|
@@ -1591,30 +1296,10 @@ class TokenMetadataExtractor {
|
|
|
1591
1296
|
static isTokenAvailable(symbol, perpMetaAssets) {
|
|
1592
1297
|
if (!perpMetaAssets)
|
|
1593
1298
|
return false;
|
|
1594
|
-
return perpMetaAssets.some(
|
|
1299
|
+
return perpMetaAssets.some(asset => asset.name === symbol);
|
|
1595
1300
|
}
|
|
1596
1301
|
}
|
|
1597
1302
|
|
|
1598
|
-
/**
|
|
1599
|
-
* Parse a token string that may have a market prefix (e.g., "xyz:GOOGL" -> { prefix: "xyz", symbol: "GOOGL" })
|
|
1600
|
-
* This allows us to keep the full name (xyz:GOOGL) for URLs/tags while extracting just the symbol for SDK lookups.
|
|
1601
|
-
*/
|
|
1602
|
-
function parseTokenWithPrefix(token) {
|
|
1603
|
-
if (token.includes(':')) {
|
|
1604
|
-
const [prefix, ...rest] = token.split(':');
|
|
1605
|
-
const symbol = rest.join(':').toUpperCase();
|
|
1606
|
-
return {
|
|
1607
|
-
prefix: prefix.toLowerCase(),
|
|
1608
|
-
symbol,
|
|
1609
|
-
fullName: `${prefix.toLowerCase()}:${symbol}`,
|
|
1610
|
-
};
|
|
1611
|
-
}
|
|
1612
|
-
return {
|
|
1613
|
-
prefix: null,
|
|
1614
|
-
symbol: token.toUpperCase(),
|
|
1615
|
-
fullName: token.toUpperCase(),
|
|
1616
|
-
};
|
|
1617
|
-
}
|
|
1618
1303
|
const useTokenSelectionMetadataStore = create((set) => ({
|
|
1619
1304
|
isPriceDataReady: false,
|
|
1620
1305
|
isLoading: true,
|
|
@@ -1624,65 +1309,23 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1624
1309
|
weightedRatio24h: 1,
|
|
1625
1310
|
priceRatio: 1,
|
|
1626
1311
|
priceRatio24h: 1,
|
|
1627
|
-
openInterest:
|
|
1628
|
-
volume:
|
|
1312
|
+
openInterest: "0",
|
|
1313
|
+
volume: "0",
|
|
1629
1314
|
sumNetFunding: 0,
|
|
1630
1315
|
maxLeverage: 0,
|
|
1631
1316
|
minMargin: 0,
|
|
1632
1317
|
leverageMatched: true,
|
|
1633
|
-
recompute: ({ perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketData, longTokens, shortTokens
|
|
1634
|
-
const isPriceDataReady = !!(perpMetaAssets &&
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
...t,
|
|
1641
|
-
parsed: parseTokenWithPrefix(t.symbol),
|
|
1642
|
-
}));
|
|
1643
|
-
const parsedShortTokens = shortTokens.map((t) => ({
|
|
1644
|
-
...t,
|
|
1645
|
-
parsed: parseTokenWithPrefix(t.symbol),
|
|
1646
|
-
}));
|
|
1647
|
-
// Extract base symbols with their market prefixes for SDK lookups
|
|
1648
|
-
// This ensures xyz:TSLA and flx:TSLA get different market data
|
|
1649
|
-
const longTokensForLookup = parsedLongTokens.map((t) => ({
|
|
1650
|
-
symbol: t.parsed.symbol,
|
|
1651
|
-
marketPrefix: t.parsed.prefix,
|
|
1652
|
-
}));
|
|
1653
|
-
const shortTokensForLookup = parsedShortTokens.map((t) => ({
|
|
1654
|
-
symbol: t.parsed.symbol,
|
|
1655
|
-
marketPrefix: t.parsed.prefix,
|
|
1656
|
-
}));
|
|
1657
|
-
// Also extract just the base symbols (without prefix) for lookups that don't support prefixes
|
|
1658
|
-
const longBaseSymbols = longTokensForLookup.map((t) => t.symbol);
|
|
1659
|
-
const shortBaseSymbols = shortTokensForLookup.map((t) => t.symbol);
|
|
1660
|
-
// Get metadata using base symbols with market prefix for proper market differentiation
|
|
1661
|
-
const longBaseMetadata = isPriceDataReady
|
|
1662
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(longTokensForLookup, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1318
|
+
recompute: ({ perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketData, longTokens, shortTokens }) => {
|
|
1319
|
+
const isPriceDataReady = !!(perpMetaAssets && finalAssetContexts && allMids);
|
|
1320
|
+
// Compute metadata when ready
|
|
1321
|
+
const longSymbols = longTokens.map((t) => t.symbol);
|
|
1322
|
+
const shortSymbols = shortTokens.map((t) => t.symbol);
|
|
1323
|
+
const longTokensMetadata = isPriceDataReady
|
|
1324
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(longSymbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1663
1325
|
: {};
|
|
1664
|
-
const
|
|
1665
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(
|
|
1326
|
+
const shortTokensMetadata = isPriceDataReady
|
|
1327
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(shortSymbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1666
1328
|
: {};
|
|
1667
|
-
// Re-map metadata using original full names (with prefix) as keys for UI consistency
|
|
1668
|
-
// The extractor now keys by "{prefix}:{symbol}" for prefixed tokens, which matches our parsed.fullName
|
|
1669
|
-
const longTokensMetadata = {};
|
|
1670
|
-
parsedLongTokens.forEach((t) => {
|
|
1671
|
-
var _a;
|
|
1672
|
-
// Use the full name (e.g., "xyz:TSLA") as the lookup key since extractor uses the same format
|
|
1673
|
-
const lookupKey = t.parsed.prefix
|
|
1674
|
-
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1675
|
-
: t.parsed.symbol;
|
|
1676
|
-
longTokensMetadata[t.symbol] = (_a = longBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1677
|
-
});
|
|
1678
|
-
const shortTokensMetadata = {};
|
|
1679
|
-
parsedShortTokens.forEach((t) => {
|
|
1680
|
-
var _a;
|
|
1681
|
-
const lookupKey = t.parsed.prefix
|
|
1682
|
-
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1683
|
-
: t.parsed.symbol;
|
|
1684
|
-
shortTokensMetadata[t.symbol] = (_a = shortBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1685
|
-
});
|
|
1686
1329
|
// Determine loading state
|
|
1687
1330
|
const allTokens = [...longTokens, ...shortTokens];
|
|
1688
1331
|
const isLoading = (() => {
|
|
@@ -1690,33 +1333,26 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1690
1333
|
return true;
|
|
1691
1334
|
if (allTokens.length === 0)
|
|
1692
1335
|
return false;
|
|
1693
|
-
const allMetadata = {
|
|
1694
|
-
...longTokensMetadata,
|
|
1695
|
-
...shortTokensMetadata,
|
|
1696
|
-
};
|
|
1336
|
+
const allMetadata = { ...longTokensMetadata, ...shortTokensMetadata };
|
|
1697
1337
|
return allTokens.some((token) => !allMetadata[token.symbol]);
|
|
1698
1338
|
})();
|
|
1699
1339
|
// Open interest and volume (from market data for matching asset basket)
|
|
1700
|
-
// Use base symbols (without prefix) for matching against market data
|
|
1701
1340
|
const { openInterest, volume } = (() => {
|
|
1702
|
-
const empty = { openInterest:
|
|
1341
|
+
const empty = { openInterest: "0", volume: "0" };
|
|
1703
1342
|
if (!(marketData === null || marketData === void 0 ? void 0 : marketData.active) || (!longTokens.length && !shortTokens.length))
|
|
1704
1343
|
return empty;
|
|
1705
|
-
const selectedLong =
|
|
1706
|
-
const selectedShort =
|
|
1344
|
+
const selectedLong = longTokens.map((t) => t.symbol).sort();
|
|
1345
|
+
const selectedShort = shortTokens.map((t) => t.symbol).sort();
|
|
1707
1346
|
const match = marketData.active.find((item) => {
|
|
1708
1347
|
const longs = [...item.longAssets].sort();
|
|
1709
1348
|
const shorts = [...item.shortAssets].sort();
|
|
1710
|
-
if (longs.length !== selectedLong.length ||
|
|
1711
|
-
shorts.length !== selectedShort.length)
|
|
1349
|
+
if (longs.length !== selectedLong.length || shorts.length !== selectedShort.length)
|
|
1712
1350
|
return false;
|
|
1713
1351
|
const longsEqual = longs.every((s, i) => s.asset === selectedLong[i]);
|
|
1714
1352
|
const shortsEqual = shorts.every((s, i) => s.asset === selectedShort[i]);
|
|
1715
1353
|
return longsEqual && shortsEqual;
|
|
1716
1354
|
});
|
|
1717
|
-
return match
|
|
1718
|
-
? { openInterest: match.openInterest, volume: match.volume }
|
|
1719
|
-
: empty;
|
|
1355
|
+
return match ? { openInterest: match.openInterest, volume: match.volume } : empty;
|
|
1720
1356
|
})();
|
|
1721
1357
|
// Price ratio (only when exactly one long and one short)
|
|
1722
1358
|
const { priceRatio, priceRatio24h } = (() => {
|
|
@@ -1795,30 +1431,20 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1795
1431
|
});
|
|
1796
1432
|
return totalFunding;
|
|
1797
1433
|
})();
|
|
1798
|
-
// Max leverage (
|
|
1799
|
-
// Use tokens with their market prefixes for proper lookup in perpMetaAssets
|
|
1434
|
+
// Max leverage (maximum across all tokens)
|
|
1800
1435
|
const maxLeverage = (() => {
|
|
1801
1436
|
if (!perpMetaAssets)
|
|
1802
1437
|
return 0;
|
|
1803
|
-
const
|
|
1804
|
-
|
|
1805
|
-
...shortTokensForLookup,
|
|
1806
|
-
];
|
|
1807
|
-
if (allTokensForLookup.length === 0)
|
|
1438
|
+
const allTokenSymbols = [...longTokens, ...shortTokens].map((t) => t.symbol);
|
|
1439
|
+
if (allTokenSymbols.length === 0)
|
|
1808
1440
|
return 0;
|
|
1809
|
-
let
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
(
|
|
1814
|
-
? u.marketPrefix === marketPrefix
|
|
1815
|
-
: !u.marketPrefix));
|
|
1816
|
-
// Fallback to just matching by name if no exact match
|
|
1817
|
-
const fallbackUniverse = tokenUniverse || perpMetaAssets.find((u) => u.name === symbol);
|
|
1818
|
-
if (fallbackUniverse === null || fallbackUniverse === void 0 ? void 0 : fallbackUniverse.maxLeverage)
|
|
1819
|
-
minLev = Math.min(minLev, fallbackUniverse.maxLeverage);
|
|
1441
|
+
let maxLev = 0;
|
|
1442
|
+
allTokenSymbols.forEach((symbol) => {
|
|
1443
|
+
const tokenUniverse = perpMetaAssets.find((u) => u.name === symbol);
|
|
1444
|
+
if (tokenUniverse === null || tokenUniverse === void 0 ? void 0 : tokenUniverse.maxLeverage)
|
|
1445
|
+
maxLev = Math.max(maxLev, tokenUniverse.maxLeverage);
|
|
1820
1446
|
});
|
|
1821
|
-
return
|
|
1447
|
+
return maxLev;
|
|
1822
1448
|
})();
|
|
1823
1449
|
// Min margin (10 * total number of tokens)
|
|
1824
1450
|
const minMargin = (() => {
|
|
@@ -1828,10 +1454,7 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1828
1454
|
// Whether all tokens have matching leverage
|
|
1829
1455
|
const leverageMatched = (() => {
|
|
1830
1456
|
const allTokensArr = [...longTokens, ...shortTokens];
|
|
1831
|
-
const allMetadata = {
|
|
1832
|
-
...longTokensMetadata,
|
|
1833
|
-
...shortTokensMetadata,
|
|
1834
|
-
};
|
|
1457
|
+
const allMetadata = { ...longTokensMetadata, ...shortTokensMetadata };
|
|
1835
1458
|
if (allTokensArr.length === 0)
|
|
1836
1459
|
return true;
|
|
1837
1460
|
const tokensWithLev = allTokensArr.filter((token) => { var _a; return (_a = allMetadata[token.symbol]) === null || _a === void 0 ? void 0 : _a.leverage; });
|
|
@@ -6016,8 +5639,8 @@ function addAuthInterceptors(params) {
|
|
|
6016
5639
|
/**
|
|
6017
5640
|
* Fetch historical candle data from HyperLiquid API
|
|
6018
5641
|
*/
|
|
6019
|
-
const fetchHistoricalCandles = async (coin, startTime, endTime, interval,
|
|
6020
|
-
const backendCoin = toBackendSymbol(coin,
|
|
5642
|
+
const fetchHistoricalCandles = async (coin, startTime, endTime, interval, displayToFull) => {
|
|
5643
|
+
const backendCoin = toBackendSymbol(coin, displayToFull);
|
|
6021
5644
|
const request = {
|
|
6022
5645
|
req: { coin: backendCoin, startTime, endTime, interval },
|
|
6023
5646
|
type: 'candleSnapshot',
|
|
@@ -6176,10 +5799,10 @@ const useHistoricalPriceData = () => {
|
|
|
6176
5799
|
setTokenLoading(token.symbol, true);
|
|
6177
5800
|
});
|
|
6178
5801
|
try {
|
|
6179
|
-
const
|
|
5802
|
+
const displayToFull = useHyperliquidData.getState().hip3DisplayToFull;
|
|
6180
5803
|
const fetchPromises = tokensToFetch.map(async (token) => {
|
|
6181
5804
|
try {
|
|
6182
|
-
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval,
|
|
5805
|
+
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval, displayToFull);
|
|
6183
5806
|
addHistoricalPriceData(token.symbol, interval, response.data, { start: startTime, end: endTime });
|
|
6184
5807
|
return { symbol: token.symbol, candles: response.data, success: true };
|
|
6185
5808
|
}
|
|
@@ -6868,14 +6491,14 @@ function useAutoSyncFills(options) {
|
|
|
6868
6491
|
* @throws MinimumPositionSizeError if any asset has less than $11 USD value
|
|
6869
6492
|
* @throws MaxAssetsPerLegError if any leg exceeds the maximum allowed assets (15)
|
|
6870
6493
|
*/
|
|
6871
|
-
async function createPosition(baseUrl, payload,
|
|
6494
|
+
async function createPosition(baseUrl, payload, displayToFull) {
|
|
6872
6495
|
// Validate maximum assets per leg before creating position
|
|
6873
6496
|
validateMaxAssetsPerLeg(payload.longAssets, payload.shortAssets);
|
|
6874
6497
|
// Validate minimum asset size before creating position
|
|
6875
6498
|
validateMinimumAssetSize(payload.usdValue, payload.longAssets, payload.shortAssets);
|
|
6876
6499
|
const url = joinUrl(baseUrl, "/positions");
|
|
6877
6500
|
// Translate display symbols to backend format
|
|
6878
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset,
|
|
6501
|
+
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
6879
6502
|
const translatedPayload = {
|
|
6880
6503
|
...payload,
|
|
6881
6504
|
longAssets: mapAssets(payload.longAssets),
|
|
@@ -6974,9 +6597,9 @@ async function adjustPosition(baseUrl, positionId, payload) {
|
|
|
6974
6597
|
throw toApiError(error);
|
|
6975
6598
|
}
|
|
6976
6599
|
}
|
|
6977
|
-
async function adjustAdvancePosition(baseUrl, positionId, payload,
|
|
6600
|
+
async function adjustAdvancePosition(baseUrl, positionId, payload, displayToFull) {
|
|
6978
6601
|
const url = joinUrl(baseUrl, `/positions/${positionId}/adjust-advance`);
|
|
6979
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset,
|
|
6602
|
+
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
6980
6603
|
const translatedPayload = (payload || []).map((item) => ({
|
|
6981
6604
|
longAssets: mapAssets(item.longAssets),
|
|
6982
6605
|
shortAssets: mapAssets(item.shortAssets),
|
|
@@ -7059,11 +6682,10 @@ const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, l
|
|
|
7059
6682
|
positionValue: currentNotional,
|
|
7060
6683
|
unrealizedPnl: unrealizedPnl,
|
|
7061
6684
|
entryPositionValue: entryNotional,
|
|
7062
|
-
initialWeight: totalInitialPositionSize > 0
|
|
6685
|
+
initialWeight: totalInitialPositionSize > 0
|
|
6686
|
+
? entryNotional / totalInitialPositionSize
|
|
6687
|
+
: 0,
|
|
7063
6688
|
fundingPaid: (_a = asset.fundingPaid) !== null && _a !== void 0 ? _a : 0,
|
|
7064
|
-
// Preserve market metadata from raw asset (if provided by backend)
|
|
7065
|
-
marketPrefix: asset.marketPrefix,
|
|
7066
|
-
collateralToken: asset.collateralToken,
|
|
7067
6689
|
};
|
|
7068
6690
|
};
|
|
7069
6691
|
const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
@@ -7152,108 +6774,36 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
7152
6774
|
});
|
|
7153
6775
|
};
|
|
7154
6776
|
|
|
7155
|
-
function findAssetMeta$3(coinName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7156
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
7157
|
-
if (!perpMetaAssets) {
|
|
7158
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7159
|
-
}
|
|
7160
|
-
if (desiredCollateral) {
|
|
7161
|
-
const collateralMatch = perpMetaAssets.find((a) => a.name === coinName && a.collateralToken === desiredCollateral);
|
|
7162
|
-
if (collateralMatch) {
|
|
7163
|
-
return {
|
|
7164
|
-
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7165
|
-
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7166
|
-
};
|
|
7167
|
-
}
|
|
7168
|
-
}
|
|
7169
|
-
if (coinName.includes(':')) {
|
|
7170
|
-
const [prefix, symbol] = coinName.split(':');
|
|
7171
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7172
|
-
var _a;
|
|
7173
|
-
return a.name === symbol &&
|
|
7174
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7175
|
-
});
|
|
7176
|
-
if (exactMatch) {
|
|
7177
|
-
return {
|
|
7178
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7179
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7180
|
-
};
|
|
7181
|
-
}
|
|
7182
|
-
}
|
|
7183
|
-
if (knownPrefix) {
|
|
7184
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7185
|
-
var _a;
|
|
7186
|
-
return a.name === coinName &&
|
|
7187
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7188
|
-
});
|
|
7189
|
-
if (exactMatch) {
|
|
7190
|
-
return {
|
|
7191
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7192
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7193
|
-
};
|
|
7194
|
-
}
|
|
7195
|
-
}
|
|
7196
|
-
const regularAsset = perpMetaAssets.find((a) => a.name === coinName && !a.marketPrefix);
|
|
7197
|
-
if (regularAsset) {
|
|
7198
|
-
return {
|
|
7199
|
-
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7200
|
-
marketPrefix: null,
|
|
7201
|
-
};
|
|
7202
|
-
}
|
|
7203
|
-
const hip3Asset = perpMetaAssets.find((a) => a.name === coinName && a.marketPrefix);
|
|
7204
|
-
if (hip3Asset) {
|
|
7205
|
-
return {
|
|
7206
|
-
collateralToken: (_h = hip3Asset.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7207
|
-
marketPrefix: (_j = hip3Asset.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7208
|
-
};
|
|
7209
|
-
}
|
|
7210
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7211
|
-
}
|
|
7212
|
-
function enrichPositionAssets(assets, perpMetaAssets) {
|
|
7213
|
-
return assets.map((asset) => {
|
|
7214
|
-
var _a;
|
|
7215
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
7216
|
-
return asset;
|
|
7217
|
-
}
|
|
7218
|
-
const meta = findAssetMeta$3(asset.coin, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7219
|
-
return {
|
|
7220
|
-
...asset,
|
|
7221
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7222
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7223
|
-
};
|
|
7224
|
-
});
|
|
7225
|
-
}
|
|
7226
|
-
function enrichPositions(positions, perpMetaAssets) {
|
|
7227
|
-
return positions.map((position) => ({
|
|
7228
|
-
...position,
|
|
7229
|
-
longAssets: enrichPositionAssets(position.longAssets, perpMetaAssets),
|
|
7230
|
-
shortAssets: enrichPositionAssets(position.shortAssets, perpMetaAssets),
|
|
7231
|
-
}));
|
|
7232
|
-
}
|
|
7233
6777
|
function usePosition() {
|
|
7234
6778
|
const context = useContext(PearHyperliquidContext);
|
|
7235
6779
|
if (!context) {
|
|
7236
6780
|
throw new Error('usePosition must be used within a PearHyperliquidProvider');
|
|
7237
6781
|
}
|
|
7238
6782
|
const { apiBaseUrl, isConnected } = context;
|
|
7239
|
-
const
|
|
6783
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
6784
|
+
// Create position API action
|
|
7240
6785
|
const createPosition$1 = async (payload) => {
|
|
7241
|
-
return createPosition(apiBaseUrl, payload,
|
|
6786
|
+
return createPosition(apiBaseUrl, payload, displayToFull);
|
|
7242
6787
|
};
|
|
6788
|
+
// Update TP/SL risk parameters for a position
|
|
7243
6789
|
const updateRiskParameters$1 = async (positionId, payload) => {
|
|
7244
6790
|
return updateRiskParameters(apiBaseUrl, positionId, payload);
|
|
7245
6791
|
};
|
|
6792
|
+
// Close a position (MARKET or TWAP)
|
|
7246
6793
|
const closePosition$1 = async (positionId, payload) => {
|
|
7247
6794
|
return closePosition(apiBaseUrl, positionId, payload);
|
|
7248
6795
|
};
|
|
6796
|
+
// Close all positions (MARKET or TWAP)
|
|
7249
6797
|
const closeAllPositions$1 = async (payload) => {
|
|
7250
6798
|
return closeAllPositions(apiBaseUrl, payload);
|
|
7251
6799
|
};
|
|
6800
|
+
// Adjust a position (REDUCE/INCREASE by %; MARKET or LIMIT)
|
|
7252
6801
|
const adjustPosition$1 = async (positionId, payload) => {
|
|
7253
6802
|
return adjustPosition(apiBaseUrl, positionId, payload);
|
|
7254
6803
|
};
|
|
6804
|
+
// Adjust to absolute target sizes per asset, optionally adding new assets
|
|
7255
6805
|
const adjustAdvancePosition$1 = async (positionId, payload) => {
|
|
7256
|
-
return adjustAdvancePosition(apiBaseUrl, positionId, payload,
|
|
6806
|
+
return adjustAdvancePosition(apiBaseUrl, positionId, payload, displayToFull);
|
|
7257
6807
|
};
|
|
7258
6808
|
const updateLeverage$1 = async (positionId, leverage) => {
|
|
7259
6809
|
return updateLeverage(apiBaseUrl, positionId, { leverage });
|
|
@@ -7262,46 +6812,22 @@ function usePosition() {
|
|
|
7262
6812
|
const userOpenPositions = useUserData((state) => state.rawOpenPositions);
|
|
7263
6813
|
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
7264
6814
|
const allMids = useHyperliquidData((state) => state.allMids);
|
|
7265
|
-
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
7266
6815
|
const isLoading = useMemo(() => {
|
|
7267
6816
|
return userOpenPositions === null && isConnected;
|
|
7268
6817
|
}, [userOpenPositions, isConnected]);
|
|
7269
6818
|
const openPositions = useMemo(() => {
|
|
7270
6819
|
if (!userOpenPositions || !aggregatedClearingHouseState || !allMids)
|
|
7271
6820
|
return null;
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
userOpenPositions,
|
|
7276
|
-
aggregatedClearingHouseState,
|
|
7277
|
-
allMids,
|
|
7278
|
-
allPerpMetaAssets,
|
|
7279
|
-
]);
|
|
7280
|
-
return {
|
|
7281
|
-
createPosition: createPosition$1,
|
|
7282
|
-
updateRiskParameters: updateRiskParameters$1,
|
|
7283
|
-
closePosition: closePosition$1,
|
|
7284
|
-
closeAllPositions: closeAllPositions$1,
|
|
7285
|
-
adjustPosition: adjustPosition$1,
|
|
7286
|
-
adjustAdvancePosition: adjustAdvancePosition$1,
|
|
7287
|
-
updateLeverage: updateLeverage$1,
|
|
7288
|
-
openPositions,
|
|
7289
|
-
isLoading,
|
|
7290
|
-
};
|
|
6821
|
+
return buildPositionValue(userOpenPositions, aggregatedClearingHouseState, allMids);
|
|
6822
|
+
}, [userOpenPositions, aggregatedClearingHouseState, allMids]);
|
|
6823
|
+
return { createPosition: createPosition$1, updateRiskParameters: updateRiskParameters$1, closePosition: closePosition$1, closeAllPositions: closeAllPositions$1, adjustPosition: adjustPosition$1, adjustAdvancePosition: adjustAdvancePosition$1, updateLeverage: updateLeverage$1, openPositions, isLoading };
|
|
7291
6824
|
}
|
|
7292
6825
|
|
|
7293
6826
|
async function adjustOrder(baseUrl, orderId, payload) {
|
|
7294
6827
|
const url = joinUrl(baseUrl, `/orders/${orderId}/adjust`);
|
|
7295
6828
|
try {
|
|
7296
|
-
const resp = await apiClient.put(url, payload, {
|
|
7297
|
-
|
|
7298
|
-
timeout: 60000,
|
|
7299
|
-
});
|
|
7300
|
-
return {
|
|
7301
|
-
data: resp.data,
|
|
7302
|
-
status: resp.status,
|
|
7303
|
-
headers: resp.headers,
|
|
7304
|
-
};
|
|
6829
|
+
const resp = await apiClient.put(url, payload, { headers: { 'Content-Type': 'application/json' }, timeout: 60000 });
|
|
6830
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7305
6831
|
}
|
|
7306
6832
|
catch (error) {
|
|
7307
6833
|
throw toApiError(error);
|
|
@@ -7310,14 +6836,8 @@ async function adjustOrder(baseUrl, orderId, payload) {
|
|
|
7310
6836
|
async function cancelOrder(baseUrl, orderId) {
|
|
7311
6837
|
const url = joinUrl(baseUrl, `/orders/${orderId}/cancel`);
|
|
7312
6838
|
try {
|
|
7313
|
-
const resp = await apiClient.delete(url, {
|
|
7314
|
-
|
|
7315
|
-
});
|
|
7316
|
-
return {
|
|
7317
|
-
data: resp.data,
|
|
7318
|
-
status: resp.status,
|
|
7319
|
-
headers: resp.headers,
|
|
7320
|
-
};
|
|
6839
|
+
const resp = await apiClient.delete(url, { timeout: 60000 });
|
|
6840
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7321
6841
|
}
|
|
7322
6842
|
catch (error) {
|
|
7323
6843
|
throw toApiError(error);
|
|
@@ -7327,129 +6847,19 @@ async function cancelTwapOrder(baseUrl, orderId) {
|
|
|
7327
6847
|
const url = joinUrl(baseUrl, `/orders/${orderId}/twap/cancel`);
|
|
7328
6848
|
try {
|
|
7329
6849
|
const resp = await apiClient.post(url, {}, { headers: { 'Content-Type': 'application/json' }, timeout: 60000 });
|
|
7330
|
-
return {
|
|
7331
|
-
data: resp.data,
|
|
7332
|
-
status: resp.status,
|
|
7333
|
-
headers: resp.headers,
|
|
7334
|
-
};
|
|
7335
|
-
}
|
|
7336
|
-
catch (error) {
|
|
7337
|
-
throw toApiError(error);
|
|
7338
|
-
}
|
|
7339
|
-
}
|
|
7340
|
-
/**
|
|
7341
|
-
* Execute a spot order (swap) using Pear Hyperliquid service
|
|
7342
|
-
* POST /orders/spot
|
|
7343
|
-
*/
|
|
7344
|
-
async function executeSpotOrder(baseUrl, payload) {
|
|
7345
|
-
const url = joinUrl(baseUrl, '/orders/spot');
|
|
7346
|
-
try {
|
|
7347
|
-
const resp = await apiClient.post(url, payload, {
|
|
7348
|
-
headers: { 'Content-Type': 'application/json' },
|
|
7349
|
-
timeout: 60000,
|
|
7350
|
-
});
|
|
7351
|
-
return {
|
|
7352
|
-
data: resp.data,
|
|
7353
|
-
status: resp.status,
|
|
7354
|
-
headers: resp.headers,
|
|
7355
|
-
};
|
|
6850
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
7356
6851
|
}
|
|
7357
6852
|
catch (error) {
|
|
7358
6853
|
throw toApiError(error);
|
|
7359
6854
|
}
|
|
7360
6855
|
}
|
|
7361
6856
|
|
|
7362
|
-
function findAssetMeta$2(assetName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7363
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
7364
|
-
if (!perpMetaAssets) {
|
|
7365
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7366
|
-
}
|
|
7367
|
-
if (desiredCollateral) {
|
|
7368
|
-
const collateralMatch = perpMetaAssets.find((a) => a.name === assetName && a.collateralToken === desiredCollateral);
|
|
7369
|
-
if (collateralMatch) {
|
|
7370
|
-
return {
|
|
7371
|
-
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7372
|
-
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7373
|
-
};
|
|
7374
|
-
}
|
|
7375
|
-
}
|
|
7376
|
-
if (assetName.includes(':')) {
|
|
7377
|
-
const [prefix, symbol] = assetName.split(':');
|
|
7378
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7379
|
-
var _a;
|
|
7380
|
-
return a.name === symbol &&
|
|
7381
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7382
|
-
});
|
|
7383
|
-
if (exactMatch) {
|
|
7384
|
-
return {
|
|
7385
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7386
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7387
|
-
};
|
|
7388
|
-
}
|
|
7389
|
-
}
|
|
7390
|
-
if (knownPrefix) {
|
|
7391
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7392
|
-
var _a;
|
|
7393
|
-
return a.name === assetName &&
|
|
7394
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7395
|
-
});
|
|
7396
|
-
if (exactMatch) {
|
|
7397
|
-
return {
|
|
7398
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7399
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7400
|
-
};
|
|
7401
|
-
}
|
|
7402
|
-
}
|
|
7403
|
-
const regularAsset = perpMetaAssets.find((a) => a.name === assetName && !a.marketPrefix);
|
|
7404
|
-
if (regularAsset) {
|
|
7405
|
-
return {
|
|
7406
|
-
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7407
|
-
marketPrefix: null,
|
|
7408
|
-
};
|
|
7409
|
-
}
|
|
7410
|
-
const hip3Assets = perpMetaAssets.filter((a) => a.name === assetName && a.marketPrefix);
|
|
7411
|
-
if (hip3Assets.length > 0) {
|
|
7412
|
-
if (desiredCollateral) {
|
|
7413
|
-
const collateralMatch = hip3Assets.find((a) => a.collateralToken === desiredCollateral);
|
|
7414
|
-
if (collateralMatch) {
|
|
7415
|
-
return {
|
|
7416
|
-
collateralToken: (_h = collateralMatch.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7417
|
-
marketPrefix: (_j = collateralMatch.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7418
|
-
};
|
|
7419
|
-
}
|
|
7420
|
-
}
|
|
7421
|
-
const usdHMatch = hip3Assets.find((a) => a.collateralToken === 'USDH');
|
|
7422
|
-
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Assets[0];
|
|
7423
|
-
return {
|
|
7424
|
-
collateralToken: (_k = chosen.collateralToken) !== null && _k !== void 0 ? _k : 'USDC',
|
|
7425
|
-
marketPrefix: (_l = chosen.marketPrefix) !== null && _l !== void 0 ? _l : null,
|
|
7426
|
-
};
|
|
7427
|
-
}
|
|
7428
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7429
|
-
}
|
|
7430
|
-
function enrichOrderAssets$1(assets, perpMetaAssets) {
|
|
7431
|
-
if (!assets)
|
|
7432
|
-
return [];
|
|
7433
|
-
return assets.map((asset) => {
|
|
7434
|
-
var _a;
|
|
7435
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
7436
|
-
return asset;
|
|
7437
|
-
}
|
|
7438
|
-
const meta = findAssetMeta$2(asset.asset, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7439
|
-
return {
|
|
7440
|
-
...asset,
|
|
7441
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7442
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7443
|
-
};
|
|
7444
|
-
});
|
|
7445
|
-
}
|
|
7446
6857
|
function useOrders() {
|
|
7447
6858
|
const context = useContext(PearHyperliquidContext);
|
|
7448
6859
|
if (!context)
|
|
7449
6860
|
throw new Error('useOrders must be used within a PearHyperliquidProvider');
|
|
7450
6861
|
const { apiBaseUrl } = context;
|
|
7451
6862
|
const openOrders = useUserData((state) => state.openOrders);
|
|
7452
|
-
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
7453
6863
|
const isLoading = useMemo(() => openOrders === null && context.isConnected, [openOrders, context.isConnected]);
|
|
7454
6864
|
const { openPositions } = usePosition();
|
|
7455
6865
|
const positionsById = useMemo(() => {
|
|
@@ -7468,27 +6878,19 @@ function useOrders() {
|
|
|
7468
6878
|
const isTpSl = ord.orderType === 'TP' || ord.orderType === 'SL';
|
|
7469
6879
|
const hasAssets = ((_b = (_a = ord.longAssets) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0 || ((_d = (_c = ord.shortAssets) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) > 0;
|
|
7470
6880
|
const pos = positionsById.get((_e = ord.positionId) !== null && _e !== void 0 ? _e : '');
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
const mapAssets = (arr) => arr.map((a) => ({
|
|
7478
|
-
asset: a.coin,
|
|
7479
|
-
weight: a.initialWeight,
|
|
7480
|
-
marketPrefix: a.marketPrefix,
|
|
7481
|
-
collateralToken: a.collateralToken,
|
|
7482
|
-
}));
|
|
7483
|
-
enrichedOrd = {
|
|
7484
|
-
...enrichedOrd,
|
|
6881
|
+
if (!isTpSl || !pos)
|
|
6882
|
+
return ord;
|
|
6883
|
+
const mapAssets = (arr) => arr.map((a) => ({ asset: a.coin, weight: a.initialWeight }));
|
|
6884
|
+
if (!hasAssets) {
|
|
6885
|
+
return {
|
|
6886
|
+
...ord,
|
|
7485
6887
|
longAssets: mapAssets(pos.longAssets),
|
|
7486
6888
|
shortAssets: mapAssets(pos.shortAssets),
|
|
7487
6889
|
};
|
|
7488
6890
|
}
|
|
7489
|
-
return
|
|
6891
|
+
return ord;
|
|
7490
6892
|
});
|
|
7491
|
-
}, [openOrders, positionsById
|
|
6893
|
+
}, [openOrders, positionsById]);
|
|
7492
6894
|
const adjustOrder$1 = async (orderId, payload) => {
|
|
7493
6895
|
return adjustOrder(apiBaseUrl, orderId, payload);
|
|
7494
6896
|
};
|
|
@@ -7498,156 +6900,16 @@ function useOrders() {
|
|
|
7498
6900
|
const cancelTwapOrder$1 = async (orderId) => {
|
|
7499
6901
|
return cancelTwapOrder(apiBaseUrl, orderId);
|
|
7500
6902
|
};
|
|
7501
|
-
return {
|
|
7502
|
-
adjustOrder: adjustOrder$1,
|
|
7503
|
-
cancelOrder: cancelOrder$1,
|
|
7504
|
-
cancelTwapOrder: cancelTwapOrder$1,
|
|
7505
|
-
openOrders: enrichedOpenOrders,
|
|
7506
|
-
isLoading,
|
|
7507
|
-
};
|
|
6903
|
+
return { adjustOrder: adjustOrder$1, cancelOrder: cancelOrder$1, cancelTwapOrder: cancelTwapOrder$1, openOrders: enrichedOpenOrders, isLoading };
|
|
7508
6904
|
}
|
|
7509
6905
|
|
|
7510
|
-
/**
|
|
7511
|
-
* Hook for executing spot orders (swaps) on Hyperliquid
|
|
7512
|
-
* Use this to swap between USDC and USDH or other spot assets
|
|
7513
|
-
*/
|
|
7514
|
-
function useSpotOrder() {
|
|
7515
|
-
const context = useContext(PearHyperliquidContext);
|
|
7516
|
-
if (!context) {
|
|
7517
|
-
throw new Error('useSpotOrder must be used within a PearHyperliquidProvider');
|
|
7518
|
-
}
|
|
7519
|
-
const { apiBaseUrl } = context;
|
|
7520
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
7521
|
-
const [error, setError] = useState(null);
|
|
7522
|
-
const resetError = useCallback(() => {
|
|
7523
|
-
setError(null);
|
|
7524
|
-
}, []);
|
|
7525
|
-
const executeSpotOrder$1 = useCallback(async (payload) => {
|
|
7526
|
-
setIsLoading(true);
|
|
7527
|
-
setError(null);
|
|
7528
|
-
try {
|
|
7529
|
-
const response = await executeSpotOrder(apiBaseUrl, payload);
|
|
7530
|
-
return response;
|
|
7531
|
-
}
|
|
7532
|
-
catch (err) {
|
|
7533
|
-
const apiError = err;
|
|
7534
|
-
setError(apiError);
|
|
7535
|
-
throw apiError;
|
|
7536
|
-
}
|
|
7537
|
-
finally {
|
|
7538
|
-
setIsLoading(false);
|
|
7539
|
-
}
|
|
7540
|
-
}, [apiBaseUrl]);
|
|
7541
|
-
return {
|
|
7542
|
-
executeSpotOrder: executeSpotOrder$1,
|
|
7543
|
-
isLoading,
|
|
7544
|
-
error,
|
|
7545
|
-
resetError,
|
|
7546
|
-
};
|
|
7547
|
-
}
|
|
7548
|
-
|
|
7549
|
-
function findAssetMeta$1(assetName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7550
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
7551
|
-
if (!perpMetaAssets) {
|
|
7552
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7553
|
-
}
|
|
7554
|
-
if (desiredCollateral) {
|
|
7555
|
-
const collateralMatch = perpMetaAssets.find((a) => a.name === assetName && a.collateralToken === desiredCollateral);
|
|
7556
|
-
if (collateralMatch) {
|
|
7557
|
-
return {
|
|
7558
|
-
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7559
|
-
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7560
|
-
};
|
|
7561
|
-
}
|
|
7562
|
-
}
|
|
7563
|
-
if (assetName.includes(':')) {
|
|
7564
|
-
const [prefix, symbol] = assetName.split(':');
|
|
7565
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7566
|
-
var _a;
|
|
7567
|
-
return a.name === symbol &&
|
|
7568
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7569
|
-
});
|
|
7570
|
-
if (exactMatch) {
|
|
7571
|
-
return {
|
|
7572
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7573
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7574
|
-
};
|
|
7575
|
-
}
|
|
7576
|
-
}
|
|
7577
|
-
if (knownPrefix) {
|
|
7578
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7579
|
-
var _a;
|
|
7580
|
-
return a.name === assetName &&
|
|
7581
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7582
|
-
});
|
|
7583
|
-
if (exactMatch) {
|
|
7584
|
-
return {
|
|
7585
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7586
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7587
|
-
};
|
|
7588
|
-
}
|
|
7589
|
-
}
|
|
7590
|
-
const regularAsset = perpMetaAssets.find((a) => a.name === assetName && !a.marketPrefix);
|
|
7591
|
-
if (regularAsset) {
|
|
7592
|
-
return {
|
|
7593
|
-
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7594
|
-
marketPrefix: null,
|
|
7595
|
-
};
|
|
7596
|
-
}
|
|
7597
|
-
const hip3Assets = perpMetaAssets.filter((a) => a.name === assetName && a.marketPrefix);
|
|
7598
|
-
if (hip3Assets.length > 0) {
|
|
7599
|
-
if (desiredCollateral) {
|
|
7600
|
-
const collateralMatch = hip3Assets.find((a) => a.collateralToken === desiredCollateral);
|
|
7601
|
-
if (collateralMatch) {
|
|
7602
|
-
return {
|
|
7603
|
-
collateralToken: (_h = collateralMatch.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7604
|
-
marketPrefix: (_j = collateralMatch.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7605
|
-
};
|
|
7606
|
-
}
|
|
7607
|
-
}
|
|
7608
|
-
const usdHMatch = hip3Assets.find((a) => a.collateralToken === 'USDH');
|
|
7609
|
-
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Assets[0];
|
|
7610
|
-
return {
|
|
7611
|
-
collateralToken: (_k = chosen.collateralToken) !== null && _k !== void 0 ? _k : 'USDC',
|
|
7612
|
-
marketPrefix: (_l = chosen.marketPrefix) !== null && _l !== void 0 ? _l : null,
|
|
7613
|
-
};
|
|
7614
|
-
}
|
|
7615
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7616
|
-
}
|
|
7617
|
-
function enrichOrderAssets(assets, perpMetaAssets) {
|
|
7618
|
-
if (!assets)
|
|
7619
|
-
return [];
|
|
7620
|
-
return assets.map((asset) => {
|
|
7621
|
-
var _a;
|
|
7622
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
7623
|
-
return asset;
|
|
7624
|
-
}
|
|
7625
|
-
const meta = findAssetMeta$1(asset.asset, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7626
|
-
return {
|
|
7627
|
-
...asset,
|
|
7628
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7629
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7630
|
-
};
|
|
7631
|
-
});
|
|
7632
|
-
}
|
|
7633
|
-
function enrichTwapOrders(orders, perpMetaAssets) {
|
|
7634
|
-
return orders.map((order) => ({
|
|
7635
|
-
...order,
|
|
7636
|
-
longAssets: enrichOrderAssets(order.longAssets, perpMetaAssets),
|
|
7637
|
-
shortAssets: enrichOrderAssets(order.shortAssets, perpMetaAssets),
|
|
7638
|
-
}));
|
|
7639
|
-
}
|
|
7640
6906
|
function useTwap() {
|
|
7641
|
-
const twapDetails = useUserData(
|
|
7642
|
-
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
6907
|
+
const twapDetails = useUserData(state => state.twapDetails);
|
|
7643
6908
|
const context = useContext(PearHyperliquidContext);
|
|
7644
6909
|
if (!context)
|
|
7645
6910
|
throw new Error('useTwap must be used within a PearHyperliquidProvider');
|
|
7646
6911
|
const { apiBaseUrl } = context;
|
|
7647
|
-
const orders = useMemo(() =>
|
|
7648
|
-
const rawOrders = twapDetails !== null && twapDetails !== void 0 ? twapDetails : [];
|
|
7649
|
-
return enrichTwapOrders(rawOrders, allPerpMetaAssets);
|
|
7650
|
-
}, [twapDetails, allPerpMetaAssets]);
|
|
6912
|
+
const orders = useMemo(() => twapDetails !== null && twapDetails !== void 0 ? twapDetails : [], [twapDetails]);
|
|
7651
6913
|
const cancelTwap$1 = async (orderId) => {
|
|
7652
6914
|
return cancelTwap(apiBaseUrl, orderId);
|
|
7653
6915
|
};
|
|
@@ -7730,170 +6992,59 @@ function useNotifications() {
|
|
|
7730
6992
|
};
|
|
7731
6993
|
}
|
|
7732
6994
|
|
|
7733
|
-
//
|
|
7734
|
-
function findAssetMeta(assetName, perpMetaAssets) {
|
|
7735
|
-
var _a, _b, _c, _d;
|
|
7736
|
-
if (!perpMetaAssets) {
|
|
7737
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7738
|
-
}
|
|
7739
|
-
// Try exact match first (for prefixed assets like "xyz:TSLA")
|
|
7740
|
-
const exactMatch = perpMetaAssets.find((a) => a.name === assetName);
|
|
7741
|
-
if (exactMatch) {
|
|
7742
|
-
return {
|
|
7743
|
-
collateralToken: (_a = exactMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7744
|
-
marketPrefix: (_b = exactMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7745
|
-
};
|
|
7746
|
-
}
|
|
7747
|
-
// Try matching by base symbol (for non-prefixed names in data)
|
|
7748
|
-
const baseMatch = perpMetaAssets.find((a) => {
|
|
7749
|
-
const baseName = a.name.includes(':') ? a.name.split(':')[1] : a.name;
|
|
7750
|
-
return baseName === assetName;
|
|
7751
|
-
});
|
|
7752
|
-
if (baseMatch) {
|
|
7753
|
-
return {
|
|
7754
|
-
collateralToken: (_c = baseMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7755
|
-
marketPrefix: (_d = baseMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7756
|
-
};
|
|
7757
|
-
}
|
|
7758
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7759
|
-
}
|
|
7760
|
-
// Enrich a single asset with metadata
|
|
7761
|
-
function enrichAsset(asset, perpMetaAssets) {
|
|
7762
|
-
const meta = findAssetMeta(asset.asset, perpMetaAssets);
|
|
7763
|
-
return {
|
|
7764
|
-
...asset,
|
|
7765
|
-
collateralToken: meta.collateralToken,
|
|
7766
|
-
marketPrefix: meta.marketPrefix,
|
|
7767
|
-
};
|
|
7768
|
-
}
|
|
7769
|
-
// Enrich a basket item with collateral info
|
|
7770
|
-
function enrichBasketItem(item, perpMetaAssets) {
|
|
7771
|
-
const enrichedLongs = item.longAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7772
|
-
const enrichedShorts = item.shortAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7773
|
-
// Determine collateral type
|
|
7774
|
-
const allAssets = [...enrichedLongs, ...enrichedShorts];
|
|
7775
|
-
const hasUsdc = allAssets.some((a) => a.collateralToken === 'USDC');
|
|
7776
|
-
const hasUsdh = allAssets.some((a) => a.collateralToken === 'USDH');
|
|
7777
|
-
let collateralType = 'USDC';
|
|
7778
|
-
if (hasUsdc && hasUsdh) {
|
|
7779
|
-
collateralType = 'MIXED';
|
|
7780
|
-
}
|
|
7781
|
-
else if (hasUsdh) {
|
|
7782
|
-
collateralType = 'USDH';
|
|
7783
|
-
}
|
|
7784
|
-
return {
|
|
7785
|
-
...item,
|
|
7786
|
-
longAssets: enrichedLongs,
|
|
7787
|
-
shortAssets: enrichedShorts,
|
|
7788
|
-
collateralType,
|
|
7789
|
-
};
|
|
7790
|
-
}
|
|
7791
|
-
/**
|
|
7792
|
-
* Filter baskets by collateral type
|
|
7793
|
-
* - 'USDC': Only baskets where ALL assets use USDC (collateralType === 'USDC')
|
|
7794
|
-
* - 'USDH': Only baskets where ALL assets use USDH (collateralType === 'USDH')
|
|
7795
|
-
* - 'ALL' or undefined: No filtering, returns all baskets
|
|
7796
|
-
*/
|
|
7797
|
-
function filterByCollateral(baskets, filter) {
|
|
7798
|
-
if (!filter || filter === 'ALL') {
|
|
7799
|
-
return baskets;
|
|
7800
|
-
}
|
|
7801
|
-
return baskets.filter((basket) => {
|
|
7802
|
-
if (filter === 'USDC') {
|
|
7803
|
-
// Include baskets that are purely USDC or have USDC assets
|
|
7804
|
-
return (basket.collateralType === 'USDC' || basket.collateralType === 'MIXED');
|
|
7805
|
-
}
|
|
7806
|
-
if (filter === 'USDH') {
|
|
7807
|
-
// Include baskets that are purely USDH or have USDH assets
|
|
7808
|
-
return (basket.collateralType === 'USDH' || basket.collateralType === 'MIXED');
|
|
7809
|
-
}
|
|
7810
|
-
return true;
|
|
7811
|
-
});
|
|
7812
|
-
}
|
|
7813
|
-
// Base selector for the full market-data payload (raw from WS)
|
|
6995
|
+
// Base selector for the full market-data payload
|
|
7814
6996
|
const useMarketDataPayload = () => {
|
|
7815
6997
|
return useMarketData((s) => s.marketData);
|
|
7816
6998
|
};
|
|
7817
|
-
// Full payload for 'market-data-all' channel
|
|
6999
|
+
// Full payload for 'market-data-all' channel
|
|
7818
7000
|
const useMarketDataAllPayload = () => {
|
|
7819
7001
|
return useMarketData((s) => s.marketDataAll);
|
|
7820
7002
|
};
|
|
7821
|
-
//
|
|
7822
|
-
const
|
|
7823
|
-
|
|
7824
|
-
};
|
|
7825
|
-
// Active baskets (with collateral and market prefix info)
|
|
7826
|
-
const useActiveBaskets = (collateralFilter) => {
|
|
7003
|
+
// Active baskets
|
|
7004
|
+
const useActiveBaskets = () => {
|
|
7005
|
+
var _a;
|
|
7827
7006
|
const data = useMarketDataPayload();
|
|
7828
|
-
|
|
7829
|
-
return useMemo(() => {
|
|
7830
|
-
if (!(data === null || data === void 0 ? void 0 : data.active))
|
|
7831
|
-
return [];
|
|
7832
|
-
const enriched = data.active.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7833
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7834
|
-
}, [data, perpMetaAssets, collateralFilter]);
|
|
7007
|
+
return (_a = data === null || data === void 0 ? void 0 : data.active) !== null && _a !== void 0 ? _a : [];
|
|
7835
7008
|
};
|
|
7836
|
-
// Top gainers (
|
|
7837
|
-
const useTopGainers = (limit
|
|
7009
|
+
// Top gainers (optional limit override)
|
|
7010
|
+
const useTopGainers = (limit) => {
|
|
7838
7011
|
const data = useMarketDataPayload();
|
|
7839
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7840
7012
|
return useMemo(() => {
|
|
7841
7013
|
var _a;
|
|
7842
7014
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topGainers) !== null && _a !== void 0 ? _a : [];
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7846
|
-
}, [data, perpMetaAssets, limit, collateralFilter]);
|
|
7015
|
+
return typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
7016
|
+
}, [data, limit]);
|
|
7847
7017
|
};
|
|
7848
|
-
// Top losers (
|
|
7849
|
-
const useTopLosers = (limit
|
|
7018
|
+
// Top losers (optional limit override)
|
|
7019
|
+
const useTopLosers = (limit) => {
|
|
7850
7020
|
const data = useMarketDataPayload();
|
|
7851
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7852
7021
|
return useMemo(() => {
|
|
7853
7022
|
var _a;
|
|
7854
7023
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topLosers) !== null && _a !== void 0 ? _a : [];
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7858
|
-
}, [data, perpMetaAssets, limit, collateralFilter]);
|
|
7024
|
+
return typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
7025
|
+
}, [data, limit]);
|
|
7859
7026
|
};
|
|
7860
|
-
// Highlighted baskets
|
|
7861
|
-
const useHighlightedBaskets = (
|
|
7027
|
+
// Highlighted baskets
|
|
7028
|
+
const useHighlightedBaskets = () => {
|
|
7029
|
+
var _a;
|
|
7862
7030
|
const data = useMarketDataPayload();
|
|
7863
|
-
|
|
7864
|
-
return useMemo(() => {
|
|
7865
|
-
if (!(data === null || data === void 0 ? void 0 : data.highlighted))
|
|
7866
|
-
return [];
|
|
7867
|
-
const enriched = data.highlighted.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7868
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7869
|
-
}, [data, perpMetaAssets, collateralFilter]);
|
|
7031
|
+
return (_a = data === null || data === void 0 ? void 0 : data.highlighted) !== null && _a !== void 0 ? _a : [];
|
|
7870
7032
|
};
|
|
7871
|
-
// Watchlist baskets (
|
|
7872
|
-
const useWatchlistBaskets = (
|
|
7033
|
+
// Watchlist baskets (from market-data payload when subscribed with address)
|
|
7034
|
+
const useWatchlistBaskets = () => {
|
|
7035
|
+
var _a;
|
|
7873
7036
|
const data = useMarketDataPayload();
|
|
7874
|
-
|
|
7875
|
-
return useMemo(() => {
|
|
7876
|
-
if (!(data === null || data === void 0 ? void 0 : data.watchlist))
|
|
7877
|
-
return [];
|
|
7878
|
-
const enriched = data.watchlist.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7879
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7880
|
-
}, [data, perpMetaAssets, collateralFilter]);
|
|
7037
|
+
return (_a = data === null || data === void 0 ? void 0 : data.watchlist) !== null && _a !== void 0 ? _a : [];
|
|
7881
7038
|
};
|
|
7882
|
-
// All baskets (
|
|
7883
|
-
const useAllBaskets = (
|
|
7039
|
+
// All baskets (from market-data-all)
|
|
7040
|
+
const useAllBaskets = () => {
|
|
7041
|
+
var _a;
|
|
7884
7042
|
const dataAll = useMarketDataAllPayload();
|
|
7885
|
-
|
|
7886
|
-
return useMemo(() => {
|
|
7887
|
-
if (!(dataAll === null || dataAll === void 0 ? void 0 : dataAll.all))
|
|
7888
|
-
return [];
|
|
7889
|
-
const enriched = dataAll.all.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7890
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7891
|
-
}, [dataAll, perpMetaAssets, collateralFilter]);
|
|
7043
|
+
return (_a = dataAll === null || dataAll === void 0 ? void 0 : dataAll.all) !== null && _a !== void 0 ? _a : [];
|
|
7892
7044
|
};
|
|
7893
7045
|
// Find a basket by its exact asset composition (order-insensitive)
|
|
7894
7046
|
const useFindBasket = (longs, shorts) => {
|
|
7895
7047
|
const data = useMarketDataPayload();
|
|
7896
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7897
7048
|
return useMemo(() => {
|
|
7898
7049
|
if (!data)
|
|
7899
7050
|
return undefined;
|
|
@@ -7907,28 +7058,17 @@ const useFindBasket = (longs, shorts) => {
|
|
|
7907
7058
|
: '';
|
|
7908
7059
|
const lKey = normalize(longs);
|
|
7909
7060
|
const sKey = normalize(shorts);
|
|
7910
|
-
const match = (item) => normalize(item.longAssets) === lKey &&
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
return found
|
|
7914
|
-
? enrichBasketItem(found, perpMetaAssets)
|
|
7915
|
-
: undefined;
|
|
7916
|
-
}, [data, longs, shorts, perpMetaAssets]);
|
|
7061
|
+
const match = (item) => normalize(item.longAssets) === lKey && normalize(item.shortAssets) === sKey;
|
|
7062
|
+
return data.active.find(match) || data.highlighted.find(match);
|
|
7063
|
+
}, [data, longs, shorts]);
|
|
7917
7064
|
};
|
|
7918
7065
|
|
|
7919
|
-
async function toggleWatchlist(baseUrl, longAssets, shortAssets,
|
|
7066
|
+
async function toggleWatchlist(baseUrl, longAssets, shortAssets, displayToFull) {
|
|
7920
7067
|
const url = joinUrl(baseUrl, '/watchlist');
|
|
7921
|
-
const mapAssets = (arr) => arr.map(
|
|
7068
|
+
const mapAssets = (arr) => arr.map(a => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
7922
7069
|
try {
|
|
7923
|
-
const response = await apiClient.post(url, {
|
|
7924
|
-
|
|
7925
|
-
shortAssets: mapAssets(shortAssets),
|
|
7926
|
-
}, { headers: { 'Content-Type': 'application/json' } });
|
|
7927
|
-
return {
|
|
7928
|
-
data: response.data,
|
|
7929
|
-
status: response.status,
|
|
7930
|
-
headers: response.headers,
|
|
7931
|
-
};
|
|
7070
|
+
const response = await apiClient.post(url, { longAssets: mapAssets(longAssets), shortAssets: mapAssets(shortAssets) }, { headers: { 'Content-Type': 'application/json' } });
|
|
7071
|
+
return { data: response.data, status: response.status, headers: response.headers };
|
|
7932
7072
|
}
|
|
7933
7073
|
catch (error) {
|
|
7934
7074
|
throw toApiError(error);
|
|
@@ -7940,11 +7080,11 @@ function useWatchlist() {
|
|
|
7940
7080
|
if (!context)
|
|
7941
7081
|
throw new Error('useWatchlist must be used within a PearHyperliquidProvider');
|
|
7942
7082
|
const { apiBaseUrl, isConnected } = context;
|
|
7943
|
-
const
|
|
7083
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
7944
7084
|
const marketData = useMarketDataPayload();
|
|
7945
7085
|
const isLoading = useMemo(() => !marketData && isConnected, [marketData, isConnected]);
|
|
7946
7086
|
const toggle = async (longAssets, shortAssets) => {
|
|
7947
|
-
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets,
|
|
7087
|
+
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets, displayToFull);
|
|
7948
7088
|
// Server will push updated market-data over WS; nothing to set here
|
|
7949
7089
|
return resp;
|
|
7950
7090
|
};
|
|
@@ -8066,38 +7206,46 @@ async function logout(baseUrl, refreshTokenVal) {
|
|
|
8066
7206
|
function useAuth() {
|
|
8067
7207
|
const context = useContext(PearHyperliquidContext);
|
|
8068
7208
|
if (!context) {
|
|
8069
|
-
throw new Error("
|
|
7209
|
+
throw new Error("useAuth must be used within a PearHyperliquidProvider");
|
|
8070
7210
|
}
|
|
8071
7211
|
const { apiBaseUrl, clientId } = context;
|
|
8072
|
-
const [isReady, setIsReady] = useState(false);
|
|
8073
7212
|
const accessToken = useUserData((s) => s.accessToken);
|
|
8074
7213
|
const refreshToken$1 = useUserData((s) => s.refreshToken);
|
|
7214
|
+
const isReady = useUserData((s) => s.isReady);
|
|
7215
|
+
const isAuthenticated = useUserData((s) => s.isAuthenticated);
|
|
7216
|
+
const address = useUserData((s) => s.address);
|
|
8075
7217
|
const setAccessToken = useUserData((s) => s.setAccessToken);
|
|
8076
7218
|
const setRefreshToken = useUserData((s) => s.setRefreshToken);
|
|
8077
|
-
const
|
|
7219
|
+
const setIsReady = useUserData((s) => s.setIsReady);
|
|
8078
7220
|
const setIsAuthenticated = useUserData((s) => s.setIsAuthenticated);
|
|
8079
7221
|
const setAddress = useUserData((s) => s.setAddress);
|
|
8080
7222
|
useEffect(() => {
|
|
8081
7223
|
if (typeof window == "undefined") {
|
|
8082
7224
|
return;
|
|
8083
7225
|
}
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
7226
|
+
if (address) {
|
|
7227
|
+
// If we already have an address in state, use it to load the session
|
|
7228
|
+
const accessTokenKey = `${address}_accessToken`;
|
|
7229
|
+
const refreshTokenKey = `${address}_refreshToken`;
|
|
7230
|
+
const storedAccessToken = localStorage.getItem(accessTokenKey);
|
|
7231
|
+
const storedRefreshToken = localStorage.getItem(refreshTokenKey);
|
|
7232
|
+
console.log({ storedAccessToken, storedRefreshToken });
|
|
7233
|
+
if (storedAccessToken && storedRefreshToken) {
|
|
7234
|
+
setAccessToken(storedAccessToken);
|
|
7235
|
+
setRefreshToken(storedRefreshToken);
|
|
7236
|
+
setIsAuthenticated(true);
|
|
7237
|
+
}
|
|
7238
|
+
}
|
|
8092
7239
|
setIsReady(true);
|
|
8093
|
-
}, [
|
|
7240
|
+
}, [address]);
|
|
8094
7241
|
useEffect(() => {
|
|
8095
7242
|
const cleanup = addAuthInterceptors({
|
|
8096
7243
|
apiBaseUrl,
|
|
8097
7244
|
getAccessToken: () => {
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
7245
|
+
if (typeof window === "undefined")
|
|
7246
|
+
return null;
|
|
7247
|
+
// Read from Zustand state as single source of truth
|
|
7248
|
+
return useUserData.getState().accessToken;
|
|
8101
7249
|
},
|
|
8102
7250
|
refreshTokens: async () => {
|
|
8103
7251
|
const data = await refreshTokens();
|
|
@@ -8123,12 +7271,12 @@ function useAuth() {
|
|
|
8123
7271
|
clientId,
|
|
8124
7272
|
details: { signature, timestamp },
|
|
8125
7273
|
});
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
window.localStorage.setItem(
|
|
7274
|
+
const accessTokenKey = `${address}_accessToken`;
|
|
7275
|
+
const refreshTokenKey = `${address}_refreshToken`;
|
|
7276
|
+
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7277
|
+
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
8129
7278
|
setAccessToken(data.accessToken);
|
|
8130
7279
|
setRefreshToken(data.refreshToken);
|
|
8131
|
-
setAddress(address);
|
|
8132
7280
|
setIsAuthenticated(true);
|
|
8133
7281
|
}
|
|
8134
7282
|
catch (e) {
|
|
@@ -8143,12 +7291,12 @@ function useAuth() {
|
|
|
8143
7291
|
appId,
|
|
8144
7292
|
accessToken: privyAccessToken,
|
|
8145
7293
|
});
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
window.localStorage.setItem(
|
|
7294
|
+
const accessTokenKey = `${address}_accessToken`;
|
|
7295
|
+
const refreshTokenKey = `${address}_refreshToken`;
|
|
7296
|
+
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7297
|
+
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
8149
7298
|
setAccessToken(data.accessToken);
|
|
8150
7299
|
setRefreshToken(data.refreshToken);
|
|
8151
|
-
setAddress(address);
|
|
8152
7300
|
setIsAuthenticated(true);
|
|
8153
7301
|
}
|
|
8154
7302
|
catch (e) {
|
|
@@ -8156,30 +7304,38 @@ function useAuth() {
|
|
|
8156
7304
|
}
|
|
8157
7305
|
}
|
|
8158
7306
|
async function refreshTokens() {
|
|
8159
|
-
const
|
|
8160
|
-
|
|
7307
|
+
const currentAddress = address;
|
|
7308
|
+
const currentRefresh = refreshToken$1;
|
|
7309
|
+
if (!currentRefresh || !currentAddress)
|
|
8161
7310
|
throw new Error("No refresh token");
|
|
8162
|
-
const { data } = await refreshToken(apiBaseUrl,
|
|
8163
|
-
|
|
8164
|
-
|
|
7311
|
+
const { data } = await refreshToken(apiBaseUrl, currentRefresh);
|
|
7312
|
+
// Update tokens in localStorage
|
|
7313
|
+
const accessTokenKey = `${currentAddress}_accessToken`;
|
|
7314
|
+
const refreshTokenKey = `${currentAddress}_refreshToken`;
|
|
7315
|
+
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7316
|
+
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
8165
7317
|
setAccessToken(data.accessToken);
|
|
8166
7318
|
setRefreshToken(data.refreshToken);
|
|
8167
7319
|
setIsAuthenticated(true);
|
|
8168
7320
|
return data;
|
|
8169
7321
|
}
|
|
8170
7322
|
async function logout$1() {
|
|
8171
|
-
const
|
|
8172
|
-
|
|
7323
|
+
const currentAddress = address;
|
|
7324
|
+
const currentRefresh = refreshToken$1;
|
|
7325
|
+
if (currentRefresh) {
|
|
8173
7326
|
try {
|
|
8174
|
-
await logout(apiBaseUrl,
|
|
7327
|
+
await logout(apiBaseUrl, currentRefresh);
|
|
8175
7328
|
}
|
|
8176
7329
|
catch (_a) {
|
|
8177
7330
|
/* ignore */
|
|
8178
7331
|
}
|
|
8179
7332
|
}
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
7333
|
+
if (currentAddress) {
|
|
7334
|
+
const accessTokenKey = `${currentAddress}_accessToken`;
|
|
7335
|
+
const refreshTokenKey = `${currentAddress}_refreshToken`;
|
|
7336
|
+
window.localStorage.removeItem(accessTokenKey);
|
|
7337
|
+
window.localStorage.removeItem(refreshTokenKey);
|
|
7338
|
+
}
|
|
8183
7339
|
setAccessToken(null);
|
|
8184
7340
|
setRefreshToken(null);
|
|
8185
7341
|
setAddress(null);
|
|
@@ -8195,114 +7351,20 @@ function useAuth() {
|
|
|
8195
7351
|
loginWithPrivyToken,
|
|
8196
7352
|
refreshTokens,
|
|
8197
7353
|
logout: logout$1,
|
|
7354
|
+
setAddress,
|
|
7355
|
+
address,
|
|
8198
7356
|
};
|
|
8199
7357
|
}
|
|
8200
7358
|
|
|
8201
|
-
const useAllUserBalances = () => {
|
|
8202
|
-
const spotState = useUserData((state) => state.spotState);
|
|
8203
|
-
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
8204
|
-
const rawClearinghouseStates = useHyperliquidData((state) => state.rawClearinghouseStates);
|
|
8205
|
-
const activeAssetData = useHyperliquidData((state) => state.activeAssetData);
|
|
8206
|
-
const { longTokensMetadata, shortTokensMetadata } = useTokenSelectionMetadata();
|
|
8207
|
-
return useMemo(() => {
|
|
8208
|
-
const isLoading = !spotState || !aggregatedClearingHouseState;
|
|
8209
|
-
// Helper function to truncate to 2 decimal places without rounding
|
|
8210
|
-
const truncateToTwoDecimals = (value) => {
|
|
8211
|
-
return Math.floor(value * 100) / 100;
|
|
8212
|
-
};
|
|
8213
|
-
// Get spot balances from spotState
|
|
8214
|
-
let spotUsdcBal = undefined;
|
|
8215
|
-
let spotUsdhBal = undefined;
|
|
8216
|
-
if (spotState) {
|
|
8217
|
-
const balances = spotState.balances || [];
|
|
8218
|
-
for (const balance of balances) {
|
|
8219
|
-
const total = parseFloat(balance.total || '0');
|
|
8220
|
-
if (balance.coin === 'USDC') {
|
|
8221
|
-
spotUsdcBal = truncateToTwoDecimals(total);
|
|
8222
|
-
}
|
|
8223
|
-
if (balance.coin === 'USDH') {
|
|
8224
|
-
spotUsdhBal = truncateToTwoDecimals(total);
|
|
8225
|
-
}
|
|
8226
|
-
}
|
|
8227
|
-
}
|
|
8228
|
-
let availableToTradeUsdhFromAsset = 0;
|
|
8229
|
-
// This activeAssetData only contains data for SELECTED tokens (user's long and short Tokens)
|
|
8230
|
-
// It does NOT contain data for all tokens, so we cannot reliably use it for available to trade as used on hl trade page
|
|
8231
|
-
// so intead, we rely on rawClearinghouseStates which provides market-specific data
|
|
8232
|
-
// if (activeAssetData) {
|
|
8233
|
-
// Object.values(activeAssetData).forEach((assetData) => {
|
|
8234
|
-
// if (!assetData.availableToTrade) return;
|
|
8235
|
-
// const coinSymbol = assetData.coin;
|
|
8236
|
-
// const availableValue = truncateToTwoDecimals(
|
|
8237
|
-
// parseFloat(assetData.availableToTrade[0] || '0'),
|
|
8238
|
-
// );
|
|
8239
|
-
// // Determine collateral type based on market prefix
|
|
8240
|
-
// // HIP3 markets have prefix: "xyz:SYMBOL", "flx:SYMBOL", "vntl:SYMBOL", etc.
|
|
8241
|
-
// if (coinSymbol.includes(':')) {
|
|
8242
|
-
// const prefix = coinSymbol.split(':')[0];
|
|
8243
|
-
// if (prefix === 'xyz') {
|
|
8244
|
-
// // xyz markets use USDC
|
|
8245
|
-
// availableToTradeUsdcFromAsset = availableValue;
|
|
8246
|
-
// } else {
|
|
8247
|
-
// // flx, vntl, hyna and other markets use USDH
|
|
8248
|
-
// availableToTradeUsdhFromAsset = availableValue;
|
|
8249
|
-
// }
|
|
8250
|
-
// } else {
|
|
8251
|
-
// // Regular markets without prefix are automatically USDC
|
|
8252
|
-
// availableToTradeUsdcFromAsset = availableValue;
|
|
8253
|
-
// }
|
|
8254
|
-
// });
|
|
8255
|
-
// }
|
|
8256
|
-
// Calculate USDC available to trade
|
|
8257
|
-
// Priority 1: Use value from activeAssetData if available (> 0)
|
|
8258
|
-
// Priority 2: Calculate from USDC-specific clearinghouseState (empty prefix)
|
|
8259
|
-
let availableToTradeUsdcValue = undefined;
|
|
8260
|
-
if (rawClearinghouseStates) {
|
|
8261
|
-
// Find USDC market (empty prefix)
|
|
8262
|
-
const usdcMarket = rawClearinghouseStates.find(([prefix]) => prefix === '');
|
|
8263
|
-
const usdcState = usdcMarket === null || usdcMarket === void 0 ? void 0 : usdcMarket[1];
|
|
8264
|
-
if (usdcState === null || usdcState === void 0 ? void 0 : usdcState.marginSummary) {
|
|
8265
|
-
const accountValue = parseFloat(usdcState.marginSummary.accountValue || '0');
|
|
8266
|
-
const totalMarginUsed = parseFloat(usdcState.marginSummary.totalMarginUsed || '0');
|
|
8267
|
-
const calculatedValue = Math.max(0, accountValue - totalMarginUsed);
|
|
8268
|
-
availableToTradeUsdcValue = truncateToTwoDecimals(calculatedValue);
|
|
8269
|
-
}
|
|
8270
|
-
}
|
|
8271
|
-
// Calculate USDH available to trade
|
|
8272
|
-
// Priority 1: Use value from activeAssetData if available (> 0)
|
|
8273
|
-
// Priority 2: Use spot USDH balance
|
|
8274
|
-
const availableToTradeUsdhValue = availableToTradeUsdhFromAsset > 0
|
|
8275
|
-
? availableToTradeUsdhFromAsset
|
|
8276
|
-
: spotUsdhBal;
|
|
8277
|
-
return {
|
|
8278
|
-
spotUsdcBalance: spotUsdcBal,
|
|
8279
|
-
availableToTradeUsdc: availableToTradeUsdcValue,
|
|
8280
|
-
spotUsdhBalance: spotUsdhBal,
|
|
8281
|
-
availableToTradeUsdh: availableToTradeUsdhValue,
|
|
8282
|
-
isLoading,
|
|
8283
|
-
};
|
|
8284
|
-
}, [
|
|
8285
|
-
spotState,
|
|
8286
|
-
aggregatedClearingHouseState,
|
|
8287
|
-
rawClearinghouseStates,
|
|
8288
|
-
activeAssetData,
|
|
8289
|
-
longTokensMetadata,
|
|
8290
|
-
shortTokensMetadata,
|
|
8291
|
-
]);
|
|
8292
|
-
};
|
|
8293
|
-
|
|
8294
7359
|
const PearHyperliquidContext = createContext(undefined);
|
|
8295
7360
|
/**
|
|
8296
7361
|
* React Provider for PearHyperliquidClient
|
|
8297
7362
|
*/
|
|
8298
|
-
const PearHyperliquidProvider = ({ children, apiBaseUrl =
|
|
7363
|
+
const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearprotocol.io", clientId = "PEARPROTOCOLUI", wsUrl = "wss://hl-ui.pearprotocol.io/ws", }) => {
|
|
8299
7364
|
const address = useUserData((s) => s.address);
|
|
8300
|
-
const setAddress = useUserData((s) => s.setAddress);
|
|
8301
7365
|
const perpsMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
8302
7366
|
const setPerpMetaAssets = useHyperliquidData((state) => state.setPerpMetaAssets);
|
|
8303
|
-
const
|
|
8304
|
-
const setHip3Assets = useHyperliquidData((state) => state.setHip3Assets);
|
|
8305
|
-
const setHip3MarketPrefixes = useHyperliquidData((state) => state.setHip3MarketPrefixes);
|
|
7367
|
+
const setHip3DisplayToFull = useHyperliquidData((state) => state.setHip3DisplayToFull);
|
|
8306
7368
|
const websocketsEnabled = useMemo(() => Array.isArray(perpsMetaAssets) && perpsMetaAssets.length > 0, [perpsMetaAssets]);
|
|
8307
7369
|
const { isConnected, lastError } = useHyperliquidWebSocket({
|
|
8308
7370
|
wsUrl,
|
|
@@ -8317,107 +7379,32 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearpro
|
|
|
8317
7379
|
if (perpsMetaAssets === null) {
|
|
8318
7380
|
fetchAllPerpMetas()
|
|
8319
7381
|
.then((res) => {
|
|
8320
|
-
|
|
8321
|
-
const
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
const
|
|
8326
|
-
const
|
|
8327
|
-
|
|
8328
|
-
const
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
const
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
if (!FILTERED_PREFIXES.includes(prefix)) {
|
|
8339
|
-
const existingMarkets = (_a = assetToMarkets.get(displayName)) !== null && _a !== void 0 ? _a : [];
|
|
8340
|
-
if (!existingMarkets.includes(fullName)) {
|
|
8341
|
-
assetToMarkets.set(displayName, [
|
|
8342
|
-
...existingMarkets,
|
|
8343
|
-
fullName,
|
|
8344
|
-
]);
|
|
8345
|
-
}
|
|
8346
|
-
}
|
|
8347
|
-
const assetWithMeta = {
|
|
8348
|
-
...asset,
|
|
8349
|
-
name: displayName,
|
|
8350
|
-
marketPrefix: prefix,
|
|
8351
|
-
collateralToken,
|
|
8352
|
-
};
|
|
8353
|
-
// Group by market prefix
|
|
8354
|
-
const allList = allAssetsByPrefix.get(prefix) || [];
|
|
8355
|
-
allList.push(assetWithMeta);
|
|
8356
|
-
allAssetsByPrefix.set(prefix, allList);
|
|
8357
|
-
if (!FILTERED_PREFIXES.includes(prefix)) {
|
|
8358
|
-
const cleanedList = assetsByPrefix.get(prefix) || [];
|
|
8359
|
-
cleanedList.push(assetWithMeta);
|
|
8360
|
-
assetsByPrefix.set(prefix, cleanedList);
|
|
8361
|
-
}
|
|
8362
|
-
}
|
|
8363
|
-
else {
|
|
8364
|
-
// Default market asset (no prefix)
|
|
8365
|
-
const assetWithMeta = {
|
|
8366
|
-
...asset,
|
|
8367
|
-
collateralToken,
|
|
8368
|
-
};
|
|
8369
|
-
// Add to default market group ("")
|
|
8370
|
-
const defaultList = assetsByPrefix.get('') || [];
|
|
8371
|
-
defaultList.push(assetWithMeta);
|
|
8372
|
-
assetsByPrefix.set('', defaultList);
|
|
8373
|
-
const allDefaultList = allAssetsByPrefix.get('') || [];
|
|
8374
|
-
allDefaultList.push(assetWithMeta);
|
|
8375
|
-
allAssetsByPrefix.set('', allDefaultList);
|
|
8376
|
-
}
|
|
8377
|
-
});
|
|
8378
|
-
});
|
|
8379
|
-
// Flatten in consistent order: default market first, then HIP3 markets alphabetically
|
|
8380
|
-
// This ensures both REST API and WebSocket data align properly
|
|
8381
|
-
const cleanedPrefixes = Array.from(assetsByPrefix.keys()).sort((a, b) => {
|
|
8382
|
-
// Empty prefix (default market) always comes first
|
|
8383
|
-
if (a === '' && b !== '')
|
|
8384
|
-
return -1;
|
|
8385
|
-
if (a !== '' && b === '')
|
|
8386
|
-
return 1;
|
|
8387
|
-
// HIP3 markets sorted alphabetically
|
|
8388
|
-
return a.localeCompare(b);
|
|
8389
|
-
});
|
|
8390
|
-
const allPrefixes = Array.from(allAssetsByPrefix.keys()).sort((a, b) => {
|
|
8391
|
-
if (a === '' && b !== '')
|
|
8392
|
-
return -1;
|
|
8393
|
-
if (a !== '' && b === '')
|
|
8394
|
-
return 1;
|
|
8395
|
-
return a.localeCompare(b);
|
|
8396
|
-
});
|
|
8397
|
-
const cleanedPerpMetas = [];
|
|
8398
|
-
const allPerpMetas = [];
|
|
8399
|
-
cleanedPrefixes.forEach((prefix) => {
|
|
8400
|
-
const assets = assetsByPrefix.get(prefix) || [];
|
|
8401
|
-
cleanedPerpMetas.push(...assets);
|
|
8402
|
-
});
|
|
8403
|
-
allPrefixes.forEach((prefix) => {
|
|
8404
|
-
const assets = allAssetsByPrefix.get(prefix) || [];
|
|
8405
|
-
allPerpMetas.push(...assets);
|
|
7382
|
+
// Only show HL and XYZ for now as other are using USDH collateral and need more work
|
|
7383
|
+
const aggregatedPerpMetas = res.data
|
|
7384
|
+
.slice(0, 2)
|
|
7385
|
+
.flatMap((item) => item.universe);
|
|
7386
|
+
const hip3Map = new Map();
|
|
7387
|
+
const displayToFull = new Map();
|
|
7388
|
+
const cleanedPerpMetas = aggregatedPerpMetas.map((asset) => {
|
|
7389
|
+
var _a;
|
|
7390
|
+
const [maybePrefix, maybeMarket] = asset.name.split(":");
|
|
7391
|
+
if (maybeMarket) {
|
|
7392
|
+
const prefix = maybePrefix.toLowerCase();
|
|
7393
|
+
const market = maybeMarket;
|
|
7394
|
+
const existing = (_a = hip3Map.get(prefix)) !== null && _a !== void 0 ? _a : [];
|
|
7395
|
+
hip3Map.set(prefix, [...existing, market]);
|
|
7396
|
+
displayToFull.set(market, `${prefix}:${market}`);
|
|
7397
|
+
return { ...asset, name: market };
|
|
7398
|
+
}
|
|
7399
|
+
return asset;
|
|
8406
7400
|
});
|
|
8407
|
-
|
|
8408
|
-
setHip3MarketPrefixes(marketPrefixes);
|
|
7401
|
+
setHip3DisplayToFull(displayToFull);
|
|
8409
7402
|
setPerpMetaAssets(cleanedPerpMetas);
|
|
8410
|
-
setAllPerpMetaAssets(allPerpMetas);
|
|
8411
7403
|
})
|
|
8412
7404
|
.catch(() => { });
|
|
8413
7405
|
}
|
|
8414
|
-
}, [
|
|
8415
|
-
|
|
8416
|
-
setPerpMetaAssets,
|
|
8417
|
-
setAllPerpMetaAssets,
|
|
8418
|
-
setHip3Assets,
|
|
8419
|
-
setHip3MarketPrefixes,
|
|
8420
|
-
]);
|
|
7406
|
+
}, [perpsMetaAssets, setPerpMetaAssets, setHip3DisplayToFull]);
|
|
7407
|
+
// Auth methods now sourced from useAuth hook
|
|
8421
7408
|
useAutoSyncFills({
|
|
8422
7409
|
baseUrl: apiBaseUrl,
|
|
8423
7410
|
address,
|
|
@@ -8439,8 +7426,6 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearpro
|
|
|
8439
7426
|
}), [
|
|
8440
7427
|
apiBaseUrl,
|
|
8441
7428
|
wsUrl,
|
|
8442
|
-
address,
|
|
8443
|
-
setAddress,
|
|
8444
7429
|
isConnected,
|
|
8445
7430
|
lastError,
|
|
8446
7431
|
nativeIsConnected,
|
|
@@ -8455,7 +7440,7 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearpro
|
|
|
8455
7440
|
function usePearHyperliquid() {
|
|
8456
7441
|
const ctx = useContext(PearHyperliquidContext);
|
|
8457
7442
|
if (!ctx)
|
|
8458
|
-
throw new Error(
|
|
7443
|
+
throw new Error("usePearHyperliquid must be used within a PearHyperliquidProvider");
|
|
8459
7444
|
return ctx;
|
|
8460
7445
|
}
|
|
8461
7446
|
|
|
@@ -8546,4 +7531,4 @@ function mapCandleIntervalToTradingViewInterval(interval) {
|
|
|
8546
7531
|
}
|
|
8547
7532
|
}
|
|
8548
7533
|
|
|
8549
|
-
export { AccountSummaryCalculator, ConflictDetector, MAX_ASSETS_PER_LEG, MINIMUM_ASSET_USD_VALUE, MaxAssetsPerLegError, MinimumPositionSizeError, PearHyperliquidProvider, TokenMetadataExtractor, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition,
|
|
7534
|
+
export { AccountSummaryCalculator, ConflictDetector, MAX_ASSETS_PER_LEG, MINIMUM_ASSET_USD_VALUE, MaxAssetsPerLegError, MinimumPositionSizeError, PearHyperliquidProvider, TokenMetadataExtractor, adjustAdvancePosition, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, getCompleteTimestamps, getPortfolio, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateLeverage, 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, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
|