@pear-protocol/hyperliquid-sdk 0.0.73-beta.1 → 0.0.73
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 +41 -0
- package/dist/clients/positions.d.ts +2 -2
- package/dist/clients/watchlist.d.ts +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useAllUserBalances.d.ts +9 -0
- package/dist/hooks/useAuth.d.ts +0 -2
- package/dist/hooks/useMarketData.d.ts +9 -7
- package/dist/hooks/useSpotOrder.d.ts +13 -0
- package/dist/hooks/useTrading.d.ts +0 -3
- package/dist/hooks/useWebData.d.ts +21 -3
- package/dist/index.d.ts +218 -42
- package/dist/index.js +1316 -261
- package/dist/provider.d.ts +1 -1
- package/dist/store/hyperliquidDataStore.d.ts +9 -3
- package/dist/store/userDataStore.d.ts +3 -3
- package/dist/types.d.ts +74 -20
- package/dist/utils/symbol-translator.d.ts +32 -3
- package/dist/utils/token-metadata-extractor.d.ts +9 -5
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -55,7 +55,6 @@ const useUserData = create((set) => ({
|
|
|
55
55
|
accessToken: null,
|
|
56
56
|
refreshToken: null,
|
|
57
57
|
isAuthenticated: false,
|
|
58
|
-
isReady: false,
|
|
59
58
|
address: null,
|
|
60
59
|
tradeHistories: null,
|
|
61
60
|
rawOpenPositions: null,
|
|
@@ -64,38 +63,40 @@ const useUserData = create((set) => ({
|
|
|
64
63
|
twapDetails: null,
|
|
65
64
|
notifications: null,
|
|
66
65
|
userExtraAgents: null,
|
|
66
|
+
spotState: null,
|
|
67
67
|
setAccessToken: (token) => set({ accessToken: token }),
|
|
68
68
|
setRefreshToken: (token) => set({ refreshToken: token }),
|
|
69
69
|
setIsAuthenticated: (value) => set({ isAuthenticated: value }),
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
},
|
|
70
|
+
setAddress: (address) => set(() => {
|
|
71
|
+
if (typeof window !== 'undefined') {
|
|
72
|
+
if (address) {
|
|
73
|
+
window.localStorage.setItem('address', address);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
window.localStorage.removeItem('address');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { address };
|
|
80
|
+
}),
|
|
81
81
|
setTradeHistories: (value) => set({ tradeHistories: value }),
|
|
82
82
|
setRawOpenPositions: (value) => set({ rawOpenPositions: value }),
|
|
83
83
|
setOpenOrders: (value) => set({ openOrders: value }),
|
|
84
84
|
setAccountSummary: (value) => set({ accountSummary: value }),
|
|
85
85
|
setTwapDetails: (value) => set({ twapDetails: value }),
|
|
86
86
|
setNotifications: (value) => set({ notifications: value }),
|
|
87
|
+
setSpotState: (value) => set({ spotState: value }),
|
|
87
88
|
clean: () => set({
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// address: null,
|
|
89
|
+
accessToken: null,
|
|
90
|
+
refreshToken: null,
|
|
91
|
+
isAuthenticated: false,
|
|
92
|
+
address: null,
|
|
93
93
|
tradeHistories: null,
|
|
94
94
|
rawOpenPositions: null,
|
|
95
95
|
openOrders: null,
|
|
96
96
|
accountSummary: null,
|
|
97
97
|
twapDetails: null,
|
|
98
98
|
notifications: null,
|
|
99
|
+
spotState: null,
|
|
99
100
|
}),
|
|
100
101
|
setUserExtraAgents: (value) => set({ userExtraAgents: value }),
|
|
101
102
|
}));
|
|
@@ -113,18 +114,71 @@ const useMarketData = create((set) => ({
|
|
|
113
114
|
* Convert a full/prefixed symbol (e.g., "xyz:XYZ100") to a display symbol (e.g., "XYZ100").
|
|
114
115
|
*/
|
|
115
116
|
function toDisplaySymbol(symbol) {
|
|
116
|
-
const parts = symbol.split(
|
|
117
|
+
const parts = symbol.split(':');
|
|
117
118
|
return parts.length > 1 ? parts.slice(-1)[0] : symbol;
|
|
118
119
|
}
|
|
119
120
|
/**
|
|
120
121
|
* Convert a display symbol back to backend form using a provided map.
|
|
121
122
|
* If mapping is missing, returns the original symbol.
|
|
122
|
-
*
|
|
123
|
-
* @param
|
|
123
|
+
* For multi-market assets, returns the first available market.
|
|
124
|
+
* @param displaySymbol e.g., "TSLA"
|
|
125
|
+
* @param hip3Assets map of display -> all full market names (e.g., "TSLA" -> ["xyz:TSLA", "flx:TSLA"])
|
|
126
|
+
*/
|
|
127
|
+
function toBackendSymbol(displaySymbol, hip3Assets) {
|
|
128
|
+
const markets = hip3Assets.get(displaySymbol);
|
|
129
|
+
// Return first market if available, otherwise return original symbol
|
|
130
|
+
return markets && markets.length > 0 ? markets[0] : displaySymbol;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Convert a display symbol to backend form for a specific market prefix.
|
|
134
|
+
* This is useful when an asset is available on multiple markets (e.g., xyz:TSLA and flx:TSLA).
|
|
135
|
+
* @param displaySymbol e.g., "TSLA"
|
|
136
|
+
* @param marketPrefix e.g., "xyz" or "flx"
|
|
137
|
+
* @param hip3Assets map of display -> all full market names
|
|
138
|
+
* @returns Full market name if found, null if prefix not specified for multi-market asset, otherwise displaySymbol with prefix
|
|
139
|
+
*/
|
|
140
|
+
function toBackendSymbolWithMarket(displaySymbol, marketPrefix, hip3Assets) {
|
|
141
|
+
const availableMarkets = hip3Assets.get(displaySymbol);
|
|
142
|
+
if (!availableMarkets || availableMarkets.length === 0) {
|
|
143
|
+
// Not a HIP-3 asset, return as-is or with prefix if provided
|
|
144
|
+
return marketPrefix ? `${marketPrefix}:${displaySymbol}` : displaySymbol;
|
|
145
|
+
}
|
|
146
|
+
if (marketPrefix) {
|
|
147
|
+
// Find the market with the specified prefix
|
|
148
|
+
const targetMarket = availableMarkets.find((market) => market.toLowerCase().startsWith(`${marketPrefix.toLowerCase()}:`));
|
|
149
|
+
if (targetMarket) {
|
|
150
|
+
return targetMarket;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// No prefix specified or not found, return null to force explicit market selection
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get all available markets for a display symbol.
|
|
158
|
+
* @param displaySymbol e.g., "TSLA"
|
|
159
|
+
* @param hip3Assets map of display -> all full market names
|
|
160
|
+
* @returns Array of full market names, e.g., ["xyz:TSLA", "flx:TSLA"]
|
|
124
161
|
*/
|
|
125
|
-
function
|
|
162
|
+
function getAvailableMarkets(displaySymbol, hip3Assets) {
|
|
126
163
|
var _a;
|
|
127
|
-
return (_a =
|
|
164
|
+
return (_a = hip3Assets.get(displaySymbol)) !== null && _a !== void 0 ? _a : [];
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Extract the market prefix from a full market name.
|
|
168
|
+
* @param fullSymbol e.g., "xyz:TSLA"
|
|
169
|
+
* @returns The prefix (e.g., "xyz") or undefined if no prefix
|
|
170
|
+
*/
|
|
171
|
+
function getMarketPrefix(fullSymbol) {
|
|
172
|
+
const parts = fullSymbol.split(':');
|
|
173
|
+
return parts.length > 1 ? parts[0] : undefined;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Check if a symbol is a HIP-3 market (has a prefix).
|
|
177
|
+
* @param symbol e.g., "xyz:TSLA" or "TSLA"
|
|
178
|
+
* @returns true if the symbol has a market prefix
|
|
179
|
+
*/
|
|
180
|
+
function isHip3Market(symbol) {
|
|
181
|
+
return symbol.includes(':');
|
|
128
182
|
}
|
|
129
183
|
|
|
130
184
|
const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
@@ -141,7 +195,8 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
141
195
|
try {
|
|
142
196
|
const message = JSON.parse(event.data);
|
|
143
197
|
// Handle subscription responses (only if they don't have channel data)
|
|
144
|
-
if (('success' in message || 'error' in message) &&
|
|
198
|
+
if (('success' in message || 'error' in message) &&
|
|
199
|
+
!('channel' in message)) {
|
|
145
200
|
if (message.error) {
|
|
146
201
|
setLastError(message.error);
|
|
147
202
|
}
|
|
@@ -160,12 +215,21 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
160
215
|
switch (dataMessage.channel) {
|
|
161
216
|
case 'trade-histories':
|
|
162
217
|
{
|
|
218
|
+
const mapAsset = (a) => {
|
|
219
|
+
var _a, _b;
|
|
220
|
+
const extractedPrefix = getMarketPrefix(a.coin);
|
|
221
|
+
return {
|
|
222
|
+
...a,
|
|
223
|
+
coin: toDisplaySymbol(a.coin),
|
|
224
|
+
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
225
|
+
};
|
|
226
|
+
};
|
|
163
227
|
const list = dataMessage.data.map((item) => {
|
|
164
228
|
var _a, _b;
|
|
165
229
|
return ({
|
|
166
230
|
...item,
|
|
167
|
-
closedLongAssets: item.closedLongAssets.map(
|
|
168
|
-
closedShortAssets: item.closedShortAssets.map(
|
|
231
|
+
closedLongAssets: item.closedLongAssets.map(mapAsset),
|
|
232
|
+
closedShortAssets: item.closedShortAssets.map(mapAsset),
|
|
169
233
|
positionLongAssets: (_a = item.positionLongAssets) === null || _a === void 0 ? void 0 : _a.map((a) => toDisplaySymbol(a)),
|
|
170
234
|
positionShortAssets: (_b = item.positionShortAssets) === null || _b === void 0 ? void 0 : _b.map((a) => toDisplaySymbol(a)),
|
|
171
235
|
});
|
|
@@ -175,10 +239,19 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
175
239
|
break;
|
|
176
240
|
case 'open-positions':
|
|
177
241
|
{
|
|
242
|
+
const enrichAsset = (a) => {
|
|
243
|
+
var _a, _b;
|
|
244
|
+
const extractedPrefix = getMarketPrefix(a.coin);
|
|
245
|
+
return {
|
|
246
|
+
...a,
|
|
247
|
+
coin: toDisplaySymbol(a.coin),
|
|
248
|
+
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
249
|
+
};
|
|
250
|
+
};
|
|
178
251
|
const list = dataMessage.data.map((pos) => ({
|
|
179
252
|
...pos,
|
|
180
|
-
longAssets: pos.longAssets.map(
|
|
181
|
-
shortAssets: pos.shortAssets.map(
|
|
253
|
+
longAssets: pos.longAssets.map(enrichAsset),
|
|
254
|
+
shortAssets: pos.shortAssets.map(enrichAsset),
|
|
182
255
|
}));
|
|
183
256
|
setRawOpenPositions(list);
|
|
184
257
|
}
|
|
@@ -187,8 +260,14 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
187
260
|
{
|
|
188
261
|
const list = dataMessage.data.map((order) => ({
|
|
189
262
|
...order,
|
|
190
|
-
longAssets: order.longAssets.map((a) => ({
|
|
191
|
-
|
|
263
|
+
longAssets: order.longAssets.map((a) => ({
|
|
264
|
+
...a,
|
|
265
|
+
asset: toDisplaySymbol(a.asset),
|
|
266
|
+
})),
|
|
267
|
+
shortAssets: order.shortAssets.map((a) => ({
|
|
268
|
+
...a,
|
|
269
|
+
asset: toDisplaySymbol(a.asset),
|
|
270
|
+
})),
|
|
192
271
|
}));
|
|
193
272
|
setOpenOrders(list);
|
|
194
273
|
}
|
|
@@ -198,10 +277,20 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
198
277
|
break;
|
|
199
278
|
case 'twap-details':
|
|
200
279
|
{
|
|
280
|
+
const mapTwapAsset = (a) => {
|
|
281
|
+
var _a, _b, _c;
|
|
282
|
+
const extractedPrefix = getMarketPrefix(a.asset);
|
|
283
|
+
return {
|
|
284
|
+
...a,
|
|
285
|
+
asset: toDisplaySymbol(a.asset),
|
|
286
|
+
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
287
|
+
collateralToken: (_c = a.collateralToken) !== null && _c !== void 0 ? _c : undefined,
|
|
288
|
+
};
|
|
289
|
+
};
|
|
201
290
|
const list = dataMessage.data.map((twap) => ({
|
|
202
291
|
...twap,
|
|
203
|
-
longAssets: twap.longAssets.map(
|
|
204
|
-
shortAssets: twap.shortAssets.map(
|
|
292
|
+
longAssets: twap.longAssets.map(mapTwapAsset),
|
|
293
|
+
shortAssets: twap.shortAssets.map(mapTwapAsset),
|
|
205
294
|
}));
|
|
206
295
|
setTwapDetails(list);
|
|
207
296
|
}
|
|
@@ -214,8 +303,14 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
214
303
|
const md = dataMessage.data;
|
|
215
304
|
const mapGroup = (g) => ({
|
|
216
305
|
...g,
|
|
217
|
-
longAssets: g.longAssets.map((a) => ({
|
|
218
|
-
|
|
306
|
+
longAssets: g.longAssets.map((a) => ({
|
|
307
|
+
...a,
|
|
308
|
+
asset: toDisplaySymbol(a.asset),
|
|
309
|
+
})),
|
|
310
|
+
shortAssets: g.shortAssets.map((a) => ({
|
|
311
|
+
...a,
|
|
312
|
+
asset: toDisplaySymbol(a.asset),
|
|
313
|
+
})),
|
|
219
314
|
});
|
|
220
315
|
const mapped = {
|
|
221
316
|
active: md.active.map(mapGroup),
|
|
@@ -233,7 +328,15 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
233
328
|
catch (error) {
|
|
234
329
|
setLastError(`Failed to parse message: ${error instanceof Error ? error.message : String(error)}`);
|
|
235
330
|
}
|
|
236
|
-
}, [
|
|
331
|
+
}, [
|
|
332
|
+
setTradeHistories,
|
|
333
|
+
setRawOpenPositions,
|
|
334
|
+
setOpenOrders,
|
|
335
|
+
setAccountSummary,
|
|
336
|
+
setTwapDetails,
|
|
337
|
+
setNotifications,
|
|
338
|
+
setMarketData,
|
|
339
|
+
]);
|
|
237
340
|
const connect = useCallback(() => {
|
|
238
341
|
if (!enabled || !wsUrl)
|
|
239
342
|
return;
|
|
@@ -302,7 +405,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
302
405
|
'open-orders',
|
|
303
406
|
'twap-details',
|
|
304
407
|
'fills-checkpoint',
|
|
305
|
-
'notifications'
|
|
408
|
+
'notifications',
|
|
306
409
|
];
|
|
307
410
|
const globalChannels = ['market-data'];
|
|
308
411
|
if (address && address !== lastSubscribedAddress) {
|
|
@@ -311,14 +414,14 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
311
414
|
sendMessage(JSON.stringify({
|
|
312
415
|
action: 'unsubscribe',
|
|
313
416
|
address: lastSubscribedAddress,
|
|
314
|
-
channels: addressSpecificChannels
|
|
417
|
+
channels: addressSpecificChannels,
|
|
315
418
|
}));
|
|
316
419
|
}
|
|
317
420
|
// Subscribe to all channels (global + address-specific)
|
|
318
421
|
sendMessage(JSON.stringify({
|
|
319
422
|
action: 'subscribe',
|
|
320
423
|
address: address,
|
|
321
|
-
channels: [...globalChannels, ...addressSpecificChannels]
|
|
424
|
+
channels: [...globalChannels, ...addressSpecificChannels],
|
|
322
425
|
}));
|
|
323
426
|
setLastSubscribedAddress(address);
|
|
324
427
|
setLastError(null);
|
|
@@ -328,7 +431,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
328
431
|
sendMessage(JSON.stringify({
|
|
329
432
|
action: 'unsubscribe',
|
|
330
433
|
address: lastSubscribedAddress,
|
|
331
|
-
channels: addressSpecificChannels
|
|
434
|
+
channels: addressSpecificChannels,
|
|
332
435
|
}));
|
|
333
436
|
setLastSubscribedAddress(null);
|
|
334
437
|
}
|
|
@@ -336,7 +439,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
336
439
|
// If no address but connected, subscribe to global channels only
|
|
337
440
|
sendMessage(JSON.stringify({
|
|
338
441
|
action: 'subscribe',
|
|
339
|
-
channels: globalChannels
|
|
442
|
+
channels: globalChannels,
|
|
340
443
|
}));
|
|
341
444
|
}
|
|
342
445
|
}, [isConnected, address, lastSubscribedAddress, sendMessage]);
|
|
@@ -359,11 +462,14 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
359
462
|
finalAssetContexts: null,
|
|
360
463
|
finalAtOICaps: null,
|
|
361
464
|
aggregatedClearingHouseState: null,
|
|
465
|
+
rawClearinghouseStates: null,
|
|
362
466
|
perpMetaAssets: null,
|
|
363
|
-
|
|
467
|
+
allPerpMetaAssets: null,
|
|
468
|
+
hip3Assets: new Map(),
|
|
469
|
+
hip3MarketPrefixes: new Map(),
|
|
364
470
|
setAllMids: (value) => set({ allMids: value }),
|
|
365
471
|
setActiveAssetData: (value) => set((state) => ({
|
|
366
|
-
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value
|
|
472
|
+
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value,
|
|
367
473
|
})),
|
|
368
474
|
deleteActiveAssetData: (key) => {
|
|
369
475
|
set((state) => {
|
|
@@ -398,13 +504,16 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
398
504
|
activeAssetData: {
|
|
399
505
|
...state.activeAssetData,
|
|
400
506
|
[key]: value,
|
|
401
|
-
}
|
|
507
|
+
},
|
|
402
508
|
})),
|
|
403
509
|
setFinalAssetContexts: (value) => set({ finalAssetContexts: value }),
|
|
404
510
|
setFinalAtOICaps: (value) => set({ finalAtOICaps: value }),
|
|
405
511
|
setAggregatedClearingHouseState: (value) => set({ aggregatedClearingHouseState: value }),
|
|
512
|
+
setRawClearinghouseStates: (value) => set({ rawClearinghouseStates: value }),
|
|
406
513
|
setPerpMetaAssets: (value) => set({ perpMetaAssets: value }),
|
|
407
|
-
|
|
514
|
+
setAllPerpMetaAssets: (value) => set({ allPerpMetaAssets: value }),
|
|
515
|
+
setHip3Assets: (value) => set({ hip3Assets: value }),
|
|
516
|
+
setHip3MarketPrefixes: (value) => set({ hip3MarketPrefixes: value }),
|
|
408
517
|
}));
|
|
409
518
|
|
|
410
519
|
/**
|
|
@@ -667,7 +776,8 @@ const useUserSelection$1 = create((set, get) => ({
|
|
|
667
776
|
}));
|
|
668
777
|
|
|
669
778
|
const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
670
|
-
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState, } = useHyperliquidData();
|
|
779
|
+
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState, setRawClearinghouseStates, } = useHyperliquidData();
|
|
780
|
+
const { setSpotState } = useUserData();
|
|
671
781
|
const { candleInterval } = useUserSelection$1();
|
|
672
782
|
const longTokens = useUserSelection$1((s) => s.longTokens);
|
|
673
783
|
const shortTokens = useUserSelection$1((s) => s.shortTokens);
|
|
@@ -686,9 +796,9 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
686
796
|
try {
|
|
687
797
|
const message = JSON.parse(event.data);
|
|
688
798
|
// Handle subscription responses
|
|
689
|
-
if (
|
|
799
|
+
if ('success' in message || 'error' in message) {
|
|
690
800
|
if (message.error) {
|
|
691
|
-
console.error(
|
|
801
|
+
console.error('[HyperLiquid WS] Subscription error:', message.error);
|
|
692
802
|
setLastError(message.error);
|
|
693
803
|
}
|
|
694
804
|
else {
|
|
@@ -697,30 +807,44 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
697
807
|
return;
|
|
698
808
|
}
|
|
699
809
|
// Handle channel data messages
|
|
700
|
-
if (
|
|
810
|
+
if ('channel' in message && 'data' in message) {
|
|
701
811
|
const response = message;
|
|
702
812
|
switch (response.channel) {
|
|
703
|
-
case
|
|
813
|
+
case 'webData3':
|
|
704
814
|
const webData3 = response.data;
|
|
705
815
|
// finalAssetContexts now sourced from allDexsAssetCtxs channel
|
|
706
816
|
const finalAtOICaps = webData3.perpDexStates.flatMap((dex) => dex.perpsAtOpenInterestCap);
|
|
707
817
|
setFinalAtOICaps(finalAtOICaps);
|
|
708
818
|
break;
|
|
709
|
-
case
|
|
819
|
+
case 'allDexsAssetCtxs':
|
|
710
820
|
{
|
|
711
821
|
const data = response.data;
|
|
712
|
-
|
|
822
|
+
// Filter out hyna to match perpMetaAssets filtering
|
|
823
|
+
const FILTERED_DEX_PREFIXES = ['hyna'];
|
|
824
|
+
const filtered = (data.ctxs || [])
|
|
825
|
+
.filter(([prefix]) => !FILTERED_DEX_PREFIXES.includes((prefix || '').toLowerCase()))
|
|
826
|
+
.sort((a, b) => {
|
|
827
|
+
// Sort to match perpMetaAssets order: default market first, then alphabetically
|
|
828
|
+
const prefixA = a[0] || '';
|
|
829
|
+
const prefixB = b[0] || '';
|
|
830
|
+
if (prefixA === '' && prefixB !== '')
|
|
831
|
+
return -1;
|
|
832
|
+
if (prefixA !== '' && prefixB === '')
|
|
833
|
+
return 1;
|
|
834
|
+
return prefixA.localeCompare(prefixB);
|
|
835
|
+
});
|
|
836
|
+
const finalAssetContexts = filtered.flatMap(([, ctxs]) => ctxs || []);
|
|
713
837
|
setFinalAssetContexts(finalAssetContexts);
|
|
714
838
|
}
|
|
715
839
|
break;
|
|
716
|
-
case
|
|
840
|
+
case 'allDexsClearinghouseState':
|
|
717
841
|
{
|
|
718
842
|
const data = response.data;
|
|
719
843
|
const states = (data.clearinghouseStates || [])
|
|
720
844
|
.map(([, s]) => s)
|
|
721
845
|
.filter(Boolean);
|
|
722
|
-
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v ||
|
|
723
|
-
const toStr = (n) => Number.isFinite(n) ? n.toString() :
|
|
846
|
+
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || '0') || 0), 0);
|
|
847
|
+
const toStr = (n) => Number.isFinite(n) ? n.toString() : '0';
|
|
724
848
|
const assetPositions = states.flatMap((s) => s.assetPositions || []);
|
|
725
849
|
const crossMaintenanceMarginUsed = toStr(sum(states.map((s) => s.crossMaintenanceMarginUsed)));
|
|
726
850
|
const crossMarginSummary = {
|
|
@@ -746,22 +870,41 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
746
870
|
withdrawable,
|
|
747
871
|
};
|
|
748
872
|
setAggregatedClearingHouseState(aggregatedClearingHouseState);
|
|
873
|
+
setRawClearinghouseStates(data.clearinghouseStates || null);
|
|
749
874
|
}
|
|
750
875
|
break;
|
|
751
|
-
case
|
|
876
|
+
case 'allMids':
|
|
752
877
|
{
|
|
753
878
|
const data = response.data;
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
879
|
+
// Keep BOTH normalized prefixed keys AND display symbol keys
|
|
880
|
+
// This ensures xyz:TSLA and flx:TSLA are stored separately,
|
|
881
|
+
// while also maintaining backward compatibility with non-prefixed lookups
|
|
882
|
+
const mids = {};
|
|
883
|
+
Object.entries(data.mids || {}).forEach(([k, v]) => {
|
|
884
|
+
// Normalize prefixed keys to lowercase prefix (e.g., "XYZ:TSLA" -> "xyz:TSLA")
|
|
885
|
+
// This matches how we look up tokens in the SDK
|
|
886
|
+
let normalizedKey = k;
|
|
887
|
+
if (k.includes(':')) {
|
|
888
|
+
const [prefix, ...rest] = k.split(':');
|
|
889
|
+
normalizedKey = `${prefix.toLowerCase()}:${rest.join(':')}`;
|
|
890
|
+
}
|
|
891
|
+
// Store with normalized key
|
|
892
|
+
mids[normalizedKey] = v;
|
|
893
|
+
// Also store with original key for backward compatibility
|
|
894
|
+
if (k !== normalizedKey) {
|
|
895
|
+
mids[k] = v;
|
|
896
|
+
}
|
|
897
|
+
// Also store with display symbol for backward compatibility
|
|
898
|
+
const displayKey = toDisplaySymbol(k);
|
|
899
|
+
// Only set display key if it doesn't already exist (avoid overwriting market-specific prices)
|
|
900
|
+
if (!(displayKey in mids)) {
|
|
901
|
+
mids[displayKey] = v;
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
setAllMids({ mids });
|
|
762
905
|
}
|
|
763
906
|
break;
|
|
764
|
-
case
|
|
907
|
+
case 'activeAssetData':
|
|
765
908
|
{
|
|
766
909
|
const assetData = response.data;
|
|
767
910
|
const symbol = toDisplaySymbol(assetData.coin);
|
|
@@ -772,14 +915,22 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
772
915
|
upsertActiveAssetData(symbol, normalized);
|
|
773
916
|
}
|
|
774
917
|
break;
|
|
775
|
-
case
|
|
918
|
+
case 'candle':
|
|
776
919
|
{
|
|
777
920
|
const candleDataItem = response.data;
|
|
778
|
-
const symbol = toDisplaySymbol(candleDataItem.s ||
|
|
921
|
+
const symbol = toDisplaySymbol(candleDataItem.s || '');
|
|
779
922
|
const normalized = { ...candleDataItem, s: symbol };
|
|
780
923
|
addCandleData(symbol, normalized);
|
|
781
924
|
}
|
|
782
925
|
break;
|
|
926
|
+
case 'spotState':
|
|
927
|
+
{
|
|
928
|
+
const spotStateData = response.data;
|
|
929
|
+
if (spotStateData === null || spotStateData === void 0 ? void 0 : spotStateData.spotState) {
|
|
930
|
+
setSpotState(spotStateData.spotState);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
break;
|
|
783
934
|
default:
|
|
784
935
|
console.warn(`[HyperLiquid WS] Unknown channel: ${response.channel}`);
|
|
785
936
|
}
|
|
@@ -787,7 +938,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
787
938
|
}
|
|
788
939
|
catch (error) {
|
|
789
940
|
const errorMessage = `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`;
|
|
790
|
-
console.error(
|
|
941
|
+
console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', event.data);
|
|
791
942
|
setLastError(errorMessage);
|
|
792
943
|
}
|
|
793
944
|
}, [
|
|
@@ -797,6 +948,8 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
797
948
|
setFinalAssetContexts,
|
|
798
949
|
setFinalAtOICaps,
|
|
799
950
|
setAggregatedClearingHouseState,
|
|
951
|
+
setRawClearinghouseStates,
|
|
952
|
+
setSpotState,
|
|
800
953
|
]);
|
|
801
954
|
const connect = useCallback(() => {
|
|
802
955
|
if (!enabled)
|
|
@@ -827,7 +980,7 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
827
980
|
if (!manualCloseRef.current && reconnectAttemptsRef.current < 5) {
|
|
828
981
|
reconnectAttemptsRef.current += 1;
|
|
829
982
|
if (reconnectAttemptsRef.current === 5) {
|
|
830
|
-
console.error(
|
|
983
|
+
console.error('[HyperLiquid WS] Reconnection stopped after 5 attempts');
|
|
831
984
|
}
|
|
832
985
|
setTimeout(() => connect(), 3000);
|
|
833
986
|
}
|
|
@@ -895,6 +1048,17 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
895
1048
|
},
|
|
896
1049
|
};
|
|
897
1050
|
sendJsonMessage(unsubscribeMessage);
|
|
1051
|
+
// Unsubscribe from spotState for previous address
|
|
1052
|
+
if (subscribedAddress !== DEFAULT_ADDRESS) {
|
|
1053
|
+
const unsubscribeSpotState = {
|
|
1054
|
+
method: 'unsubscribe',
|
|
1055
|
+
subscription: {
|
|
1056
|
+
type: 'spotState',
|
|
1057
|
+
user: subscribedAddress,
|
|
1058
|
+
},
|
|
1059
|
+
};
|
|
1060
|
+
sendJsonMessage(unsubscribeSpotState);
|
|
1061
|
+
}
|
|
898
1062
|
const unsubscribeAllDexsClearinghouseState = {
|
|
899
1063
|
method: "unsubscribe",
|
|
900
1064
|
subscription: {
|
|
@@ -938,11 +1102,26 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
938
1102
|
sendJsonMessage(subscribeAllDexsClearinghouseState);
|
|
939
1103
|
sendJsonMessage(subscribeAllMids);
|
|
940
1104
|
sendJsonMessage(subscribeAllDexsAssetCtxs);
|
|
1105
|
+
// Subscribe to spotState for real-time spot balances (USDH, USDC, etc.)
|
|
1106
|
+
// Only subscribe if we have a real user address (not the default)
|
|
1107
|
+
if (userAddress !== DEFAULT_ADDRESS) {
|
|
1108
|
+
const subscribeSpotState = {
|
|
1109
|
+
method: 'subscribe',
|
|
1110
|
+
subscription: {
|
|
1111
|
+
type: 'spotState',
|
|
1112
|
+
user: userAddress,
|
|
1113
|
+
},
|
|
1114
|
+
};
|
|
1115
|
+
sendJsonMessage(subscribeSpotState);
|
|
1116
|
+
}
|
|
941
1117
|
setSubscribedAddress(userAddress);
|
|
942
1118
|
// Clear previous data when address changes
|
|
943
1119
|
if (subscribedAddress && subscribedAddress !== userAddress) {
|
|
944
1120
|
// clear aggregatedClearingHouseState
|
|
945
1121
|
setAggregatedClearingHouseState(null);
|
|
1122
|
+
setRawClearinghouseStates(null);
|
|
1123
|
+
// clear spotState
|
|
1124
|
+
setSpotState(null);
|
|
946
1125
|
}
|
|
947
1126
|
}, [
|
|
948
1127
|
isConnected,
|
|
@@ -950,6 +1129,8 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
|
950
1129
|
subscribedAddress,
|
|
951
1130
|
sendJsonMessage,
|
|
952
1131
|
setAggregatedClearingHouseState,
|
|
1132
|
+
setRawClearinghouseStates,
|
|
1133
|
+
setSpotState,
|
|
953
1134
|
]);
|
|
954
1135
|
// Handle token subscriptions for activeAssetData
|
|
955
1136
|
useEffect(() => {
|
|
@@ -1146,20 +1327,112 @@ const useAccountSummary = () => {
|
|
|
1146
1327
|
return { data: calculated, isLoading };
|
|
1147
1328
|
};
|
|
1148
1329
|
|
|
1330
|
+
function findAssetMeta$4(coinName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
1331
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
1332
|
+
if (!perpMetaAssets) {
|
|
1333
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
1334
|
+
}
|
|
1335
|
+
if (desiredCollateral) {
|
|
1336
|
+
const collateralMatch = perpMetaAssets.find((a) => a.name === coinName && a.collateralToken === desiredCollateral);
|
|
1337
|
+
if (collateralMatch) {
|
|
1338
|
+
return {
|
|
1339
|
+
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
1340
|
+
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
if (coinName.includes(':')) {
|
|
1345
|
+
const [prefix, symbol] = coinName.split(':');
|
|
1346
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
1347
|
+
var _a;
|
|
1348
|
+
return a.name === symbol &&
|
|
1349
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
1350
|
+
});
|
|
1351
|
+
if (exactMatch) {
|
|
1352
|
+
return {
|
|
1353
|
+
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
1354
|
+
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (knownPrefix) {
|
|
1359
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
1360
|
+
var _a;
|
|
1361
|
+
return a.name === coinName &&
|
|
1362
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
1363
|
+
});
|
|
1364
|
+
if (exactMatch) {
|
|
1365
|
+
return {
|
|
1366
|
+
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
1367
|
+
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
const exactMatch = perpMetaAssets.find((a) => a.name === coinName && !a.marketPrefix);
|
|
1372
|
+
if (exactMatch) {
|
|
1373
|
+
return {
|
|
1374
|
+
collateralToken: (_g = exactMatch.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
1375
|
+
marketPrefix: (_h = exactMatch.marketPrefix) !== null && _h !== void 0 ? _h : null,
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
const hip3Matches = perpMetaAssets.filter((a) => a.name === coinName && a.marketPrefix);
|
|
1379
|
+
if (hip3Matches.length > 0) {
|
|
1380
|
+
if (desiredCollateral) {
|
|
1381
|
+
const collateralMatch = hip3Matches.find((a) => a.collateralToken === desiredCollateral);
|
|
1382
|
+
if (collateralMatch) {
|
|
1383
|
+
return {
|
|
1384
|
+
collateralToken: (_j = collateralMatch.collateralToken) !== null && _j !== void 0 ? _j : 'USDC',
|
|
1385
|
+
marketPrefix: (_k = collateralMatch.marketPrefix) !== null && _k !== void 0 ? _k : null,
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
const usdHMatch = hip3Matches.find((a) => a.collateralToken === 'USDH');
|
|
1390
|
+
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Matches[0];
|
|
1391
|
+
return {
|
|
1392
|
+
collateralToken: (_l = chosen.collateralToken) !== null && _l !== void 0 ? _l : 'USDC',
|
|
1393
|
+
marketPrefix: (_m = chosen.marketPrefix) !== null && _m !== void 0 ? _m : null,
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
1397
|
+
}
|
|
1398
|
+
function enrichTradeHistoryAssets(assets, perpMetaAssets) {
|
|
1399
|
+
return assets.map((asset) => {
|
|
1400
|
+
var _a;
|
|
1401
|
+
if (asset.marketPrefix && asset.collateralToken) {
|
|
1402
|
+
return asset;
|
|
1403
|
+
}
|
|
1404
|
+
const meta = findAssetMeta$4(asset.coin, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
1405
|
+
return {
|
|
1406
|
+
...asset,
|
|
1407
|
+
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
1408
|
+
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
1409
|
+
};
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
function enrichTradeHistories(histories, perpMetaAssets) {
|
|
1413
|
+
return histories.map((history) => ({
|
|
1414
|
+
...history,
|
|
1415
|
+
closedLongAssets: enrichTradeHistoryAssets(history.closedLongAssets, perpMetaAssets),
|
|
1416
|
+
closedShortAssets: enrichTradeHistoryAssets(history.closedShortAssets, perpMetaAssets),
|
|
1417
|
+
}));
|
|
1418
|
+
}
|
|
1149
1419
|
const useTradeHistories = () => {
|
|
1150
1420
|
const context = useContext(PearHyperliquidContext);
|
|
1151
1421
|
if (!context) {
|
|
1152
1422
|
throw new Error('useTradeHistories must be used within a PearHyperliquidProvider');
|
|
1153
1423
|
}
|
|
1154
1424
|
const tradeHistories = useUserData((state) => state.tradeHistories);
|
|
1425
|
+
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
1155
1426
|
const isLoading = useMemo(() => {
|
|
1156
1427
|
return tradeHistories === null && context.isConnected;
|
|
1157
1428
|
}, [tradeHistories, context.isConnected]);
|
|
1158
|
-
|
|
1429
|
+
const enrichedTradeHistories = useMemo(() => {
|
|
1430
|
+
if (!tradeHistories)
|
|
1431
|
+
return null;
|
|
1432
|
+
return enrichTradeHistories(tradeHistories, allPerpMetaAssets);
|
|
1433
|
+
}, [tradeHistories, allPerpMetaAssets]);
|
|
1434
|
+
return { data: enrichedTradeHistories, isLoading };
|
|
1159
1435
|
};
|
|
1160
|
-
/**
|
|
1161
|
-
* Hook to access open orders with loading state
|
|
1162
|
-
*/
|
|
1163
1436
|
const useOpenOrders = () => {
|
|
1164
1437
|
const context = useContext(PearHyperliquidContext);
|
|
1165
1438
|
if (!context) {
|
|
@@ -1188,21 +1461,51 @@ const useWebData = () => {
|
|
|
1188
1461
|
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
1189
1462
|
const aggregatedClearinghouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
1190
1463
|
const finalAtOICaps = useHyperliquidData((state) => state.finalAtOICaps);
|
|
1191
|
-
const hip3Assets = useHyperliquidData((state) => state.
|
|
1464
|
+
const hip3Assets = useHyperliquidData((state) => state.hip3Assets);
|
|
1465
|
+
const hip3MarketPrefixes = useHyperliquidData((state) => state.hip3MarketPrefixes);
|
|
1192
1466
|
let marketDataBySymbol = {};
|
|
1193
1467
|
if (finalAssetContexts && perpMetaAssets) {
|
|
1194
1468
|
const result = {};
|
|
1469
|
+
// Build a map of display name -> asset context index (for unique display names)
|
|
1470
|
+
const displayNameToContextIndex = new Map();
|
|
1471
|
+
const seenNames = new Set();
|
|
1472
|
+
let contextIndex = 0;
|
|
1473
|
+
// First pass: map unique display names to their context index
|
|
1195
1474
|
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1196
1475
|
const name = perpMetaAssets[index].name;
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1476
|
+
if (!seenNames.has(name)) {
|
|
1477
|
+
seenNames.add(name);
|
|
1478
|
+
if (contextIndex < finalAssetContexts.length) {
|
|
1479
|
+
displayNameToContextIndex.set(name, contextIndex);
|
|
1480
|
+
contextIndex++;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
// Second pass: create nested entries for all market variants
|
|
1485
|
+
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1486
|
+
const universeAsset = perpMetaAssets[index];
|
|
1487
|
+
const displayName = universeAsset.name;
|
|
1488
|
+
const marketPrefix = universeAsset.marketPrefix;
|
|
1489
|
+
const ctxIndex = displayNameToContextIndex.get(displayName);
|
|
1490
|
+
if (ctxIndex !== undefined) {
|
|
1491
|
+
const assetContext = finalAssetContexts[ctxIndex];
|
|
1492
|
+
// Initialize the symbol entry if it doesn't exist
|
|
1493
|
+
if (!result[displayName]) {
|
|
1494
|
+
result[displayName] = {};
|
|
1495
|
+
}
|
|
1496
|
+
// Use marketPrefix as key for HIP-3 assets, "default" for regular assets
|
|
1497
|
+
const variantKey = marketPrefix || 'default';
|
|
1498
|
+
result[displayName][variantKey] = {
|
|
1499
|
+
asset: assetContext,
|
|
1500
|
+
universe: universeAsset,
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1201
1503
|
}
|
|
1202
1504
|
marketDataBySymbol = result;
|
|
1203
1505
|
}
|
|
1204
1506
|
return {
|
|
1205
1507
|
hip3Assets,
|
|
1508
|
+
hip3MarketPrefixes,
|
|
1206
1509
|
clearinghouseState: aggregatedClearinghouseState,
|
|
1207
1510
|
perpsAtOpenInterestCap: finalAtOICaps,
|
|
1208
1511
|
marketDataBySymbol,
|
|
@@ -1217,19 +1520,30 @@ const useWebData = () => {
|
|
|
1217
1520
|
class TokenMetadataExtractor {
|
|
1218
1521
|
/**
|
|
1219
1522
|
* Extracts comprehensive token metadata
|
|
1220
|
-
* @param symbol - Token symbol
|
|
1523
|
+
* @param symbol - Token symbol (base symbol without prefix, e.g., "TSLA")
|
|
1221
1524
|
* @param perpMetaAssets - Aggregated universe assets (flattened across dexes)
|
|
1222
1525
|
* @param finalAssetContexts - Aggregated asset contexts (flattened across dexes)
|
|
1223
1526
|
* @param allMids - AllMids data containing current prices
|
|
1224
1527
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1528
|
+
* @param marketPrefix - Optional market prefix (e.g., "xyz", "flx") for HIP3 multi-market assets
|
|
1225
1529
|
* @returns TokenMetadata or null if token not found
|
|
1226
1530
|
*/
|
|
1227
|
-
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
1531
|
+
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketPrefix) {
|
|
1228
1532
|
if (!perpMetaAssets || !finalAssetContexts || !allMids) {
|
|
1229
1533
|
return null;
|
|
1230
1534
|
}
|
|
1231
1535
|
// Find token index in aggregated universe
|
|
1232
|
-
|
|
1536
|
+
// For HIP3 assets, match both name AND marketPrefix
|
|
1537
|
+
const universeIndex = perpMetaAssets.findIndex((asset) => {
|
|
1538
|
+
if (asset.name !== symbol)
|
|
1539
|
+
return false;
|
|
1540
|
+
// If marketPrefix is specified, match it; otherwise match assets without prefix
|
|
1541
|
+
if (marketPrefix) {
|
|
1542
|
+
return asset.marketPrefix === marketPrefix;
|
|
1543
|
+
}
|
|
1544
|
+
// No prefix specified - match non-HIP3 asset (no marketPrefix) or first matching asset
|
|
1545
|
+
return !asset.marketPrefix;
|
|
1546
|
+
});
|
|
1233
1547
|
if (universeIndex === -1) {
|
|
1234
1548
|
return null;
|
|
1235
1549
|
}
|
|
@@ -1238,9 +1552,20 @@ class TokenMetadataExtractor {
|
|
|
1238
1552
|
if (!assetCtx) {
|
|
1239
1553
|
return null;
|
|
1240
1554
|
}
|
|
1241
|
-
// Get current price
|
|
1242
|
-
|
|
1243
|
-
const
|
|
1555
|
+
// Get current price - prefer assetCtx.midPx as it's already index-matched,
|
|
1556
|
+
// fall back to allMids lookup if midPx is null
|
|
1557
|
+
const prefixedKeyColon = marketPrefix ? `${marketPrefix}:${symbol}` : null;
|
|
1558
|
+
let currentPrice = 0;
|
|
1559
|
+
// Primary source: assetCtx.midPx (already properly indexed)
|
|
1560
|
+
if (assetCtx.midPx) {
|
|
1561
|
+
currentPrice = parseFloat(assetCtx.midPx);
|
|
1562
|
+
}
|
|
1563
|
+
// Fallback: allMids lookup with multiple key formats for HIP3 markets
|
|
1564
|
+
if (!currentPrice || isNaN(currentPrice)) {
|
|
1565
|
+
const currentPriceStr = (prefixedKeyColon && allMids.mids[prefixedKeyColon]) ||
|
|
1566
|
+
allMids.mids[symbol];
|
|
1567
|
+
currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
1568
|
+
}
|
|
1244
1569
|
// Get previous day price
|
|
1245
1570
|
const prevDayPrice = parseFloat(assetCtx.prevDayPx);
|
|
1246
1571
|
// Calculate 24h price change
|
|
@@ -1251,7 +1576,11 @@ class TokenMetadataExtractor {
|
|
|
1251
1576
|
const markPrice = parseFloat(assetCtx.markPx);
|
|
1252
1577
|
const oraclePrice = parseFloat(assetCtx.oraclePx);
|
|
1253
1578
|
// Extract leverage info from activeAssetData if available
|
|
1254
|
-
|
|
1579
|
+
// Try prefixed key first (e.g., "xyz:TSLA"), then fall back to plain symbol
|
|
1580
|
+
const activeDataKey = prefixedKeyColon && (activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[prefixedKeyColon])
|
|
1581
|
+
? prefixedKeyColon
|
|
1582
|
+
: symbol;
|
|
1583
|
+
const tokenActiveData = activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[activeDataKey];
|
|
1255
1584
|
const leverage = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.leverage;
|
|
1256
1585
|
const maxTradeSzs = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.maxTradeSzs;
|
|
1257
1586
|
const availableToTrade = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.availableToTrade;
|
|
@@ -1269,21 +1598,27 @@ class TokenMetadataExtractor {
|
|
|
1269
1598
|
leverage,
|
|
1270
1599
|
maxTradeSzs,
|
|
1271
1600
|
availableToTrade,
|
|
1601
|
+
collateralToken: universeAsset.collateralToken,
|
|
1272
1602
|
};
|
|
1273
1603
|
}
|
|
1274
1604
|
/**
|
|
1275
1605
|
* Extracts metadata for multiple tokens
|
|
1276
|
-
* @param
|
|
1606
|
+
* @param tokens - Array of token objects with symbol and optional marketPrefix
|
|
1277
1607
|
* @param perpMetaAssets - Aggregated universe assets
|
|
1278
1608
|
* @param finalAssetContexts - Aggregated asset contexts
|
|
1279
1609
|
* @param allMids - AllMids data
|
|
1280
1610
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1281
|
-
* @returns Record of
|
|
1611
|
+
* @returns Record of unique key to TokenMetadata. Key is "{prefix}:{symbol}" for HIP3 assets, or just "{symbol}" otherwise
|
|
1282
1612
|
*/
|
|
1283
|
-
static extractMultipleTokensMetadata(
|
|
1613
|
+
static extractMultipleTokensMetadata(tokens, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
1284
1614
|
const result = {};
|
|
1285
|
-
for (const
|
|
1286
|
-
|
|
1615
|
+
for (const token of tokens) {
|
|
1616
|
+
// Use a unique key that includes the prefix for HIP3 assets
|
|
1617
|
+
// This ensures xyz:TSLA and flx:TSLA get separate entries
|
|
1618
|
+
const resultKey = token.marketPrefix
|
|
1619
|
+
? `${token.marketPrefix}:${token.symbol}`
|
|
1620
|
+
: token.symbol;
|
|
1621
|
+
result[resultKey] = this.extractTokenMetadata(token.symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData, token.marketPrefix);
|
|
1287
1622
|
}
|
|
1288
1623
|
return result;
|
|
1289
1624
|
}
|
|
@@ -1296,10 +1631,30 @@ class TokenMetadataExtractor {
|
|
|
1296
1631
|
static isTokenAvailable(symbol, perpMetaAssets) {
|
|
1297
1632
|
if (!perpMetaAssets)
|
|
1298
1633
|
return false;
|
|
1299
|
-
return perpMetaAssets.some(asset => asset.name === symbol);
|
|
1634
|
+
return perpMetaAssets.some((asset) => asset.name === symbol);
|
|
1300
1635
|
}
|
|
1301
1636
|
}
|
|
1302
1637
|
|
|
1638
|
+
/**
|
|
1639
|
+
* Parse a token string that may have a market prefix (e.g., "xyz:GOOGL" -> { prefix: "xyz", symbol: "GOOGL" })
|
|
1640
|
+
* This allows us to keep the full name (xyz:GOOGL) for URLs/tags while extracting just the symbol for SDK lookups.
|
|
1641
|
+
*/
|
|
1642
|
+
function parseTokenWithPrefix(token) {
|
|
1643
|
+
if (token.includes(":")) {
|
|
1644
|
+
const [prefix, ...rest] = token.split(":");
|
|
1645
|
+
const symbol = rest.join(":").toUpperCase();
|
|
1646
|
+
return {
|
|
1647
|
+
prefix: prefix.toLowerCase(),
|
|
1648
|
+
symbol,
|
|
1649
|
+
fullName: `${prefix.toLowerCase()}:${symbol}`,
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
return {
|
|
1653
|
+
prefix: null,
|
|
1654
|
+
symbol: token.toUpperCase(),
|
|
1655
|
+
fullName: token.toUpperCase(),
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1303
1658
|
const useTokenSelectionMetadataStore = create((set) => ({
|
|
1304
1659
|
isPriceDataReady: false,
|
|
1305
1660
|
isLoading: true,
|
|
@@ -1315,17 +1670,59 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1315
1670
|
maxLeverage: 0,
|
|
1316
1671
|
minMargin: 0,
|
|
1317
1672
|
leverageMatched: true,
|
|
1318
|
-
recompute: ({ perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketData, longTokens, shortTokens }) => {
|
|
1319
|
-
const isPriceDataReady = !!(perpMetaAssets &&
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1673
|
+
recompute: ({ perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketData, longTokens, shortTokens, }) => {
|
|
1674
|
+
const isPriceDataReady = !!(perpMetaAssets &&
|
|
1675
|
+
finalAssetContexts &&
|
|
1676
|
+
allMids);
|
|
1677
|
+
// Parse tokens - handle prefixed tokens like "xyz:GOOGL" by extracting the symbol and market prefix
|
|
1678
|
+
// The full name (xyz:GOOGL) is kept as the metadata key for UI consistency
|
|
1679
|
+
const parsedLongTokens = longTokens.map((t) => ({
|
|
1680
|
+
...t,
|
|
1681
|
+
parsed: parseTokenWithPrefix(t.symbol),
|
|
1682
|
+
}));
|
|
1683
|
+
const parsedShortTokens = shortTokens.map((t) => ({
|
|
1684
|
+
...t,
|
|
1685
|
+
parsed: parseTokenWithPrefix(t.symbol),
|
|
1686
|
+
}));
|
|
1687
|
+
// Extract base symbols with their market prefixes for SDK lookups
|
|
1688
|
+
// This ensures xyz:TSLA and flx:TSLA get different market data
|
|
1689
|
+
const longTokensForLookup = parsedLongTokens.map((t) => ({
|
|
1690
|
+
symbol: t.parsed.symbol,
|
|
1691
|
+
marketPrefix: t.parsed.prefix,
|
|
1692
|
+
}));
|
|
1693
|
+
const shortTokensForLookup = parsedShortTokens.map((t) => ({
|
|
1694
|
+
symbol: t.parsed.symbol,
|
|
1695
|
+
marketPrefix: t.parsed.prefix,
|
|
1696
|
+
}));
|
|
1697
|
+
// Also extract just the base symbols (without prefix) for lookups that don't support prefixes
|
|
1698
|
+
const longBaseSymbols = longTokensForLookup.map((t) => t.symbol);
|
|
1699
|
+
const shortBaseSymbols = shortTokensForLookup.map((t) => t.symbol);
|
|
1700
|
+
// Get metadata using base symbols with market prefix for proper market differentiation
|
|
1701
|
+
const longBaseMetadata = isPriceDataReady
|
|
1702
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(longTokensForLookup, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1325
1703
|
: {};
|
|
1326
|
-
const
|
|
1327
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(
|
|
1704
|
+
const shortBaseMetadata = isPriceDataReady
|
|
1705
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(shortTokensForLookup, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1328
1706
|
: {};
|
|
1707
|
+
// Re-map metadata using original full names (with prefix) as keys for UI consistency
|
|
1708
|
+
// The extractor now keys by "{prefix}:{symbol}" for prefixed tokens, which matches our parsed.fullName
|
|
1709
|
+
const longTokensMetadata = {};
|
|
1710
|
+
parsedLongTokens.forEach((t) => {
|
|
1711
|
+
var _a;
|
|
1712
|
+
// Use the full name (e.g., "xyz:TSLA") as the lookup key since extractor uses the same format
|
|
1713
|
+
const lookupKey = t.parsed.prefix
|
|
1714
|
+
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1715
|
+
: t.parsed.symbol;
|
|
1716
|
+
longTokensMetadata[t.symbol] = (_a = longBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1717
|
+
});
|
|
1718
|
+
const shortTokensMetadata = {};
|
|
1719
|
+
parsedShortTokens.forEach((t) => {
|
|
1720
|
+
var _a;
|
|
1721
|
+
const lookupKey = t.parsed.prefix
|
|
1722
|
+
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1723
|
+
: t.parsed.symbol;
|
|
1724
|
+
shortTokensMetadata[t.symbol] = (_a = shortBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1725
|
+
});
|
|
1329
1726
|
// Determine loading state
|
|
1330
1727
|
const allTokens = [...longTokens, ...shortTokens];
|
|
1331
1728
|
const isLoading = (() => {
|
|
@@ -1333,26 +1730,33 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1333
1730
|
return true;
|
|
1334
1731
|
if (allTokens.length === 0)
|
|
1335
1732
|
return false;
|
|
1336
|
-
const allMetadata = {
|
|
1733
|
+
const allMetadata = {
|
|
1734
|
+
...longTokensMetadata,
|
|
1735
|
+
...shortTokensMetadata,
|
|
1736
|
+
};
|
|
1337
1737
|
return allTokens.some((token) => !allMetadata[token.symbol]);
|
|
1338
1738
|
})();
|
|
1339
1739
|
// Open interest and volume (from market data for matching asset basket)
|
|
1740
|
+
// Use base symbols (without prefix) for matching against market data
|
|
1340
1741
|
const { openInterest, volume } = (() => {
|
|
1341
1742
|
const empty = { openInterest: "0", volume: "0" };
|
|
1342
1743
|
if (!(marketData === null || marketData === void 0 ? void 0 : marketData.active) || (!longTokens.length && !shortTokens.length))
|
|
1343
1744
|
return empty;
|
|
1344
|
-
const selectedLong =
|
|
1345
|
-
const selectedShort =
|
|
1745
|
+
const selectedLong = longBaseSymbols.slice().sort();
|
|
1746
|
+
const selectedShort = shortBaseSymbols.slice().sort();
|
|
1346
1747
|
const match = marketData.active.find((item) => {
|
|
1347
1748
|
const longs = [...item.longAssets].sort();
|
|
1348
1749
|
const shorts = [...item.shortAssets].sort();
|
|
1349
|
-
if (longs.length !== selectedLong.length ||
|
|
1750
|
+
if (longs.length !== selectedLong.length ||
|
|
1751
|
+
shorts.length !== selectedShort.length)
|
|
1350
1752
|
return false;
|
|
1351
1753
|
const longsEqual = longs.every((s, i) => s.asset === selectedLong[i]);
|
|
1352
1754
|
const shortsEqual = shorts.every((s, i) => s.asset === selectedShort[i]);
|
|
1353
1755
|
return longsEqual && shortsEqual;
|
|
1354
1756
|
});
|
|
1355
|
-
return match
|
|
1757
|
+
return match
|
|
1758
|
+
? { openInterest: match.openInterest, volume: match.volume }
|
|
1759
|
+
: empty;
|
|
1356
1760
|
})();
|
|
1357
1761
|
// Price ratio (only when exactly one long and one short)
|
|
1358
1762
|
const { priceRatio, priceRatio24h } = (() => {
|
|
@@ -1432,17 +1836,27 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1432
1836
|
return totalFunding;
|
|
1433
1837
|
})();
|
|
1434
1838
|
// Max leverage (maximum across all tokens)
|
|
1839
|
+
// Use tokens with their market prefixes for proper lookup in perpMetaAssets
|
|
1435
1840
|
const maxLeverage = (() => {
|
|
1436
1841
|
if (!perpMetaAssets)
|
|
1437
1842
|
return 0;
|
|
1438
|
-
const
|
|
1439
|
-
|
|
1843
|
+
const allTokensForLookup = [
|
|
1844
|
+
...longTokensForLookup,
|
|
1845
|
+
...shortTokensForLookup,
|
|
1846
|
+
];
|
|
1847
|
+
if (allTokensForLookup.length === 0)
|
|
1440
1848
|
return 0;
|
|
1441
1849
|
let maxLev = 0;
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1850
|
+
allTokensForLookup.forEach(({ symbol, marketPrefix }) => {
|
|
1851
|
+
// Match by both name AND marketPrefix for HIP3 assets
|
|
1852
|
+
const tokenUniverse = perpMetaAssets.find((u) => u.name === symbol &&
|
|
1853
|
+
(marketPrefix
|
|
1854
|
+
? u.marketPrefix === marketPrefix
|
|
1855
|
+
: !u.marketPrefix));
|
|
1856
|
+
// Fallback to just matching by name if no exact match
|
|
1857
|
+
const fallbackUniverse = tokenUniverse || perpMetaAssets.find((u) => u.name === symbol);
|
|
1858
|
+
if (fallbackUniverse === null || fallbackUniverse === void 0 ? void 0 : fallbackUniverse.maxLeverage)
|
|
1859
|
+
maxLev = Math.max(maxLev, fallbackUniverse.maxLeverage);
|
|
1446
1860
|
});
|
|
1447
1861
|
return maxLev;
|
|
1448
1862
|
})();
|
|
@@ -1454,7 +1868,10 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1454
1868
|
// Whether all tokens have matching leverage
|
|
1455
1869
|
const leverageMatched = (() => {
|
|
1456
1870
|
const allTokensArr = [...longTokens, ...shortTokens];
|
|
1457
|
-
const allMetadata = {
|
|
1871
|
+
const allMetadata = {
|
|
1872
|
+
...longTokensMetadata,
|
|
1873
|
+
...shortTokensMetadata,
|
|
1874
|
+
};
|
|
1458
1875
|
if (allTokensArr.length === 0)
|
|
1459
1876
|
return true;
|
|
1460
1877
|
const tokensWithLev = allTokensArr.filter((token) => { var _a; return (_a = allMetadata[token.symbol]) === null || _a === void 0 ? void 0 : _a.leverage; });
|
|
@@ -5639,8 +6056,8 @@ function addAuthInterceptors(params) {
|
|
|
5639
6056
|
/**
|
|
5640
6057
|
* Fetch historical candle data from HyperLiquid API
|
|
5641
6058
|
*/
|
|
5642
|
-
const fetchHistoricalCandles = async (coin, startTime, endTime, interval,
|
|
5643
|
-
const backendCoin = toBackendSymbol(coin,
|
|
6059
|
+
const fetchHistoricalCandles = async (coin, startTime, endTime, interval, hip3Assets) => {
|
|
6060
|
+
const backendCoin = toBackendSymbol(coin, hip3Assets);
|
|
5644
6061
|
const request = {
|
|
5645
6062
|
req: { coin: backendCoin, startTime, endTime, interval },
|
|
5646
6063
|
type: 'candleSnapshot',
|
|
@@ -5799,10 +6216,10 @@ const useHistoricalPriceData = () => {
|
|
|
5799
6216
|
setTokenLoading(token.symbol, true);
|
|
5800
6217
|
});
|
|
5801
6218
|
try {
|
|
5802
|
-
const
|
|
6219
|
+
const hip3Assets = useHyperliquidData.getState().hip3Assets;
|
|
5803
6220
|
const fetchPromises = tokensToFetch.map(async (token) => {
|
|
5804
6221
|
try {
|
|
5805
|
-
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval,
|
|
6222
|
+
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval, hip3Assets);
|
|
5806
6223
|
addHistoricalPriceData(token.symbol, interval, response.data, { start: startTime, end: endTime });
|
|
5807
6224
|
return { symbol: token.symbol, candles: response.data, success: true };
|
|
5808
6225
|
}
|
|
@@ -6491,14 +6908,14 @@ function useAutoSyncFills(options) {
|
|
|
6491
6908
|
* @throws MinimumPositionSizeError if any asset has less than $11 USD value
|
|
6492
6909
|
* @throws MaxAssetsPerLegError if any leg exceeds the maximum allowed assets (15)
|
|
6493
6910
|
*/
|
|
6494
|
-
async function createPosition(baseUrl, payload,
|
|
6911
|
+
async function createPosition(baseUrl, payload, hip3Assets) {
|
|
6495
6912
|
// Validate maximum assets per leg before creating position
|
|
6496
6913
|
validateMaxAssetsPerLeg(payload.longAssets, payload.shortAssets);
|
|
6497
6914
|
// Validate minimum asset size before creating position
|
|
6498
6915
|
validateMinimumAssetSize(payload.usdValue, payload.longAssets, payload.shortAssets);
|
|
6499
6916
|
const url = joinUrl(baseUrl, "/positions");
|
|
6500
6917
|
// Translate display symbols to backend format
|
|
6501
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset,
|
|
6918
|
+
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, hip3Assets) }));
|
|
6502
6919
|
const translatedPayload = {
|
|
6503
6920
|
...payload,
|
|
6504
6921
|
longAssets: mapAssets(payload.longAssets),
|
|
@@ -6597,9 +7014,9 @@ async function adjustPosition(baseUrl, positionId, payload) {
|
|
|
6597
7014
|
throw toApiError(error);
|
|
6598
7015
|
}
|
|
6599
7016
|
}
|
|
6600
|
-
async function adjustAdvancePosition(baseUrl, positionId, payload,
|
|
7017
|
+
async function adjustAdvancePosition(baseUrl, positionId, payload, hip3Assets) {
|
|
6601
7018
|
const url = joinUrl(baseUrl, `/positions/${positionId}/adjust-advance`);
|
|
6602
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset,
|
|
7019
|
+
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, hip3Assets) }));
|
|
6603
7020
|
const translatedPayload = (payload || []).map((item) => ({
|
|
6604
7021
|
longAssets: mapAssets(item.longAssets),
|
|
6605
7022
|
shortAssets: mapAssets(item.shortAssets),
|
|
@@ -6682,10 +7099,11 @@ const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, l
|
|
|
6682
7099
|
positionValue: currentNotional,
|
|
6683
7100
|
unrealizedPnl: unrealizedPnl,
|
|
6684
7101
|
entryPositionValue: entryNotional,
|
|
6685
|
-
initialWeight: totalInitialPositionSize > 0
|
|
6686
|
-
? entryNotional / totalInitialPositionSize
|
|
6687
|
-
: 0,
|
|
7102
|
+
initialWeight: totalInitialPositionSize > 0 ? entryNotional / totalInitialPositionSize : 0,
|
|
6688
7103
|
fundingPaid: (_a = asset.fundingPaid) !== null && _a !== void 0 ? _a : 0,
|
|
7104
|
+
// Preserve market metadata from raw asset (if provided by backend)
|
|
7105
|
+
marketPrefix: asset.marketPrefix,
|
|
7106
|
+
collateralToken: asset.collateralToken,
|
|
6689
7107
|
};
|
|
6690
7108
|
};
|
|
6691
7109
|
const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
@@ -6774,36 +7192,108 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
6774
7192
|
});
|
|
6775
7193
|
};
|
|
6776
7194
|
|
|
7195
|
+
function findAssetMeta$3(coinName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7196
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
7197
|
+
if (!perpMetaAssets) {
|
|
7198
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7199
|
+
}
|
|
7200
|
+
if (desiredCollateral) {
|
|
7201
|
+
const collateralMatch = perpMetaAssets.find((a) => a.name === coinName && a.collateralToken === desiredCollateral);
|
|
7202
|
+
if (collateralMatch) {
|
|
7203
|
+
return {
|
|
7204
|
+
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7205
|
+
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7206
|
+
};
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
7209
|
+
if (coinName.includes(':')) {
|
|
7210
|
+
const [prefix, symbol] = coinName.split(':');
|
|
7211
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
7212
|
+
var _a;
|
|
7213
|
+
return a.name === symbol &&
|
|
7214
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7215
|
+
});
|
|
7216
|
+
if (exactMatch) {
|
|
7217
|
+
return {
|
|
7218
|
+
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7219
|
+
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7220
|
+
};
|
|
7221
|
+
}
|
|
7222
|
+
}
|
|
7223
|
+
if (knownPrefix) {
|
|
7224
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
7225
|
+
var _a;
|
|
7226
|
+
return a.name === coinName &&
|
|
7227
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7228
|
+
});
|
|
7229
|
+
if (exactMatch) {
|
|
7230
|
+
return {
|
|
7231
|
+
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7232
|
+
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7233
|
+
};
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
const regularAsset = perpMetaAssets.find((a) => a.name === coinName && !a.marketPrefix);
|
|
7237
|
+
if (regularAsset) {
|
|
7238
|
+
return {
|
|
7239
|
+
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7240
|
+
marketPrefix: null,
|
|
7241
|
+
};
|
|
7242
|
+
}
|
|
7243
|
+
const hip3Asset = perpMetaAssets.find((a) => a.name === coinName && a.marketPrefix);
|
|
7244
|
+
if (hip3Asset) {
|
|
7245
|
+
return {
|
|
7246
|
+
collateralToken: (_h = hip3Asset.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7247
|
+
marketPrefix: (_j = hip3Asset.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7248
|
+
};
|
|
7249
|
+
}
|
|
7250
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7251
|
+
}
|
|
7252
|
+
function enrichPositionAssets(assets, perpMetaAssets) {
|
|
7253
|
+
return assets.map((asset) => {
|
|
7254
|
+
var _a;
|
|
7255
|
+
if (asset.marketPrefix && asset.collateralToken) {
|
|
7256
|
+
return asset;
|
|
7257
|
+
}
|
|
7258
|
+
const meta = findAssetMeta$3(asset.coin, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7259
|
+
return {
|
|
7260
|
+
...asset,
|
|
7261
|
+
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7262
|
+
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7263
|
+
};
|
|
7264
|
+
});
|
|
7265
|
+
}
|
|
7266
|
+
function enrichPositions(positions, perpMetaAssets) {
|
|
7267
|
+
return positions.map((position) => ({
|
|
7268
|
+
...position,
|
|
7269
|
+
longAssets: enrichPositionAssets(position.longAssets, perpMetaAssets),
|
|
7270
|
+
shortAssets: enrichPositionAssets(position.shortAssets, perpMetaAssets),
|
|
7271
|
+
}));
|
|
7272
|
+
}
|
|
6777
7273
|
function usePosition() {
|
|
6778
7274
|
const context = useContext(PearHyperliquidContext);
|
|
6779
7275
|
if (!context) {
|
|
6780
7276
|
throw new Error('usePosition must be used within a PearHyperliquidProvider');
|
|
6781
7277
|
}
|
|
6782
7278
|
const { apiBaseUrl, isConnected } = context;
|
|
6783
|
-
const
|
|
6784
|
-
// Create position API action
|
|
7279
|
+
const hip3Assets = useHyperliquidData((s) => s.hip3Assets);
|
|
6785
7280
|
const createPosition$1 = async (payload) => {
|
|
6786
|
-
return createPosition(apiBaseUrl, payload,
|
|
7281
|
+
return createPosition(apiBaseUrl, payload, hip3Assets);
|
|
6787
7282
|
};
|
|
6788
|
-
// Update TP/SL risk parameters for a position
|
|
6789
7283
|
const updateRiskParameters$1 = async (positionId, payload) => {
|
|
6790
7284
|
return updateRiskParameters(apiBaseUrl, positionId, payload);
|
|
6791
7285
|
};
|
|
6792
|
-
// Close a position (MARKET or TWAP)
|
|
6793
7286
|
const closePosition$1 = async (positionId, payload) => {
|
|
6794
7287
|
return closePosition(apiBaseUrl, positionId, payload);
|
|
6795
7288
|
};
|
|
6796
|
-
// Close all positions (MARKET or TWAP)
|
|
6797
7289
|
const closeAllPositions$1 = async (payload) => {
|
|
6798
7290
|
return closeAllPositions(apiBaseUrl, payload);
|
|
6799
7291
|
};
|
|
6800
|
-
// Adjust a position (REDUCE/INCREASE by %; MARKET or LIMIT)
|
|
6801
7292
|
const adjustPosition$1 = async (positionId, payload) => {
|
|
6802
7293
|
return adjustPosition(apiBaseUrl, positionId, payload);
|
|
6803
7294
|
};
|
|
6804
|
-
// Adjust to absolute target sizes per asset, optionally adding new assets
|
|
6805
7295
|
const adjustAdvancePosition$1 = async (positionId, payload) => {
|
|
6806
|
-
return adjustAdvancePosition(apiBaseUrl, positionId, payload,
|
|
7296
|
+
return adjustAdvancePosition(apiBaseUrl, positionId, payload, hip3Assets);
|
|
6807
7297
|
};
|
|
6808
7298
|
const updateLeverage$1 = async (positionId, leverage) => {
|
|
6809
7299
|
return updateLeverage(apiBaseUrl, positionId, { leverage });
|
|
@@ -6812,22 +7302,46 @@ function usePosition() {
|
|
|
6812
7302
|
const userOpenPositions = useUserData((state) => state.rawOpenPositions);
|
|
6813
7303
|
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
6814
7304
|
const allMids = useHyperliquidData((state) => state.allMids);
|
|
7305
|
+
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
6815
7306
|
const isLoading = useMemo(() => {
|
|
6816
7307
|
return userOpenPositions === null && isConnected;
|
|
6817
7308
|
}, [userOpenPositions, isConnected]);
|
|
6818
7309
|
const openPositions = useMemo(() => {
|
|
6819
7310
|
if (!userOpenPositions || !aggregatedClearingHouseState || !allMids)
|
|
6820
7311
|
return null;
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
7312
|
+
const positions = buildPositionValue(userOpenPositions, aggregatedClearingHouseState, allMids);
|
|
7313
|
+
return enrichPositions(positions, allPerpMetaAssets);
|
|
7314
|
+
}, [
|
|
7315
|
+
userOpenPositions,
|
|
7316
|
+
aggregatedClearingHouseState,
|
|
7317
|
+
allMids,
|
|
7318
|
+
allPerpMetaAssets,
|
|
7319
|
+
]);
|
|
7320
|
+
return {
|
|
7321
|
+
createPosition: createPosition$1,
|
|
7322
|
+
updateRiskParameters: updateRiskParameters$1,
|
|
7323
|
+
closePosition: closePosition$1,
|
|
7324
|
+
closeAllPositions: closeAllPositions$1,
|
|
7325
|
+
adjustPosition: adjustPosition$1,
|
|
7326
|
+
adjustAdvancePosition: adjustAdvancePosition$1,
|
|
7327
|
+
updateLeverage: updateLeverage$1,
|
|
7328
|
+
openPositions,
|
|
7329
|
+
isLoading,
|
|
7330
|
+
};
|
|
6824
7331
|
}
|
|
6825
7332
|
|
|
6826
7333
|
async function adjustOrder(baseUrl, orderId, payload) {
|
|
6827
7334
|
const url = joinUrl(baseUrl, `/orders/${orderId}/adjust`);
|
|
6828
7335
|
try {
|
|
6829
|
-
const resp = await apiClient.put(url, payload, {
|
|
6830
|
-
|
|
7336
|
+
const resp = await apiClient.put(url, payload, {
|
|
7337
|
+
headers: { 'Content-Type': 'application/json' },
|
|
7338
|
+
timeout: 60000,
|
|
7339
|
+
});
|
|
7340
|
+
return {
|
|
7341
|
+
data: resp.data,
|
|
7342
|
+
status: resp.status,
|
|
7343
|
+
headers: resp.headers,
|
|
7344
|
+
};
|
|
6831
7345
|
}
|
|
6832
7346
|
catch (error) {
|
|
6833
7347
|
throw toApiError(error);
|
|
@@ -6836,8 +7350,14 @@ async function adjustOrder(baseUrl, orderId, payload) {
|
|
|
6836
7350
|
async function cancelOrder(baseUrl, orderId) {
|
|
6837
7351
|
const url = joinUrl(baseUrl, `/orders/${orderId}/cancel`);
|
|
6838
7352
|
try {
|
|
6839
|
-
const resp = await apiClient.delete(url, {
|
|
6840
|
-
|
|
7353
|
+
const resp = await apiClient.delete(url, {
|
|
7354
|
+
timeout: 60000,
|
|
7355
|
+
});
|
|
7356
|
+
return {
|
|
7357
|
+
data: resp.data,
|
|
7358
|
+
status: resp.status,
|
|
7359
|
+
headers: resp.headers,
|
|
7360
|
+
};
|
|
6841
7361
|
}
|
|
6842
7362
|
catch (error) {
|
|
6843
7363
|
throw toApiError(error);
|
|
@@ -6847,19 +7367,129 @@ async function cancelTwapOrder(baseUrl, orderId) {
|
|
|
6847
7367
|
const url = joinUrl(baseUrl, `/orders/${orderId}/twap/cancel`);
|
|
6848
7368
|
try {
|
|
6849
7369
|
const resp = await apiClient.post(url, {}, { headers: { 'Content-Type': 'application/json' }, timeout: 60000 });
|
|
6850
|
-
return {
|
|
7370
|
+
return {
|
|
7371
|
+
data: resp.data,
|
|
7372
|
+
status: resp.status,
|
|
7373
|
+
headers: resp.headers,
|
|
7374
|
+
};
|
|
7375
|
+
}
|
|
7376
|
+
catch (error) {
|
|
7377
|
+
throw toApiError(error);
|
|
7378
|
+
}
|
|
7379
|
+
}
|
|
7380
|
+
/**
|
|
7381
|
+
* Execute a spot order (swap) using Pear Hyperliquid service
|
|
7382
|
+
* POST /orders/spot
|
|
7383
|
+
*/
|
|
7384
|
+
async function executeSpotOrder(baseUrl, payload) {
|
|
7385
|
+
const url = joinUrl(baseUrl, '/orders/spot');
|
|
7386
|
+
try {
|
|
7387
|
+
const resp = await apiClient.post(url, payload, {
|
|
7388
|
+
headers: { 'Content-Type': 'application/json' },
|
|
7389
|
+
timeout: 60000,
|
|
7390
|
+
});
|
|
7391
|
+
return {
|
|
7392
|
+
data: resp.data,
|
|
7393
|
+
status: resp.status,
|
|
7394
|
+
headers: resp.headers,
|
|
7395
|
+
};
|
|
6851
7396
|
}
|
|
6852
7397
|
catch (error) {
|
|
6853
7398
|
throw toApiError(error);
|
|
6854
7399
|
}
|
|
6855
7400
|
}
|
|
6856
7401
|
|
|
7402
|
+
function findAssetMeta$2(assetName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7403
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
7404
|
+
if (!perpMetaAssets) {
|
|
7405
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7406
|
+
}
|
|
7407
|
+
if (desiredCollateral) {
|
|
7408
|
+
const collateralMatch = perpMetaAssets.find((a) => a.name === assetName && a.collateralToken === desiredCollateral);
|
|
7409
|
+
if (collateralMatch) {
|
|
7410
|
+
return {
|
|
7411
|
+
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7412
|
+
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7413
|
+
};
|
|
7414
|
+
}
|
|
7415
|
+
}
|
|
7416
|
+
if (assetName.includes(':')) {
|
|
7417
|
+
const [prefix, symbol] = assetName.split(':');
|
|
7418
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
7419
|
+
var _a;
|
|
7420
|
+
return a.name === symbol &&
|
|
7421
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7422
|
+
});
|
|
7423
|
+
if (exactMatch) {
|
|
7424
|
+
return {
|
|
7425
|
+
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7426
|
+
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7427
|
+
};
|
|
7428
|
+
}
|
|
7429
|
+
}
|
|
7430
|
+
if (knownPrefix) {
|
|
7431
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
7432
|
+
var _a;
|
|
7433
|
+
return a.name === assetName &&
|
|
7434
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7435
|
+
});
|
|
7436
|
+
if (exactMatch) {
|
|
7437
|
+
return {
|
|
7438
|
+
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7439
|
+
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7440
|
+
};
|
|
7441
|
+
}
|
|
7442
|
+
}
|
|
7443
|
+
const regularAsset = perpMetaAssets.find((a) => a.name === assetName && !a.marketPrefix);
|
|
7444
|
+
if (regularAsset) {
|
|
7445
|
+
return {
|
|
7446
|
+
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7447
|
+
marketPrefix: null,
|
|
7448
|
+
};
|
|
7449
|
+
}
|
|
7450
|
+
const hip3Assets = perpMetaAssets.filter((a) => a.name === assetName && a.marketPrefix);
|
|
7451
|
+
if (hip3Assets.length > 0) {
|
|
7452
|
+
if (desiredCollateral) {
|
|
7453
|
+
const collateralMatch = hip3Assets.find((a) => a.collateralToken === desiredCollateral);
|
|
7454
|
+
if (collateralMatch) {
|
|
7455
|
+
return {
|
|
7456
|
+
collateralToken: (_h = collateralMatch.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7457
|
+
marketPrefix: (_j = collateralMatch.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7458
|
+
};
|
|
7459
|
+
}
|
|
7460
|
+
}
|
|
7461
|
+
const usdHMatch = hip3Assets.find((a) => a.collateralToken === 'USDH');
|
|
7462
|
+
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Assets[0];
|
|
7463
|
+
return {
|
|
7464
|
+
collateralToken: (_k = chosen.collateralToken) !== null && _k !== void 0 ? _k : 'USDC',
|
|
7465
|
+
marketPrefix: (_l = chosen.marketPrefix) !== null && _l !== void 0 ? _l : null,
|
|
7466
|
+
};
|
|
7467
|
+
}
|
|
7468
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7469
|
+
}
|
|
7470
|
+
function enrichOrderAssets$1(assets, perpMetaAssets) {
|
|
7471
|
+
if (!assets)
|
|
7472
|
+
return [];
|
|
7473
|
+
return assets.map((asset) => {
|
|
7474
|
+
var _a;
|
|
7475
|
+
if (asset.marketPrefix && asset.collateralToken) {
|
|
7476
|
+
return asset;
|
|
7477
|
+
}
|
|
7478
|
+
const meta = findAssetMeta$2(asset.asset, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7479
|
+
return {
|
|
7480
|
+
...asset,
|
|
7481
|
+
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7482
|
+
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7483
|
+
};
|
|
7484
|
+
});
|
|
7485
|
+
}
|
|
6857
7486
|
function useOrders() {
|
|
6858
7487
|
const context = useContext(PearHyperliquidContext);
|
|
6859
7488
|
if (!context)
|
|
6860
7489
|
throw new Error('useOrders must be used within a PearHyperliquidProvider');
|
|
6861
7490
|
const { apiBaseUrl } = context;
|
|
6862
7491
|
const openOrders = useUserData((state) => state.openOrders);
|
|
7492
|
+
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
6863
7493
|
const isLoading = useMemo(() => openOrders === null && context.isConnected, [openOrders, context.isConnected]);
|
|
6864
7494
|
const { openPositions } = usePosition();
|
|
6865
7495
|
const positionsById = useMemo(() => {
|
|
@@ -6878,19 +7508,27 @@ function useOrders() {
|
|
|
6878
7508
|
const isTpSl = ord.orderType === 'TP' || ord.orderType === 'SL';
|
|
6879
7509
|
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;
|
|
6880
7510
|
const pos = positionsById.get((_e = ord.positionId) !== null && _e !== void 0 ? _e : '');
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
7511
|
+
let enrichedOrd = {
|
|
7512
|
+
...ord,
|
|
7513
|
+
longAssets: enrichOrderAssets$1(ord.longAssets, allPerpMetaAssets),
|
|
7514
|
+
shortAssets: enrichOrderAssets$1(ord.shortAssets, allPerpMetaAssets),
|
|
7515
|
+
};
|
|
7516
|
+
if (isTpSl && !hasAssets && pos) {
|
|
7517
|
+
const mapAssets = (arr) => arr.map((a) => ({
|
|
7518
|
+
asset: a.coin,
|
|
7519
|
+
weight: a.initialWeight,
|
|
7520
|
+
marketPrefix: a.marketPrefix,
|
|
7521
|
+
collateralToken: a.collateralToken,
|
|
7522
|
+
}));
|
|
7523
|
+
enrichedOrd = {
|
|
7524
|
+
...enrichedOrd,
|
|
6887
7525
|
longAssets: mapAssets(pos.longAssets),
|
|
6888
7526
|
shortAssets: mapAssets(pos.shortAssets),
|
|
6889
7527
|
};
|
|
6890
7528
|
}
|
|
6891
|
-
return
|
|
7529
|
+
return enrichedOrd;
|
|
6892
7530
|
});
|
|
6893
|
-
}, [openOrders, positionsById]);
|
|
7531
|
+
}, [openOrders, positionsById, allPerpMetaAssets]);
|
|
6894
7532
|
const adjustOrder$1 = async (orderId, payload) => {
|
|
6895
7533
|
return adjustOrder(apiBaseUrl, orderId, payload);
|
|
6896
7534
|
};
|
|
@@ -6900,16 +7538,156 @@ function useOrders() {
|
|
|
6900
7538
|
const cancelTwapOrder$1 = async (orderId) => {
|
|
6901
7539
|
return cancelTwapOrder(apiBaseUrl, orderId);
|
|
6902
7540
|
};
|
|
6903
|
-
return {
|
|
7541
|
+
return {
|
|
7542
|
+
adjustOrder: adjustOrder$1,
|
|
7543
|
+
cancelOrder: cancelOrder$1,
|
|
7544
|
+
cancelTwapOrder: cancelTwapOrder$1,
|
|
7545
|
+
openOrders: enrichedOpenOrders,
|
|
7546
|
+
isLoading,
|
|
7547
|
+
};
|
|
6904
7548
|
}
|
|
6905
7549
|
|
|
7550
|
+
/**
|
|
7551
|
+
* Hook for executing spot orders (swaps) on Hyperliquid
|
|
7552
|
+
* Use this to swap between USDC and USDH or other spot assets
|
|
7553
|
+
*/
|
|
7554
|
+
function useSpotOrder() {
|
|
7555
|
+
const context = useContext(PearHyperliquidContext);
|
|
7556
|
+
if (!context) {
|
|
7557
|
+
throw new Error('useSpotOrder must be used within a PearHyperliquidProvider');
|
|
7558
|
+
}
|
|
7559
|
+
const { apiBaseUrl } = context;
|
|
7560
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
7561
|
+
const [error, setError] = useState(null);
|
|
7562
|
+
const resetError = useCallback(() => {
|
|
7563
|
+
setError(null);
|
|
7564
|
+
}, []);
|
|
7565
|
+
const executeSpotOrder$1 = useCallback(async (payload) => {
|
|
7566
|
+
setIsLoading(true);
|
|
7567
|
+
setError(null);
|
|
7568
|
+
try {
|
|
7569
|
+
const response = await executeSpotOrder(apiBaseUrl, payload);
|
|
7570
|
+
return response;
|
|
7571
|
+
}
|
|
7572
|
+
catch (err) {
|
|
7573
|
+
const apiError = err;
|
|
7574
|
+
setError(apiError);
|
|
7575
|
+
throw apiError;
|
|
7576
|
+
}
|
|
7577
|
+
finally {
|
|
7578
|
+
setIsLoading(false);
|
|
7579
|
+
}
|
|
7580
|
+
}, [apiBaseUrl]);
|
|
7581
|
+
return {
|
|
7582
|
+
executeSpotOrder: executeSpotOrder$1,
|
|
7583
|
+
isLoading,
|
|
7584
|
+
error,
|
|
7585
|
+
resetError,
|
|
7586
|
+
};
|
|
7587
|
+
}
|
|
7588
|
+
|
|
7589
|
+
function findAssetMeta$1(assetName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7590
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
7591
|
+
if (!perpMetaAssets) {
|
|
7592
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7593
|
+
}
|
|
7594
|
+
if (desiredCollateral) {
|
|
7595
|
+
const collateralMatch = perpMetaAssets.find((a) => a.name === assetName && a.collateralToken === desiredCollateral);
|
|
7596
|
+
if (collateralMatch) {
|
|
7597
|
+
return {
|
|
7598
|
+
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7599
|
+
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7600
|
+
};
|
|
7601
|
+
}
|
|
7602
|
+
}
|
|
7603
|
+
if (assetName.includes(':')) {
|
|
7604
|
+
const [prefix, symbol] = assetName.split(':');
|
|
7605
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
7606
|
+
var _a;
|
|
7607
|
+
return a.name === symbol &&
|
|
7608
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7609
|
+
});
|
|
7610
|
+
if (exactMatch) {
|
|
7611
|
+
return {
|
|
7612
|
+
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7613
|
+
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7614
|
+
};
|
|
7615
|
+
}
|
|
7616
|
+
}
|
|
7617
|
+
if (knownPrefix) {
|
|
7618
|
+
const exactMatch = perpMetaAssets.find((a) => {
|
|
7619
|
+
var _a;
|
|
7620
|
+
return a.name === assetName &&
|
|
7621
|
+
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7622
|
+
});
|
|
7623
|
+
if (exactMatch) {
|
|
7624
|
+
return {
|
|
7625
|
+
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7626
|
+
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7627
|
+
};
|
|
7628
|
+
}
|
|
7629
|
+
}
|
|
7630
|
+
const regularAsset = perpMetaAssets.find((a) => a.name === assetName && !a.marketPrefix);
|
|
7631
|
+
if (regularAsset) {
|
|
7632
|
+
return {
|
|
7633
|
+
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7634
|
+
marketPrefix: null,
|
|
7635
|
+
};
|
|
7636
|
+
}
|
|
7637
|
+
const hip3Assets = perpMetaAssets.filter((a) => a.name === assetName && a.marketPrefix);
|
|
7638
|
+
if (hip3Assets.length > 0) {
|
|
7639
|
+
if (desiredCollateral) {
|
|
7640
|
+
const collateralMatch = hip3Assets.find((a) => a.collateralToken === desiredCollateral);
|
|
7641
|
+
if (collateralMatch) {
|
|
7642
|
+
return {
|
|
7643
|
+
collateralToken: (_h = collateralMatch.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7644
|
+
marketPrefix: (_j = collateralMatch.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7645
|
+
};
|
|
7646
|
+
}
|
|
7647
|
+
}
|
|
7648
|
+
const usdHMatch = hip3Assets.find((a) => a.collateralToken === 'USDH');
|
|
7649
|
+
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Assets[0];
|
|
7650
|
+
return {
|
|
7651
|
+
collateralToken: (_k = chosen.collateralToken) !== null && _k !== void 0 ? _k : 'USDC',
|
|
7652
|
+
marketPrefix: (_l = chosen.marketPrefix) !== null && _l !== void 0 ? _l : null,
|
|
7653
|
+
};
|
|
7654
|
+
}
|
|
7655
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7656
|
+
}
|
|
7657
|
+
function enrichOrderAssets(assets, perpMetaAssets) {
|
|
7658
|
+
if (!assets)
|
|
7659
|
+
return [];
|
|
7660
|
+
return assets.map((asset) => {
|
|
7661
|
+
var _a;
|
|
7662
|
+
if (asset.marketPrefix && asset.collateralToken) {
|
|
7663
|
+
return asset;
|
|
7664
|
+
}
|
|
7665
|
+
const meta = findAssetMeta$1(asset.asset, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7666
|
+
return {
|
|
7667
|
+
...asset,
|
|
7668
|
+
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7669
|
+
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7670
|
+
};
|
|
7671
|
+
});
|
|
7672
|
+
}
|
|
7673
|
+
function enrichTwapOrders(orders, perpMetaAssets) {
|
|
7674
|
+
return orders.map((order) => ({
|
|
7675
|
+
...order,
|
|
7676
|
+
longAssets: enrichOrderAssets(order.longAssets, perpMetaAssets),
|
|
7677
|
+
shortAssets: enrichOrderAssets(order.shortAssets, perpMetaAssets),
|
|
7678
|
+
}));
|
|
7679
|
+
}
|
|
6906
7680
|
function useTwap() {
|
|
6907
|
-
const twapDetails = useUserData(state => state.twapDetails);
|
|
7681
|
+
const twapDetails = useUserData((state) => state.twapDetails);
|
|
7682
|
+
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
6908
7683
|
const context = useContext(PearHyperliquidContext);
|
|
6909
7684
|
if (!context)
|
|
6910
7685
|
throw new Error('useTwap must be used within a PearHyperliquidProvider');
|
|
6911
7686
|
const { apiBaseUrl } = context;
|
|
6912
|
-
const orders = useMemo(() =>
|
|
7687
|
+
const orders = useMemo(() => {
|
|
7688
|
+
const rawOrders = twapDetails !== null && twapDetails !== void 0 ? twapDetails : [];
|
|
7689
|
+
return enrichTwapOrders(rawOrders, allPerpMetaAssets);
|
|
7690
|
+
}, [twapDetails, allPerpMetaAssets]);
|
|
6913
7691
|
const cancelTwap$1 = async (orderId) => {
|
|
6914
7692
|
return cancelTwap(apiBaseUrl, orderId);
|
|
6915
7693
|
};
|
|
@@ -6992,59 +7770,170 @@ function useNotifications() {
|
|
|
6992
7770
|
};
|
|
6993
7771
|
}
|
|
6994
7772
|
|
|
6995
|
-
//
|
|
7773
|
+
// Helper to find asset metadata from perpMetaAssets
|
|
7774
|
+
function findAssetMeta(assetName, perpMetaAssets) {
|
|
7775
|
+
var _a, _b, _c, _d;
|
|
7776
|
+
if (!perpMetaAssets) {
|
|
7777
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7778
|
+
}
|
|
7779
|
+
// Try exact match first (for prefixed assets like "xyz:TSLA")
|
|
7780
|
+
const exactMatch = perpMetaAssets.find((a) => a.name === assetName);
|
|
7781
|
+
if (exactMatch) {
|
|
7782
|
+
return {
|
|
7783
|
+
collateralToken: (_a = exactMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7784
|
+
marketPrefix: (_b = exactMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7785
|
+
};
|
|
7786
|
+
}
|
|
7787
|
+
// Try matching by base symbol (for non-prefixed names in data)
|
|
7788
|
+
const baseMatch = perpMetaAssets.find((a) => {
|
|
7789
|
+
const baseName = a.name.includes(':') ? a.name.split(':')[1] : a.name;
|
|
7790
|
+
return baseName === assetName;
|
|
7791
|
+
});
|
|
7792
|
+
if (baseMatch) {
|
|
7793
|
+
return {
|
|
7794
|
+
collateralToken: (_c = baseMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7795
|
+
marketPrefix: (_d = baseMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7796
|
+
};
|
|
7797
|
+
}
|
|
7798
|
+
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7799
|
+
}
|
|
7800
|
+
// Enrich a single asset with metadata
|
|
7801
|
+
function enrichAsset(asset, perpMetaAssets) {
|
|
7802
|
+
const meta = findAssetMeta(asset.asset, perpMetaAssets);
|
|
7803
|
+
return {
|
|
7804
|
+
...asset,
|
|
7805
|
+
collateralToken: meta.collateralToken,
|
|
7806
|
+
marketPrefix: meta.marketPrefix,
|
|
7807
|
+
};
|
|
7808
|
+
}
|
|
7809
|
+
// Enrich a basket item with collateral info
|
|
7810
|
+
function enrichBasketItem(item, perpMetaAssets) {
|
|
7811
|
+
const enrichedLongs = item.longAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7812
|
+
const enrichedShorts = item.shortAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7813
|
+
// Determine collateral type
|
|
7814
|
+
const allAssets = [...enrichedLongs, ...enrichedShorts];
|
|
7815
|
+
const hasUsdc = allAssets.some((a) => a.collateralToken === 'USDC');
|
|
7816
|
+
const hasUsdh = allAssets.some((a) => a.collateralToken === 'USDH');
|
|
7817
|
+
let collateralType = 'USDC';
|
|
7818
|
+
if (hasUsdc && hasUsdh) {
|
|
7819
|
+
collateralType = 'MIXED';
|
|
7820
|
+
}
|
|
7821
|
+
else if (hasUsdh) {
|
|
7822
|
+
collateralType = 'USDH';
|
|
7823
|
+
}
|
|
7824
|
+
return {
|
|
7825
|
+
...item,
|
|
7826
|
+
longAssets: enrichedLongs,
|
|
7827
|
+
shortAssets: enrichedShorts,
|
|
7828
|
+
collateralType,
|
|
7829
|
+
};
|
|
7830
|
+
}
|
|
7831
|
+
/**
|
|
7832
|
+
* Filter baskets by collateral type
|
|
7833
|
+
* - 'USDC': Only baskets where ALL assets use USDC (collateralType === 'USDC')
|
|
7834
|
+
* - 'USDH': Only baskets where ALL assets use USDH (collateralType === 'USDH')
|
|
7835
|
+
* - 'ALL' or undefined: No filtering, returns all baskets
|
|
7836
|
+
*/
|
|
7837
|
+
function filterByCollateral(baskets, filter) {
|
|
7838
|
+
if (!filter || filter === 'ALL') {
|
|
7839
|
+
return baskets;
|
|
7840
|
+
}
|
|
7841
|
+
return baskets.filter((basket) => {
|
|
7842
|
+
if (filter === 'USDC') {
|
|
7843
|
+
// Include baskets that are purely USDC or have USDC assets
|
|
7844
|
+
return (basket.collateralType === 'USDC' || basket.collateralType === 'MIXED');
|
|
7845
|
+
}
|
|
7846
|
+
if (filter === 'USDH') {
|
|
7847
|
+
// Include baskets that are purely USDH or have USDH assets
|
|
7848
|
+
return (basket.collateralType === 'USDH' || basket.collateralType === 'MIXED');
|
|
7849
|
+
}
|
|
7850
|
+
return true;
|
|
7851
|
+
});
|
|
7852
|
+
}
|
|
7853
|
+
// Base selector for the full market-data payload (raw from WS)
|
|
6996
7854
|
const useMarketDataPayload = () => {
|
|
6997
7855
|
return useMarketData((s) => s.marketData);
|
|
6998
7856
|
};
|
|
6999
|
-
// Full payload for 'market-data-all' channel
|
|
7857
|
+
// Full payload for 'market-data-all' channel (raw from WS)
|
|
7000
7858
|
const useMarketDataAllPayload = () => {
|
|
7001
7859
|
return useMarketData((s) => s.marketDataAll);
|
|
7002
7860
|
};
|
|
7003
|
-
//
|
|
7004
|
-
const
|
|
7005
|
-
|
|
7861
|
+
// Access perpMetaAssets for enrichment
|
|
7862
|
+
const usePerpMetaAssets = () => {
|
|
7863
|
+
return useHyperliquidData((s) => s.perpMetaAssets);
|
|
7864
|
+
};
|
|
7865
|
+
// Active baskets (with collateral and market prefix info)
|
|
7866
|
+
const useActiveBaskets = (collateralFilter) => {
|
|
7006
7867
|
const data = useMarketDataPayload();
|
|
7007
|
-
|
|
7868
|
+
const perpMetaAssets = usePerpMetaAssets();
|
|
7869
|
+
return useMemo(() => {
|
|
7870
|
+
if (!(data === null || data === void 0 ? void 0 : data.active))
|
|
7871
|
+
return [];
|
|
7872
|
+
const enriched = data.active.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7873
|
+
return filterByCollateral(enriched, collateralFilter);
|
|
7874
|
+
}, [data, perpMetaAssets, collateralFilter]);
|
|
7008
7875
|
};
|
|
7009
|
-
// Top gainers (
|
|
7010
|
-
const useTopGainers = (limit) => {
|
|
7876
|
+
// Top gainers (with collateral and market prefix info)
|
|
7877
|
+
const useTopGainers = (limit, collateralFilter) => {
|
|
7011
7878
|
const data = useMarketDataPayload();
|
|
7879
|
+
const perpMetaAssets = usePerpMetaAssets();
|
|
7012
7880
|
return useMemo(() => {
|
|
7013
7881
|
var _a;
|
|
7014
7882
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topGainers) !== null && _a !== void 0 ? _a : [];
|
|
7015
|
-
|
|
7016
|
-
|
|
7883
|
+
const limited = typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
7884
|
+
const enriched = limited.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7885
|
+
return filterByCollateral(enriched, collateralFilter);
|
|
7886
|
+
}, [data, perpMetaAssets, limit, collateralFilter]);
|
|
7017
7887
|
};
|
|
7018
|
-
// Top losers (
|
|
7019
|
-
const useTopLosers = (limit) => {
|
|
7888
|
+
// Top losers (with collateral and market prefix info)
|
|
7889
|
+
const useTopLosers = (limit, collateralFilter) => {
|
|
7020
7890
|
const data = useMarketDataPayload();
|
|
7891
|
+
const perpMetaAssets = usePerpMetaAssets();
|
|
7021
7892
|
return useMemo(() => {
|
|
7022
7893
|
var _a;
|
|
7023
7894
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topLosers) !== null && _a !== void 0 ? _a : [];
|
|
7024
|
-
|
|
7025
|
-
|
|
7895
|
+
const limited = typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
7896
|
+
const enriched = limited.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7897
|
+
return filterByCollateral(enriched, collateralFilter);
|
|
7898
|
+
}, [data, perpMetaAssets, limit, collateralFilter]);
|
|
7026
7899
|
};
|
|
7027
|
-
// Highlighted baskets
|
|
7028
|
-
const useHighlightedBaskets = () => {
|
|
7029
|
-
var _a;
|
|
7900
|
+
// Highlighted baskets (with collateral and market prefix info)
|
|
7901
|
+
const useHighlightedBaskets = (collateralFilter) => {
|
|
7030
7902
|
const data = useMarketDataPayload();
|
|
7031
|
-
|
|
7903
|
+
const perpMetaAssets = usePerpMetaAssets();
|
|
7904
|
+
return useMemo(() => {
|
|
7905
|
+
if (!(data === null || data === void 0 ? void 0 : data.highlighted))
|
|
7906
|
+
return [];
|
|
7907
|
+
const enriched = data.highlighted.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7908
|
+
return filterByCollateral(enriched, collateralFilter);
|
|
7909
|
+
}, [data, perpMetaAssets, collateralFilter]);
|
|
7032
7910
|
};
|
|
7033
|
-
// Watchlist baskets (
|
|
7034
|
-
const useWatchlistBaskets = () => {
|
|
7035
|
-
var _a;
|
|
7911
|
+
// Watchlist baskets (with collateral and market prefix info)
|
|
7912
|
+
const useWatchlistBaskets = (collateralFilter) => {
|
|
7036
7913
|
const data = useMarketDataPayload();
|
|
7037
|
-
|
|
7914
|
+
const perpMetaAssets = usePerpMetaAssets();
|
|
7915
|
+
return useMemo(() => {
|
|
7916
|
+
if (!(data === null || data === void 0 ? void 0 : data.watchlist))
|
|
7917
|
+
return [];
|
|
7918
|
+
const enriched = data.watchlist.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7919
|
+
return filterByCollateral(enriched, collateralFilter);
|
|
7920
|
+
}, [data, perpMetaAssets, collateralFilter]);
|
|
7038
7921
|
};
|
|
7039
|
-
// All baskets (
|
|
7040
|
-
const useAllBaskets = () => {
|
|
7041
|
-
var _a;
|
|
7922
|
+
// All baskets (with collateral and market prefix info)
|
|
7923
|
+
const useAllBaskets = (collateralFilter) => {
|
|
7042
7924
|
const dataAll = useMarketDataAllPayload();
|
|
7043
|
-
|
|
7925
|
+
const perpMetaAssets = usePerpMetaAssets();
|
|
7926
|
+
return useMemo(() => {
|
|
7927
|
+
if (!(dataAll === null || dataAll === void 0 ? void 0 : dataAll.all))
|
|
7928
|
+
return [];
|
|
7929
|
+
const enriched = dataAll.all.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7930
|
+
return filterByCollateral(enriched, collateralFilter);
|
|
7931
|
+
}, [dataAll, perpMetaAssets, collateralFilter]);
|
|
7044
7932
|
};
|
|
7045
7933
|
// Find a basket by its exact asset composition (order-insensitive)
|
|
7046
7934
|
const useFindBasket = (longs, shorts) => {
|
|
7047
7935
|
const data = useMarketDataPayload();
|
|
7936
|
+
const perpMetaAssets = usePerpMetaAssets();
|
|
7048
7937
|
return useMemo(() => {
|
|
7049
7938
|
if (!data)
|
|
7050
7939
|
return undefined;
|
|
@@ -7058,17 +7947,28 @@ const useFindBasket = (longs, shorts) => {
|
|
|
7058
7947
|
: '';
|
|
7059
7948
|
const lKey = normalize(longs);
|
|
7060
7949
|
const sKey = normalize(shorts);
|
|
7061
|
-
const match = (item) => normalize(item.longAssets) === lKey &&
|
|
7062
|
-
|
|
7063
|
-
|
|
7950
|
+
const match = (item) => normalize(item.longAssets) === lKey &&
|
|
7951
|
+
normalize(item.shortAssets) === sKey;
|
|
7952
|
+
const found = data.active.find(match) || data.highlighted.find(match);
|
|
7953
|
+
return found
|
|
7954
|
+
? enrichBasketItem(found, perpMetaAssets)
|
|
7955
|
+
: undefined;
|
|
7956
|
+
}, [data, longs, shorts, perpMetaAssets]);
|
|
7064
7957
|
};
|
|
7065
7958
|
|
|
7066
|
-
async function toggleWatchlist(baseUrl, longAssets, shortAssets,
|
|
7959
|
+
async function toggleWatchlist(baseUrl, longAssets, shortAssets, hip3Assets) {
|
|
7067
7960
|
const url = joinUrl(baseUrl, '/watchlist');
|
|
7068
|
-
const mapAssets = (arr) => arr.map(a => ({ ...a, asset: toBackendSymbol(a.asset,
|
|
7961
|
+
const mapAssets = (arr) => arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, hip3Assets) }));
|
|
7069
7962
|
try {
|
|
7070
|
-
const response = await apiClient.post(url, {
|
|
7071
|
-
|
|
7963
|
+
const response = await apiClient.post(url, {
|
|
7964
|
+
longAssets: mapAssets(longAssets),
|
|
7965
|
+
shortAssets: mapAssets(shortAssets),
|
|
7966
|
+
}, { headers: { 'Content-Type': 'application/json' } });
|
|
7967
|
+
return {
|
|
7968
|
+
data: response.data,
|
|
7969
|
+
status: response.status,
|
|
7970
|
+
headers: response.headers,
|
|
7971
|
+
};
|
|
7072
7972
|
}
|
|
7073
7973
|
catch (error) {
|
|
7074
7974
|
throw toApiError(error);
|
|
@@ -7080,11 +7980,11 @@ function useWatchlist() {
|
|
|
7080
7980
|
if (!context)
|
|
7081
7981
|
throw new Error('useWatchlist must be used within a PearHyperliquidProvider');
|
|
7082
7982
|
const { apiBaseUrl, isConnected } = context;
|
|
7083
|
-
const
|
|
7983
|
+
const hip3Assets = useHyperliquidData((s) => s.hip3Assets);
|
|
7084
7984
|
const marketData = useMarketDataPayload();
|
|
7085
7985
|
const isLoading = useMemo(() => !marketData && isConnected, [marketData, isConnected]);
|
|
7086
7986
|
const toggle = async (longAssets, shortAssets) => {
|
|
7087
|
-
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets,
|
|
7987
|
+
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets, hip3Assets);
|
|
7088
7988
|
// Server will push updated market-data over WS; nothing to set here
|
|
7089
7989
|
return resp;
|
|
7090
7990
|
};
|
|
@@ -7206,46 +8106,38 @@ async function logout(baseUrl, refreshTokenVal) {
|
|
|
7206
8106
|
function useAuth() {
|
|
7207
8107
|
const context = useContext(PearHyperliquidContext);
|
|
7208
8108
|
if (!context) {
|
|
7209
|
-
throw new Error("
|
|
8109
|
+
throw new Error("usePortfolio must be used within a PearHyperliquidProvider");
|
|
7210
8110
|
}
|
|
7211
8111
|
const { apiBaseUrl, clientId } = context;
|
|
8112
|
+
const [isReady, setIsReady] = useState(false);
|
|
7212
8113
|
const accessToken = useUserData((s) => s.accessToken);
|
|
7213
8114
|
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);
|
|
7217
8115
|
const setAccessToken = useUserData((s) => s.setAccessToken);
|
|
7218
8116
|
const setRefreshToken = useUserData((s) => s.setRefreshToken);
|
|
7219
|
-
const
|
|
8117
|
+
const isAuthenticated = useUserData((s) => s.isAuthenticated);
|
|
7220
8118
|
const setIsAuthenticated = useUserData((s) => s.setIsAuthenticated);
|
|
7221
8119
|
const setAddress = useUserData((s) => s.setAddress);
|
|
7222
8120
|
useEffect(() => {
|
|
7223
8121
|
if (typeof window == "undefined") {
|
|
7224
8122
|
return;
|
|
7225
8123
|
}
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
setAccessToken(storedAccessToken);
|
|
7235
|
-
setRefreshToken(storedRefreshToken);
|
|
7236
|
-
setIsAuthenticated(true);
|
|
7237
|
-
}
|
|
7238
|
-
}
|
|
8124
|
+
const access = localStorage.getItem("accessToken");
|
|
8125
|
+
const refresh = localStorage.getItem("refreshToken");
|
|
8126
|
+
const addr = localStorage.getItem("address");
|
|
8127
|
+
setAccessToken(access);
|
|
8128
|
+
setRefreshToken(refresh);
|
|
8129
|
+
setAddress(addr);
|
|
8130
|
+
const authed = Boolean(access && addr);
|
|
8131
|
+
setIsAuthenticated(authed);
|
|
7239
8132
|
setIsReady(true);
|
|
7240
|
-
}, [
|
|
8133
|
+
}, [setAccessToken, setRefreshToken, setIsAuthenticated, setAddress]);
|
|
7241
8134
|
useEffect(() => {
|
|
7242
8135
|
const cleanup = addAuthInterceptors({
|
|
7243
8136
|
apiBaseUrl,
|
|
7244
8137
|
getAccessToken: () => {
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
return useUserData.getState().accessToken;
|
|
8138
|
+
return typeof window !== "undefined"
|
|
8139
|
+
? window.localStorage.getItem("accessToken")
|
|
8140
|
+
: null;
|
|
7249
8141
|
},
|
|
7250
8142
|
refreshTokens: async () => {
|
|
7251
8143
|
const data = await refreshTokens();
|
|
@@ -7271,12 +8163,12 @@ function useAuth() {
|
|
|
7271
8163
|
clientId,
|
|
7272
8164
|
details: { signature, timestamp },
|
|
7273
8165
|
});
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
window.localStorage.setItem(
|
|
7277
|
-
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
8166
|
+
window.localStorage.setItem("accessToken", data.accessToken);
|
|
8167
|
+
window.localStorage.setItem("refreshToken", data.refreshToken);
|
|
8168
|
+
window.localStorage.setItem("address", address);
|
|
7278
8169
|
setAccessToken(data.accessToken);
|
|
7279
8170
|
setRefreshToken(data.refreshToken);
|
|
8171
|
+
setAddress(address);
|
|
7280
8172
|
setIsAuthenticated(true);
|
|
7281
8173
|
}
|
|
7282
8174
|
catch (e) {
|
|
@@ -7291,12 +8183,12 @@ function useAuth() {
|
|
|
7291
8183
|
appId,
|
|
7292
8184
|
accessToken: privyAccessToken,
|
|
7293
8185
|
});
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
window.localStorage.setItem(
|
|
7297
|
-
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
8186
|
+
window.localStorage.setItem("accessToken", data.accessToken);
|
|
8187
|
+
window.localStorage.setItem("refreshToken", data.refreshToken);
|
|
8188
|
+
window.localStorage.setItem("address", address);
|
|
7298
8189
|
setAccessToken(data.accessToken);
|
|
7299
8190
|
setRefreshToken(data.refreshToken);
|
|
8191
|
+
setAddress(address);
|
|
7300
8192
|
setIsAuthenticated(true);
|
|
7301
8193
|
}
|
|
7302
8194
|
catch (e) {
|
|
@@ -7304,38 +8196,30 @@ function useAuth() {
|
|
|
7304
8196
|
}
|
|
7305
8197
|
}
|
|
7306
8198
|
async function refreshTokens() {
|
|
7307
|
-
const
|
|
7308
|
-
|
|
7309
|
-
if (!currentRefresh || !currentAddress)
|
|
8199
|
+
const refresh = window.localStorage.getItem("refreshToken");
|
|
8200
|
+
if (!refresh)
|
|
7310
8201
|
throw new Error("No refresh token");
|
|
7311
|
-
const { data } = await refreshToken(apiBaseUrl,
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
const refreshTokenKey = `${currentAddress}_refreshToken`;
|
|
7315
|
-
window.localStorage.setItem(accessTokenKey, data.accessToken);
|
|
7316
|
-
window.localStorage.setItem(refreshTokenKey, data.refreshToken);
|
|
8202
|
+
const { data } = await refreshToken(apiBaseUrl, refresh);
|
|
8203
|
+
window.localStorage.setItem("accessToken", data.accessToken);
|
|
8204
|
+
window.localStorage.setItem("refreshToken", data.refreshToken);
|
|
7317
8205
|
setAccessToken(data.accessToken);
|
|
7318
8206
|
setRefreshToken(data.refreshToken);
|
|
7319
8207
|
setIsAuthenticated(true);
|
|
7320
8208
|
return data;
|
|
7321
8209
|
}
|
|
7322
8210
|
async function logout$1() {
|
|
7323
|
-
const
|
|
7324
|
-
|
|
7325
|
-
if (currentRefresh) {
|
|
8211
|
+
const refresh = window.localStorage.getItem("refreshToken");
|
|
8212
|
+
if (refresh) {
|
|
7326
8213
|
try {
|
|
7327
|
-
await logout(apiBaseUrl,
|
|
8214
|
+
await logout(apiBaseUrl, refresh);
|
|
7328
8215
|
}
|
|
7329
8216
|
catch (_a) {
|
|
7330
8217
|
/* ignore */
|
|
7331
8218
|
}
|
|
7332
8219
|
}
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
window.localStorage.removeItem(accessTokenKey);
|
|
7337
|
-
window.localStorage.removeItem(refreshTokenKey);
|
|
7338
|
-
}
|
|
8220
|
+
window.localStorage.removeItem("accessToken");
|
|
8221
|
+
window.localStorage.removeItem("refreshToken");
|
|
8222
|
+
window.localStorage.removeItem("address");
|
|
7339
8223
|
setAccessToken(null);
|
|
7340
8224
|
setRefreshToken(null);
|
|
7341
8225
|
setAddress(null);
|
|
@@ -7351,20 +8235,114 @@ function useAuth() {
|
|
|
7351
8235
|
loginWithPrivyToken,
|
|
7352
8236
|
refreshTokens,
|
|
7353
8237
|
logout: logout$1,
|
|
7354
|
-
setAddress,
|
|
7355
|
-
address,
|
|
7356
8238
|
};
|
|
7357
8239
|
}
|
|
7358
8240
|
|
|
8241
|
+
const useAllUserBalances = () => {
|
|
8242
|
+
const spotState = useUserData((state) => state.spotState);
|
|
8243
|
+
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
8244
|
+
const rawClearinghouseStates = useHyperliquidData((state) => state.rawClearinghouseStates);
|
|
8245
|
+
const activeAssetData = useHyperliquidData((state) => state.activeAssetData);
|
|
8246
|
+
const { longTokensMetadata, shortTokensMetadata } = useTokenSelectionMetadata();
|
|
8247
|
+
return useMemo(() => {
|
|
8248
|
+
const isLoading = !spotState || !aggregatedClearingHouseState;
|
|
8249
|
+
// Helper function to truncate to 2 decimal places without rounding
|
|
8250
|
+
const truncateToTwoDecimals = (value) => {
|
|
8251
|
+
return Math.floor(value * 100) / 100;
|
|
8252
|
+
};
|
|
8253
|
+
// Get spot balances from spotState
|
|
8254
|
+
let spotUsdcBal = undefined;
|
|
8255
|
+
let spotUsdhBal = undefined;
|
|
8256
|
+
if (spotState) {
|
|
8257
|
+
const balances = spotState.balances || [];
|
|
8258
|
+
for (const balance of balances) {
|
|
8259
|
+
const total = parseFloat(balance.total || '0');
|
|
8260
|
+
if (balance.coin === 'USDC') {
|
|
8261
|
+
spotUsdcBal = truncateToTwoDecimals(total);
|
|
8262
|
+
}
|
|
8263
|
+
if (balance.coin === 'USDH') {
|
|
8264
|
+
spotUsdhBal = truncateToTwoDecimals(total);
|
|
8265
|
+
}
|
|
8266
|
+
}
|
|
8267
|
+
}
|
|
8268
|
+
let availableToTradeUsdhFromAsset = 0;
|
|
8269
|
+
// This activeAssetData only contains data for SELECTED tokens (user's long and short Tokens)
|
|
8270
|
+
// It does NOT contain data for all tokens, so we cannot reliably use it for available to trade as used on hl trade page
|
|
8271
|
+
// so intead, we rely on rawClearinghouseStates which provides market-specific data
|
|
8272
|
+
// if (activeAssetData) {
|
|
8273
|
+
// Object.values(activeAssetData).forEach((assetData) => {
|
|
8274
|
+
// if (!assetData.availableToTrade) return;
|
|
8275
|
+
// const coinSymbol = assetData.coin;
|
|
8276
|
+
// const availableValue = truncateToTwoDecimals(
|
|
8277
|
+
// parseFloat(assetData.availableToTrade[0] || '0'),
|
|
8278
|
+
// );
|
|
8279
|
+
// // Determine collateral type based on market prefix
|
|
8280
|
+
// // HIP3 markets have prefix: "xyz:SYMBOL", "flx:SYMBOL", "vntl:SYMBOL", etc.
|
|
8281
|
+
// if (coinSymbol.includes(':')) {
|
|
8282
|
+
// const prefix = coinSymbol.split(':')[0];
|
|
8283
|
+
// if (prefix === 'xyz') {
|
|
8284
|
+
// // xyz markets use USDC
|
|
8285
|
+
// availableToTradeUsdcFromAsset = availableValue;
|
|
8286
|
+
// } else {
|
|
8287
|
+
// // flx, vntl, hyna and other markets use USDH
|
|
8288
|
+
// availableToTradeUsdhFromAsset = availableValue;
|
|
8289
|
+
// }
|
|
8290
|
+
// } else {
|
|
8291
|
+
// // Regular markets without prefix are automatically USDC
|
|
8292
|
+
// availableToTradeUsdcFromAsset = availableValue;
|
|
8293
|
+
// }
|
|
8294
|
+
// });
|
|
8295
|
+
// }
|
|
8296
|
+
// Calculate USDC available to trade
|
|
8297
|
+
// Priority 1: Use value from activeAssetData if available (> 0)
|
|
8298
|
+
// Priority 2: Calculate from USDC-specific clearinghouseState (empty prefix)
|
|
8299
|
+
let availableToTradeUsdcValue = undefined;
|
|
8300
|
+
if (rawClearinghouseStates) {
|
|
8301
|
+
// Find USDC market (empty prefix)
|
|
8302
|
+
const usdcMarket = rawClearinghouseStates.find(([prefix]) => prefix === '');
|
|
8303
|
+
const usdcState = usdcMarket === null || usdcMarket === void 0 ? void 0 : usdcMarket[1];
|
|
8304
|
+
if (usdcState === null || usdcState === void 0 ? void 0 : usdcState.marginSummary) {
|
|
8305
|
+
const accountValue = parseFloat(usdcState.marginSummary.accountValue || '0');
|
|
8306
|
+
const totalMarginUsed = parseFloat(usdcState.marginSummary.totalMarginUsed || '0');
|
|
8307
|
+
const calculatedValue = Math.max(0, accountValue - totalMarginUsed);
|
|
8308
|
+
availableToTradeUsdcValue = truncateToTwoDecimals(calculatedValue);
|
|
8309
|
+
}
|
|
8310
|
+
}
|
|
8311
|
+
// Calculate USDH available to trade
|
|
8312
|
+
// Priority 1: Use value from activeAssetData if available (> 0)
|
|
8313
|
+
// Priority 2: Use spot USDH balance
|
|
8314
|
+
const availableToTradeUsdhValue = availableToTradeUsdhFromAsset > 0
|
|
8315
|
+
? availableToTradeUsdhFromAsset
|
|
8316
|
+
: spotUsdhBal;
|
|
8317
|
+
return {
|
|
8318
|
+
spotUsdcBalance: spotUsdcBal,
|
|
8319
|
+
availableToTradeUsdc: availableToTradeUsdcValue,
|
|
8320
|
+
spotUsdhBalance: spotUsdhBal,
|
|
8321
|
+
availableToTradeUsdh: availableToTradeUsdhValue,
|
|
8322
|
+
isLoading,
|
|
8323
|
+
};
|
|
8324
|
+
}, [
|
|
8325
|
+
spotState,
|
|
8326
|
+
aggregatedClearingHouseState,
|
|
8327
|
+
rawClearinghouseStates,
|
|
8328
|
+
activeAssetData,
|
|
8329
|
+
longTokensMetadata,
|
|
8330
|
+
shortTokensMetadata,
|
|
8331
|
+
]);
|
|
8332
|
+
};
|
|
8333
|
+
|
|
7359
8334
|
const PearHyperliquidContext = createContext(undefined);
|
|
7360
8335
|
/**
|
|
7361
8336
|
* React Provider for PearHyperliquidClient
|
|
7362
8337
|
*/
|
|
7363
|
-
const PearHyperliquidProvider = ({ children, apiBaseUrl =
|
|
8338
|
+
const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearprotocol.io', clientId = 'PEARPROTOCOLUI', wsUrl = 'wss://hl-ui.pearprotocol.io/ws', }) => {
|
|
7364
8339
|
const address = useUserData((s) => s.address);
|
|
8340
|
+
const setAddress = useUserData((s) => s.setAddress);
|
|
7365
8341
|
const perpsMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
7366
8342
|
const setPerpMetaAssets = useHyperliquidData((state) => state.setPerpMetaAssets);
|
|
7367
|
-
const
|
|
8343
|
+
const setAllPerpMetaAssets = useHyperliquidData((state) => state.setAllPerpMetaAssets);
|
|
8344
|
+
const setHip3Assets = useHyperliquidData((state) => state.setHip3Assets);
|
|
8345
|
+
const setHip3MarketPrefixes = useHyperliquidData((state) => state.setHip3MarketPrefixes);
|
|
7368
8346
|
const websocketsEnabled = useMemo(() => Array.isArray(perpsMetaAssets) && perpsMetaAssets.length > 0, [perpsMetaAssets]);
|
|
7369
8347
|
const { isConnected, lastError } = useHyperliquidWebSocket({
|
|
7370
8348
|
wsUrl,
|
|
@@ -7379,32 +8357,107 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
|
|
|
7379
8357
|
if (perpsMetaAssets === null) {
|
|
7380
8358
|
fetchAllPerpMetas()
|
|
7381
8359
|
.then((res) => {
|
|
7382
|
-
|
|
7383
|
-
const
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
const
|
|
7388
|
-
const
|
|
7389
|
-
|
|
7390
|
-
const
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
const
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
8360
|
+
const assetToMarkets = new Map();
|
|
8361
|
+
const marketPrefixes = new Map();
|
|
8362
|
+
const FILTERED_PREFIXES = ['hyna'];
|
|
8363
|
+
// Group assets by market prefix to match WebSocket flattening order
|
|
8364
|
+
// WebSocket sends in order: "", "flx", "hyna", "vntl", "xyz" (we filter out hyna)
|
|
8365
|
+
const assetsByPrefix = new Map();
|
|
8366
|
+
const allAssetsByPrefix = new Map();
|
|
8367
|
+
res.data.forEach((item) => {
|
|
8368
|
+
const collateralToken = item.collateralToken === 360 ? 'USDH' : 'USDC';
|
|
8369
|
+
item.universe.forEach((asset) => {
|
|
8370
|
+
var _a;
|
|
8371
|
+
const [maybePrefix, maybeMarket] = asset.name.split(':');
|
|
8372
|
+
if (maybeMarket) {
|
|
8373
|
+
// HIP3 asset with market prefix
|
|
8374
|
+
const prefix = maybePrefix.toLowerCase();
|
|
8375
|
+
const displayName = maybeMarket;
|
|
8376
|
+
const fullName = `${prefix}:${displayName}`;
|
|
8377
|
+
marketPrefixes.set(fullName, prefix);
|
|
8378
|
+
if (!FILTERED_PREFIXES.includes(prefix)) {
|
|
8379
|
+
const existingMarkets = (_a = assetToMarkets.get(displayName)) !== null && _a !== void 0 ? _a : [];
|
|
8380
|
+
if (!existingMarkets.includes(fullName)) {
|
|
8381
|
+
assetToMarkets.set(displayName, [
|
|
8382
|
+
...existingMarkets,
|
|
8383
|
+
fullName,
|
|
8384
|
+
]);
|
|
8385
|
+
}
|
|
8386
|
+
}
|
|
8387
|
+
const assetWithMeta = {
|
|
8388
|
+
...asset,
|
|
8389
|
+
name: displayName,
|
|
8390
|
+
marketPrefix: prefix,
|
|
8391
|
+
collateralToken,
|
|
8392
|
+
};
|
|
8393
|
+
// Group by market prefix
|
|
8394
|
+
const allList = allAssetsByPrefix.get(prefix) || [];
|
|
8395
|
+
allList.push(assetWithMeta);
|
|
8396
|
+
allAssetsByPrefix.set(prefix, allList);
|
|
8397
|
+
if (!FILTERED_PREFIXES.includes(prefix)) {
|
|
8398
|
+
const cleanedList = assetsByPrefix.get(prefix) || [];
|
|
8399
|
+
cleanedList.push(assetWithMeta);
|
|
8400
|
+
assetsByPrefix.set(prefix, cleanedList);
|
|
8401
|
+
}
|
|
8402
|
+
}
|
|
8403
|
+
else {
|
|
8404
|
+
// Default market asset (no prefix)
|
|
8405
|
+
const assetWithMeta = {
|
|
8406
|
+
...asset,
|
|
8407
|
+
collateralToken,
|
|
8408
|
+
};
|
|
8409
|
+
// Add to default market group ("")
|
|
8410
|
+
const defaultList = assetsByPrefix.get('') || [];
|
|
8411
|
+
defaultList.push(assetWithMeta);
|
|
8412
|
+
assetsByPrefix.set('', defaultList);
|
|
8413
|
+
const allDefaultList = allAssetsByPrefix.get('') || [];
|
|
8414
|
+
allDefaultList.push(assetWithMeta);
|
|
8415
|
+
allAssetsByPrefix.set('', allDefaultList);
|
|
8416
|
+
}
|
|
8417
|
+
});
|
|
8418
|
+
});
|
|
8419
|
+
// Flatten in consistent order: default market first, then HIP3 markets alphabetically
|
|
8420
|
+
// This ensures both REST API and WebSocket data align properly
|
|
8421
|
+
const cleanedPrefixes = Array.from(assetsByPrefix.keys()).sort((a, b) => {
|
|
8422
|
+
// Empty prefix (default market) always comes first
|
|
8423
|
+
if (a === '' && b !== '')
|
|
8424
|
+
return -1;
|
|
8425
|
+
if (a !== '' && b === '')
|
|
8426
|
+
return 1;
|
|
8427
|
+
// HIP3 markets sorted alphabetically
|
|
8428
|
+
return a.localeCompare(b);
|
|
8429
|
+
});
|
|
8430
|
+
const allPrefixes = Array.from(allAssetsByPrefix.keys()).sort((a, b) => {
|
|
8431
|
+
if (a === '' && b !== '')
|
|
8432
|
+
return -1;
|
|
8433
|
+
if (a !== '' && b === '')
|
|
8434
|
+
return 1;
|
|
8435
|
+
return a.localeCompare(b);
|
|
8436
|
+
});
|
|
8437
|
+
const cleanedPerpMetas = [];
|
|
8438
|
+
const allPerpMetas = [];
|
|
8439
|
+
cleanedPrefixes.forEach((prefix) => {
|
|
8440
|
+
const assets = assetsByPrefix.get(prefix) || [];
|
|
8441
|
+
cleanedPerpMetas.push(...assets);
|
|
7400
8442
|
});
|
|
7401
|
-
|
|
8443
|
+
allPrefixes.forEach((prefix) => {
|
|
8444
|
+
const assets = allAssetsByPrefix.get(prefix) || [];
|
|
8445
|
+
allPerpMetas.push(...assets);
|
|
8446
|
+
});
|
|
8447
|
+
setHip3Assets(assetToMarkets);
|
|
8448
|
+
setHip3MarketPrefixes(marketPrefixes);
|
|
7402
8449
|
setPerpMetaAssets(cleanedPerpMetas);
|
|
8450
|
+
setAllPerpMetaAssets(allPerpMetas);
|
|
7403
8451
|
})
|
|
7404
8452
|
.catch(() => { });
|
|
7405
8453
|
}
|
|
7406
|
-
}, [
|
|
7407
|
-
|
|
8454
|
+
}, [
|
|
8455
|
+
perpsMetaAssets,
|
|
8456
|
+
setPerpMetaAssets,
|
|
8457
|
+
setAllPerpMetaAssets,
|
|
8458
|
+
setHip3Assets,
|
|
8459
|
+
setHip3MarketPrefixes,
|
|
8460
|
+
]);
|
|
7408
8461
|
useAutoSyncFills({
|
|
7409
8462
|
baseUrl: apiBaseUrl,
|
|
7410
8463
|
address,
|
|
@@ -7426,6 +8479,8 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
|
|
|
7426
8479
|
}), [
|
|
7427
8480
|
apiBaseUrl,
|
|
7428
8481
|
wsUrl,
|
|
8482
|
+
address,
|
|
8483
|
+
setAddress,
|
|
7429
8484
|
isConnected,
|
|
7430
8485
|
lastError,
|
|
7431
8486
|
nativeIsConnected,
|
|
@@ -7440,7 +8495,7 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = "https://hl-ui.pearpro
|
|
|
7440
8495
|
function usePearHyperliquid() {
|
|
7441
8496
|
const ctx = useContext(PearHyperliquidContext);
|
|
7442
8497
|
if (!ctx)
|
|
7443
|
-
throw new Error(
|
|
8498
|
+
throw new Error('usePearHyperliquid must be used within a PearHyperliquidProvider');
|
|
7444
8499
|
return ctx;
|
|
7445
8500
|
}
|
|
7446
8501
|
|
|
@@ -7531,4 +8586,4 @@ function mapCandleIntervalToTradingViewInterval(interval) {
|
|
|
7531
8586
|
}
|
|
7532
8587
|
}
|
|
7533
8588
|
|
|
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 };
|
|
8589
|
+
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, executeSpotOrder, getAvailableMarkets, getCompleteTimestamps, getMarketPrefix, getPortfolio, isHip3Market, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toBackendSymbol, toBackendSymbolWithMarket, toDisplaySymbol, toggleWatchlist, updateLeverage, updateRiskParameters, useAccountSummary, useActiveBaskets, useAgentWallet, useAllBaskets, useAllUserBalances, useAuth, useAutoSyncFills, useBasketCandles, useFindBasket, useHighlightedBaskets, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMarketData, useMarketDataAllPayload, useMarketDataPayload, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePerpMetaAssets, usePortfolio, usePosition, useSpotOrder, useTokenSelectionMetadata, useTopGainers, useTopLosers, useTradeHistories, useTwap, useUserSelection, useWatchlist, useWatchlistBaskets, useWebData, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
|