@pear-protocol/hyperliquid-sdk 0.0.79 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1141 -0
- package/dist/clients/hyperliquid.d.ts +9 -2
- package/dist/clients/positions.d.ts +2 -2
- package/dist/clients/watchlist.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/useMarket.d.ts +8 -0
- package/dist/hooks/useMarketData.d.ts +1 -4
- package/dist/hooks/useTrading.d.ts +1 -2
- package/dist/index.d.ts +35 -139
- package/dist/index.js +594 -1218
- package/dist/store/hyperliquidDataStore.d.ts +9 -7
- package/dist/store/marketDataStore.d.ts +1 -3
- package/dist/store/tokenSelectionMetadataStore.d.ts +2 -4
- package/dist/types.d.ts +28 -32
- package/dist/utils/market-symbol.d.ts +5 -0
- package/dist/utils/position-processor.d.ts +2 -2
- package/dist/utils/token-metadata-extractor.d.ts +35 -24
- package/dist/utils/token-metadata-selectors.d.ts +4 -0
- package/package.json +1 -1
- package/dist/hooks/useWebData.d.ts +0 -30
- package/dist/utils/symbol-translator.d.ts +0 -40
package/dist/index.js
CHANGED
|
@@ -105,84 +105,9 @@ const useMarketData = create((set) => ({
|
|
|
105
105
|
marketData: null,
|
|
106
106
|
marketDataAll: null,
|
|
107
107
|
setMarketData: (value) => set({ marketData: value }),
|
|
108
|
-
|
|
109
|
-
clean: () => set({ marketData: null, marketDataAll: null }),
|
|
108
|
+
clean: () => set({ marketData: null }),
|
|
110
109
|
}));
|
|
111
110
|
|
|
112
|
-
// Utilities for translating between display symbols and backend (prefixed) symbols
|
|
113
|
-
/**
|
|
114
|
-
* Convert a full/prefixed symbol (e.g., "xyz:XYZ100") to a display symbol (e.g., "XYZ100").
|
|
115
|
-
*/
|
|
116
|
-
function toDisplaySymbol(symbol) {
|
|
117
|
-
const parts = symbol.split(":");
|
|
118
|
-
return parts.length > 1 ? parts.slice(-1)[0] : symbol;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Convert a display symbol back to backend form using a provided map.
|
|
122
|
-
* If mapping is missing, returns the original symbol.
|
|
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
|
-
if (displaySymbol === "BTC")
|
|
129
|
-
return "BTC";
|
|
130
|
-
const markets = hip3Assets.get(displaySymbol);
|
|
131
|
-
// Return first market if available, otherwise return original symbol
|
|
132
|
-
return markets && markets.length > 0 ? markets[0] : displaySymbol;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Convert a display symbol to backend form for a specific market prefix.
|
|
136
|
-
* This is useful when an asset is available on multiple markets (e.g., xyz:TSLA and flx:TSLA).
|
|
137
|
-
* @param displaySymbol e.g., "TSLA"
|
|
138
|
-
* @param marketPrefix e.g., "xyz" or "flx"
|
|
139
|
-
* @param hip3Assets map of display -> all full market names
|
|
140
|
-
* @returns Full market name if found, null if prefix not specified for multi-market asset, otherwise displaySymbol with prefix
|
|
141
|
-
*/
|
|
142
|
-
function toBackendSymbolWithMarket(displaySymbol, marketPrefix, hip3Assets) {
|
|
143
|
-
const availableMarkets = hip3Assets.get(displaySymbol);
|
|
144
|
-
if (!availableMarkets || availableMarkets.length === 0) {
|
|
145
|
-
// Not a HIP-3 asset, return as-is or with prefix if provided
|
|
146
|
-
return marketPrefix ? `${marketPrefix}:${displaySymbol}` : displaySymbol;
|
|
147
|
-
}
|
|
148
|
-
if (marketPrefix) {
|
|
149
|
-
// Find the market with the specified prefix
|
|
150
|
-
const targetMarket = availableMarkets.find((market) => market.toLowerCase().startsWith(`${marketPrefix.toLowerCase()}:`));
|
|
151
|
-
if (targetMarket) {
|
|
152
|
-
return targetMarket;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
// No prefix specified or not found, return null to force explicit market selection
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Get all available markets for a display symbol.
|
|
160
|
-
* @param displaySymbol e.g., "TSLA"
|
|
161
|
-
* @param hip3Assets map of display -> all full market names
|
|
162
|
-
* @returns Array of full market names, e.g., ["xyz:TSLA", "flx:TSLA"]
|
|
163
|
-
*/
|
|
164
|
-
function getAvailableMarkets(displaySymbol, hip3Assets) {
|
|
165
|
-
var _a;
|
|
166
|
-
return (_a = hip3Assets.get(displaySymbol)) !== null && _a !== void 0 ? _a : [];
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Extract the market prefix from a full market name.
|
|
170
|
-
* @param fullSymbol e.g., "xyz:TSLA"
|
|
171
|
-
* @returns The prefix (e.g., "xyz") or undefined if no prefix
|
|
172
|
-
*/
|
|
173
|
-
function getMarketPrefix(fullSymbol) {
|
|
174
|
-
const parts = fullSymbol.split(":");
|
|
175
|
-
return parts.length > 1 ? parts[0] : undefined;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Check if a symbol is a HIP-3 market (has a prefix).
|
|
179
|
-
* @param symbol e.g., "xyz:TSLA" or "TSLA"
|
|
180
|
-
* @returns true if the symbol has a market prefix
|
|
181
|
-
*/
|
|
182
|
-
function isHip3Market(symbol) {
|
|
183
|
-
return symbol.includes(":");
|
|
184
|
-
}
|
|
185
|
-
|
|
186
111
|
const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
187
112
|
const { setTradeHistories, setRawOpenPositions, setOpenOrders, setAccountSummary, setTwapDetails, setNotifications, clean, } = useUserData();
|
|
188
113
|
const { setMarketData } = useMarketData();
|
|
@@ -217,60 +142,19 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
217
142
|
switch (dataMessage.channel) {
|
|
218
143
|
case 'trade-histories':
|
|
219
144
|
{
|
|
220
|
-
const
|
|
221
|
-
var _a, _b;
|
|
222
|
-
const extractedPrefix = getMarketPrefix(a.coin);
|
|
223
|
-
return {
|
|
224
|
-
...a,
|
|
225
|
-
coin: toDisplaySymbol(a.coin),
|
|
226
|
-
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
227
|
-
};
|
|
228
|
-
};
|
|
229
|
-
const list = dataMessage.data.map((item) => {
|
|
230
|
-
var _a, _b;
|
|
231
|
-
return ({
|
|
232
|
-
...item,
|
|
233
|
-
closedLongAssets: item.closedLongAssets.map(mapAsset),
|
|
234
|
-
closedShortAssets: item.closedShortAssets.map(mapAsset),
|
|
235
|
-
positionLongAssets: (_a = item.positionLongAssets) === null || _a === void 0 ? void 0 : _a.map((a) => toDisplaySymbol(a)),
|
|
236
|
-
positionShortAssets: (_b = item.positionShortAssets) === null || _b === void 0 ? void 0 : _b.map((a) => toDisplaySymbol(a)),
|
|
237
|
-
});
|
|
238
|
-
});
|
|
145
|
+
const list = dataMessage.data;
|
|
239
146
|
setTradeHistories(list);
|
|
240
147
|
}
|
|
241
148
|
break;
|
|
242
149
|
case 'open-positions':
|
|
243
150
|
{
|
|
244
|
-
const
|
|
245
|
-
var _a, _b;
|
|
246
|
-
const extractedPrefix = getMarketPrefix(a.coin);
|
|
247
|
-
return {
|
|
248
|
-
...a,
|
|
249
|
-
coin: toDisplaySymbol(a.coin),
|
|
250
|
-
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
251
|
-
};
|
|
252
|
-
};
|
|
253
|
-
const list = dataMessage.data.map((pos) => ({
|
|
254
|
-
...pos,
|
|
255
|
-
longAssets: pos.longAssets.map(enrichAsset),
|
|
256
|
-
shortAssets: pos.shortAssets.map(enrichAsset),
|
|
257
|
-
}));
|
|
151
|
+
const list = dataMessage.data;
|
|
258
152
|
setRawOpenPositions(list);
|
|
259
153
|
}
|
|
260
154
|
break;
|
|
261
155
|
case 'open-orders':
|
|
262
156
|
{
|
|
263
|
-
const list = dataMessage.data
|
|
264
|
-
...order,
|
|
265
|
-
longAssets: order.longAssets.map((a) => ({
|
|
266
|
-
...a,
|
|
267
|
-
asset: toDisplaySymbol(a.asset),
|
|
268
|
-
})),
|
|
269
|
-
shortAssets: order.shortAssets.map((a) => ({
|
|
270
|
-
...a,
|
|
271
|
-
asset: toDisplaySymbol(a.asset),
|
|
272
|
-
})),
|
|
273
|
-
}));
|
|
157
|
+
const list = dataMessage.data;
|
|
274
158
|
setOpenOrders(list);
|
|
275
159
|
}
|
|
276
160
|
break;
|
|
@@ -279,21 +163,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
279
163
|
break;
|
|
280
164
|
case 'twap-details':
|
|
281
165
|
{
|
|
282
|
-
const
|
|
283
|
-
var _a, _b, _c;
|
|
284
|
-
const extractedPrefix = getMarketPrefix(a.asset);
|
|
285
|
-
return {
|
|
286
|
-
...a,
|
|
287
|
-
asset: toDisplaySymbol(a.asset),
|
|
288
|
-
marketPrefix: (_b = (_a = a.marketPrefix) !== null && _a !== void 0 ? _a : extractedPrefix) !== null && _b !== void 0 ? _b : null,
|
|
289
|
-
collateralToken: (_c = a.collateralToken) !== null && _c !== void 0 ? _c : undefined,
|
|
290
|
-
};
|
|
291
|
-
};
|
|
292
|
-
const list = dataMessage.data.map((twap) => ({
|
|
293
|
-
...twap,
|
|
294
|
-
longAssets: twap.longAssets.map(mapTwapAsset),
|
|
295
|
-
shortAssets: twap.shortAssets.map(mapTwapAsset),
|
|
296
|
-
}));
|
|
166
|
+
const list = dataMessage.data;
|
|
297
167
|
setTwapDetails(list);
|
|
298
168
|
}
|
|
299
169
|
break;
|
|
@@ -303,25 +173,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
303
173
|
case 'market-data':
|
|
304
174
|
{
|
|
305
175
|
const md = dataMessage.data;
|
|
306
|
-
|
|
307
|
-
...g,
|
|
308
|
-
longAssets: g.longAssets.map((a) => ({
|
|
309
|
-
...a,
|
|
310
|
-
asset: toDisplaySymbol(a.asset),
|
|
311
|
-
})),
|
|
312
|
-
shortAssets: g.shortAssets.map((a) => ({
|
|
313
|
-
...a,
|
|
314
|
-
asset: toDisplaySymbol(a.asset),
|
|
315
|
-
})),
|
|
316
|
-
});
|
|
317
|
-
const mapped = {
|
|
318
|
-
active: md.active.map(mapGroup),
|
|
319
|
-
topGainers: md.topGainers.map(mapGroup),
|
|
320
|
-
topLosers: md.topLosers.map(mapGroup),
|
|
321
|
-
highlighted: md.highlighted.map(mapGroup),
|
|
322
|
-
watchlist: md.watchlist.map(mapGroup),
|
|
323
|
-
};
|
|
324
|
-
setMarketData(mapped);
|
|
176
|
+
setMarketData(md);
|
|
325
177
|
}
|
|
326
178
|
break;
|
|
327
179
|
}
|
|
@@ -457,7 +309,229 @@ const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
|
457
309
|
};
|
|
458
310
|
};
|
|
459
311
|
|
|
460
|
-
const
|
|
312
|
+
const getMarketInfoFromSymbol = (symbol) => {
|
|
313
|
+
const separatorIndex = symbol.indexOf(':');
|
|
314
|
+
if (separatorIndex > -1) {
|
|
315
|
+
const prefix = symbol.slice(0, separatorIndex);
|
|
316
|
+
const name = symbol.slice(separatorIndex + 1);
|
|
317
|
+
return {
|
|
318
|
+
symbolName: name || symbol,
|
|
319
|
+
marketName: prefix || '',
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
return { symbolName: symbol, marketName: '' };
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Check if two symbols match, handling kPEPE/KPEPE variations
|
|
327
|
+
* Returns true if symbols match (case-insensitive for k-prefix tokens)
|
|
328
|
+
*/
|
|
329
|
+
function symbolsMatch(assetName, searchSymbol) {
|
|
330
|
+
// Exact match
|
|
331
|
+
if (assetName === searchSymbol)
|
|
332
|
+
return true;
|
|
333
|
+
// Try case-insensitive match for k-prefix tokens (kPEPE vs KPEPE)
|
|
334
|
+
if (assetName.toUpperCase() === searchSymbol.toUpperCase()) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Extracts token metadata from aggregated WebData3 contexts and AllMids data
|
|
341
|
+
*/
|
|
342
|
+
class TokenMetadataExtractor {
|
|
343
|
+
/**
|
|
344
|
+
* Checks if token data is available in aggregated universe assets
|
|
345
|
+
* @param symbol - Token symbol
|
|
346
|
+
* @param perpMetaAssets - Aggregated universe assets
|
|
347
|
+
* @returns boolean indicating if token exists in universe
|
|
348
|
+
*/
|
|
349
|
+
static isTokenAvailable(symbol, perpMetaAssets) {
|
|
350
|
+
if (!perpMetaAssets)
|
|
351
|
+
return false;
|
|
352
|
+
return perpMetaAssets.some((asset) => symbolsMatch(asset.name, symbol));
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Extracts token metadata using DEX-aware lookup (correctly matches perpMetas to assetContexts)
|
|
356
|
+
* @param symbol - Token symbol (e.g., "BTC", "TSLA")
|
|
357
|
+
* @param perpMetasByDex - Map of DEX name to UniverseAsset[]
|
|
358
|
+
* @param assetContextsByDex - Map of DEX name to WebData3AssetCtx[]
|
|
359
|
+
* @param allMids - AllMids data containing current prices
|
|
360
|
+
* @param activeAssetData - Optional active asset data containing leverage information
|
|
361
|
+
* @param finalAtOICaps - Optional array of symbols at OI caps
|
|
362
|
+
* @returns TokenMetadata or null if token not found
|
|
363
|
+
*/
|
|
364
|
+
static extractTokenMetadataByDex(symbol, perpMetasByDex, assetContextsByDex, allMids, activeAssetData, finalAtOICaps) {
|
|
365
|
+
let foundDexName = null;
|
|
366
|
+
let foundAssetIndex = -1;
|
|
367
|
+
let foundAsset = null;
|
|
368
|
+
for (const [dexName, assets] of perpMetasByDex) {
|
|
369
|
+
const assetIndex = assets.findIndex((asset) => symbolsMatch(asset.name, symbol));
|
|
370
|
+
if (assetIndex !== -1) {
|
|
371
|
+
foundDexName = dexName;
|
|
372
|
+
foundAssetIndex = assetIndex;
|
|
373
|
+
foundAsset = assets[assetIndex];
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (!foundDexName || foundAssetIndex === -1 || !foundAsset) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
const dexContexts = assetContextsByDex.get(foundDexName);
|
|
381
|
+
const assetCtx = dexContexts === null || dexContexts === void 0 ? void 0 : dexContexts[foundAssetIndex];
|
|
382
|
+
if (!assetCtx) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
// Get current price - prefer assetCtx.midPx as it's already index-matched,
|
|
386
|
+
// fall back to allMids lookup if midPx is null
|
|
387
|
+
const actualSymbol = foundAsset.name;
|
|
388
|
+
let currentPrice = 0;
|
|
389
|
+
// Fallback: assetCtx.midPx (already properly indexed)
|
|
390
|
+
if (!currentPrice || isNaN(currentPrice)) {
|
|
391
|
+
const currentPriceStr = allMids.mids[actualSymbol] || allMids.mids[symbol];
|
|
392
|
+
currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
393
|
+
}
|
|
394
|
+
// Primary source: allMids lookup
|
|
395
|
+
if (assetCtx.midPx) {
|
|
396
|
+
currentPrice = parseFloat(assetCtx.midPx);
|
|
397
|
+
}
|
|
398
|
+
// Get previous day price
|
|
399
|
+
const prevDayPrice = parseFloat(assetCtx.prevDayPx);
|
|
400
|
+
// Calculate 24h price change
|
|
401
|
+
const priceChange24h = currentPrice - prevDayPrice;
|
|
402
|
+
const priceChange24hPercent = prevDayPrice !== 0 ? (priceChange24h / prevDayPrice) * 100 : 0;
|
|
403
|
+
// Parse other metadata
|
|
404
|
+
const netFunding = parseFloat(assetCtx.funding) * 100;
|
|
405
|
+
const markPrice = parseFloat(assetCtx.markPx);
|
|
406
|
+
const oraclePrice = parseFloat(assetCtx.oraclePx);
|
|
407
|
+
// Extract leverage info from activeAssetData if available
|
|
408
|
+
const tokenActiveData = (activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[actualSymbol]) || (activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[symbol]);
|
|
409
|
+
const leverage = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.leverage;
|
|
410
|
+
const maxTradeSzs = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.maxTradeSzs;
|
|
411
|
+
const availableToTrade = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.availableToTrade;
|
|
412
|
+
const { symbolName, marketName } = getMarketInfoFromSymbol(actualSymbol);
|
|
413
|
+
return {
|
|
414
|
+
assetName: foundAsset.name,
|
|
415
|
+
symbolName,
|
|
416
|
+
marketName,
|
|
417
|
+
isAtOiCaps: finalAtOICaps ? finalAtOICaps.includes(symbol) : false,
|
|
418
|
+
currentPrice,
|
|
419
|
+
prevDayPrice,
|
|
420
|
+
priceChange24h,
|
|
421
|
+
priceChange24hPercent,
|
|
422
|
+
netFunding,
|
|
423
|
+
maxLeverage: foundAsset.maxLeverage,
|
|
424
|
+
markPrice,
|
|
425
|
+
oraclePrice,
|
|
426
|
+
openInterest: assetCtx.openInterest,
|
|
427
|
+
dayVolume: assetCtx.dayNtlVlm,
|
|
428
|
+
leverage,
|
|
429
|
+
maxTradeSzs,
|
|
430
|
+
availableToTrade,
|
|
431
|
+
collateralToken: foundAsset.collateralToken,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
// Helper functions for token metadata
|
|
436
|
+
const buildOiCapSet = (finalAtOICaps) => new Set((finalAtOICaps !== null && finalAtOICaps !== void 0 ? finalAtOICaps : [])
|
|
437
|
+
.filter(Boolean)
|
|
438
|
+
.map((value) => value.toUpperCase()));
|
|
439
|
+
const isAtOiCaps = (assetName, oiCapSet) => oiCapSet.has(assetName.toUpperCase());
|
|
440
|
+
const applyMetadataContext = (symbol, metadata, oiCapSet) => {
|
|
441
|
+
if (!metadata)
|
|
442
|
+
return null;
|
|
443
|
+
const { symbolName, marketName } = getMarketInfoFromSymbol(symbol);
|
|
444
|
+
return {
|
|
445
|
+
...metadata,
|
|
446
|
+
symbolName,
|
|
447
|
+
marketName,
|
|
448
|
+
isAtOiCaps: isAtOiCaps(symbol, oiCapSet),
|
|
449
|
+
};
|
|
450
|
+
};
|
|
451
|
+
const applyOiCapsToMetadataMap = (tokenMetadata, finalAtOICaps) => {
|
|
452
|
+
if (!tokenMetadata || Object.keys(tokenMetadata).length === 0) {
|
|
453
|
+
return tokenMetadata;
|
|
454
|
+
}
|
|
455
|
+
const oiCapSet = buildOiCapSet(finalAtOICaps);
|
|
456
|
+
const next = {};
|
|
457
|
+
Object.entries(tokenMetadata).forEach(([symbol, metadata]) => {
|
|
458
|
+
next[symbol] = applyMetadataContext(symbol, metadata, oiCapSet);
|
|
459
|
+
});
|
|
460
|
+
return next;
|
|
461
|
+
};
|
|
462
|
+
const shouldSkipToken = (asset, oiCapSet) => {
|
|
463
|
+
if (asset.isDelisted)
|
|
464
|
+
return true;
|
|
465
|
+
if (isAtOiCaps(asset.name, oiCapSet))
|
|
466
|
+
return true;
|
|
467
|
+
return false;
|
|
468
|
+
};
|
|
469
|
+
const buildTokenMetadataMap = ({ perpMetasByDex, assetContextsByDex, allMids, activeAssetData, finalAtOICaps, }) => {
|
|
470
|
+
if (!perpMetasByDex || !assetContextsByDex || !allMids) {
|
|
471
|
+
return {};
|
|
472
|
+
}
|
|
473
|
+
const oiCapSet = buildOiCapSet(finalAtOICaps);
|
|
474
|
+
const metadataMap = {};
|
|
475
|
+
// Iterate through all DEXes and their assets
|
|
476
|
+
for (const [, assets] of perpMetasByDex) {
|
|
477
|
+
for (const asset of assets) {
|
|
478
|
+
if (shouldSkipToken(asset, oiCapSet)) {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
const symbol = asset.name;
|
|
482
|
+
const metadata = TokenMetadataExtractor.extractTokenMetadataByDex(symbol, perpMetasByDex, assetContextsByDex, allMids, activeAssetData, finalAtOICaps);
|
|
483
|
+
metadataMap[symbol] = applyMetadataContext(symbol, metadata, oiCapSet);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return metadataMap;
|
|
487
|
+
};
|
|
488
|
+
const updateTokenMetadataForSymbols = (prev, symbols, { perpMetasByDex, assetContextsByDex, allMids, activeAssetData, finalAtOICaps, }) => {
|
|
489
|
+
if (!perpMetasByDex || !assetContextsByDex || !allMids) {
|
|
490
|
+
return prev;
|
|
491
|
+
}
|
|
492
|
+
const oiCapSet = buildOiCapSet(finalAtOICaps);
|
|
493
|
+
const next = { ...prev };
|
|
494
|
+
symbols.forEach((symbol) => {
|
|
495
|
+
// Find asset in any DEX
|
|
496
|
+
let foundAsset;
|
|
497
|
+
for (const [, assets] of perpMetasByDex) {
|
|
498
|
+
foundAsset = assets.find((a) => a.name === symbol);
|
|
499
|
+
if (foundAsset)
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
if (foundAsset && shouldSkipToken(foundAsset, oiCapSet)) {
|
|
503
|
+
delete next[symbol];
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
next[symbol] = applyMetadataContext(symbol, TokenMetadataExtractor.extractTokenMetadataByDex(symbol, perpMetasByDex, assetContextsByDex, allMids, activeAssetData, finalAtOICaps), oiCapSet);
|
|
507
|
+
});
|
|
508
|
+
return next;
|
|
509
|
+
};
|
|
510
|
+
const refreshTokenMetadata = (state, overrides, options) => {
|
|
511
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
512
|
+
const inputs = {
|
|
513
|
+
perpMetaAssets: (_a = overrides.perpMetaAssets) !== null && _a !== void 0 ? _a : state.perpMetaAssets,
|
|
514
|
+
finalAssetContexts: (_b = overrides.finalAssetContexts) !== null && _b !== void 0 ? _b : state.finalAssetContexts,
|
|
515
|
+
allMids: (_c = overrides.allMids) !== null && _c !== void 0 ? _c : state.allMids,
|
|
516
|
+
activeAssetData: (_d = overrides.activeAssetData) !== null && _d !== void 0 ? _d : state.activeAssetData,
|
|
517
|
+
finalAtOICaps: (_e = overrides.finalAtOICaps) !== null && _e !== void 0 ? _e : state.finalAtOICaps,
|
|
518
|
+
// DEX-aware inputs
|
|
519
|
+
perpMetasByDex: (_f = overrides.perpMetasByDex) !== null && _f !== void 0 ? _f : state.perpMetasByDex,
|
|
520
|
+
assetContextsByDex: (_g = overrides.assetContextsByDex) !== null && _g !== void 0 ? _g : state.assetContextsByDex,
|
|
521
|
+
};
|
|
522
|
+
if (!inputs.perpMetasByDex || !inputs.assetContextsByDex || !inputs.allMids) {
|
|
523
|
+
return state.tokenMetadata;
|
|
524
|
+
}
|
|
525
|
+
if (options === null || options === void 0 ? void 0 : options.oiCapsOnly) {
|
|
526
|
+
return applyOiCapsToMetadataMap(state.tokenMetadata, inputs.finalAtOICaps);
|
|
527
|
+
}
|
|
528
|
+
if ((_h = options === null || options === void 0 ? void 0 : options.symbols) === null || _h === void 0 ? void 0 : _h.length) {
|
|
529
|
+
return updateTokenMetadataForSymbols(state.tokenMetadata, options.symbols, inputs);
|
|
530
|
+
}
|
|
531
|
+
return buildTokenMetadataMap(inputs);
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
const useHyperliquidData = create((set) => ({
|
|
461
535
|
allMids: null,
|
|
462
536
|
activeAssetData: null,
|
|
463
537
|
candleData: null,
|
|
@@ -466,21 +540,32 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
466
540
|
aggregatedClearingHouseState: null,
|
|
467
541
|
rawClearinghouseStates: null,
|
|
468
542
|
perpMetaAssets: null,
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
543
|
+
tokenMetadata: {},
|
|
544
|
+
perpDexs: null,
|
|
545
|
+
perpMetasByDex: null,
|
|
546
|
+
assetContextsByDex: null,
|
|
547
|
+
setAllMids: (value) => set((state) => ({
|
|
548
|
+
allMids: value,
|
|
549
|
+
tokenMetadata: refreshTokenMetadata(state, { allMids: value }),
|
|
475
550
|
})),
|
|
551
|
+
setActiveAssetData: (value) => set((state) => {
|
|
552
|
+
const activeAssetData = typeof value === 'function' ? value(state.activeAssetData) : value;
|
|
553
|
+
return {
|
|
554
|
+
activeAssetData,
|
|
555
|
+
tokenMetadata: refreshTokenMetadata(state, { activeAssetData }),
|
|
556
|
+
};
|
|
557
|
+
}),
|
|
476
558
|
deleteActiveAssetData: (key) => {
|
|
477
559
|
set((state) => {
|
|
478
560
|
if (!state.activeAssetData || !(key in state.activeAssetData)) {
|
|
479
|
-
return state;
|
|
561
|
+
return state;
|
|
480
562
|
}
|
|
481
|
-
const
|
|
482
|
-
delete
|
|
483
|
-
return {
|
|
563
|
+
const activeAssetData = { ...state.activeAssetData };
|
|
564
|
+
delete activeAssetData[key];
|
|
565
|
+
return {
|
|
566
|
+
activeAssetData,
|
|
567
|
+
tokenMetadata: refreshTokenMetadata(state, { activeAssetData }, { symbols: [key] }),
|
|
568
|
+
};
|
|
484
569
|
});
|
|
485
570
|
},
|
|
486
571
|
addCandleData(symbol, candle) {
|
|
@@ -502,20 +587,43 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
502
587
|
});
|
|
503
588
|
},
|
|
504
589
|
setCandleData: (value) => set({ candleData: value }),
|
|
505
|
-
upsertActiveAssetData: (key, value) => set((state) =>
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
590
|
+
upsertActiveAssetData: (key, value) => set((state) => {
|
|
591
|
+
var _a;
|
|
592
|
+
const activeAssetData = { ...((_a = state.activeAssetData) !== null && _a !== void 0 ? _a : {}), [key]: value };
|
|
593
|
+
return {
|
|
594
|
+
activeAssetData,
|
|
595
|
+
tokenMetadata: refreshTokenMetadata(state, { activeAssetData }, { symbols: [key] }),
|
|
596
|
+
};
|
|
597
|
+
}),
|
|
598
|
+
setFinalAssetContexts: (value) => set((state) => ({
|
|
599
|
+
finalAssetContexts: value,
|
|
600
|
+
tokenMetadata: refreshTokenMetadata(state, { finalAssetContexts: value }),
|
|
601
|
+
})),
|
|
602
|
+
setFinalAtOICaps: (value) => set((state) => ({
|
|
603
|
+
finalAtOICaps: value,
|
|
604
|
+
tokenMetadata: refreshTokenMetadata(state, { finalAtOICaps: value }, { oiCapsOnly: true }),
|
|
510
605
|
})),
|
|
511
|
-
setFinalAssetContexts: (value) => set({ finalAssetContexts: value }),
|
|
512
|
-
setFinalAtOICaps: (value) => set({ finalAtOICaps: value }),
|
|
513
606
|
setAggregatedClearingHouseState: (value) => set({ aggregatedClearingHouseState: value }),
|
|
514
607
|
setRawClearinghouseStates: (value) => set({ rawClearinghouseStates: value }),
|
|
515
|
-
setPerpMetaAssets: (value) => set(
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
608
|
+
setPerpMetaAssets: (value) => set((state) => ({
|
|
609
|
+
perpMetaAssets: value,
|
|
610
|
+
tokenMetadata: refreshTokenMetadata(state, { perpMetaAssets: value }),
|
|
611
|
+
})),
|
|
612
|
+
setPerpDexs: (value) => set({ perpDexs: value }),
|
|
613
|
+
setPerpMetasByDex: (value) => set((state) => ({
|
|
614
|
+
perpMetasByDex: value,
|
|
615
|
+
tokenMetadata: refreshTokenMetadata(state, {
|
|
616
|
+
perpMetasByDex: value,
|
|
617
|
+
assetContextsByDex: state.assetContextsByDex,
|
|
618
|
+
}),
|
|
619
|
+
})),
|
|
620
|
+
setAssetContextsByDex: (value) => set((state) => ({
|
|
621
|
+
assetContextsByDex: value,
|
|
622
|
+
tokenMetadata: refreshTokenMetadata(state, {
|
|
623
|
+
assetContextsByDex: value,
|
|
624
|
+
perpMetasByDex: state.perpMetasByDex,
|
|
625
|
+
}),
|
|
626
|
+
})),
|
|
519
627
|
}));
|
|
520
628
|
|
|
521
629
|
/**
|
|
@@ -778,7 +886,7 @@ const useUserSelection$1 = create((set, get) => ({
|
|
|
778
886
|
}));
|
|
779
887
|
|
|
780
888
|
const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }) => {
|
|
781
|
-
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData,
|
|
889
|
+
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAtOICaps, setAggregatedClearingHouseState, setRawClearinghouseStates, setAssetContextsByDex, } = useHyperliquidData();
|
|
782
890
|
const { setSpotState } = useUserData();
|
|
783
891
|
const { candleInterval } = useUserSelection$1();
|
|
784
892
|
const userSummary = useUserData((state) => state.accountSummary);
|
|
@@ -831,22 +939,13 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
831
939
|
case 'allDexsAssetCtxs':
|
|
832
940
|
{
|
|
833
941
|
const data = response.data;
|
|
834
|
-
//
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
.
|
|
839
|
-
// Sort to match perpMetaAssets order: default market first, then alphabetically
|
|
840
|
-
const prefixA = a[0] || '';
|
|
841
|
-
const prefixB = b[0] || '';
|
|
842
|
-
if (prefixA === '' && prefixB !== '')
|
|
843
|
-
return -1;
|
|
844
|
-
if (prefixA !== '' && prefixB === '')
|
|
845
|
-
return 1;
|
|
846
|
-
return prefixA.localeCompare(prefixB);
|
|
942
|
+
// Store by DEX name, mapping '' to 'HYPERLIQUID'
|
|
943
|
+
const assetContextsByDex = new Map();
|
|
944
|
+
data.ctxs.forEach(([dexKey, ctxs]) => {
|
|
945
|
+
const dexName = dexKey === '' ? 'HYPERLIQUID' : dexKey;
|
|
946
|
+
assetContextsByDex.set(dexName, ctxs || []);
|
|
847
947
|
});
|
|
848
|
-
|
|
849
|
-
setFinalAssetContexts(finalAssetContexts);
|
|
948
|
+
setAssetContextsByDex(assetContextsByDex);
|
|
850
949
|
}
|
|
851
950
|
break;
|
|
852
951
|
case 'allDexsClearinghouseState':
|
|
@@ -889,51 +988,20 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
889
988
|
case 'allMids':
|
|
890
989
|
{
|
|
891
990
|
const data = response.data;
|
|
892
|
-
|
|
893
|
-
// This ensures xyz:TSLA and flx:TSLA are stored separately,
|
|
894
|
-
// while also maintaining backward compatibility with non-prefixed lookups
|
|
895
|
-
const mids = {};
|
|
896
|
-
Object.entries(data.mids || {}).forEach(([k, v]) => {
|
|
897
|
-
// Normalize prefixed keys to lowercase prefix (e.g., "XYZ:TSLA" -> "xyz:TSLA")
|
|
898
|
-
// This matches how we look up tokens in the SDK
|
|
899
|
-
let normalizedKey = k;
|
|
900
|
-
if (k.includes(':')) {
|
|
901
|
-
const [prefix, ...rest] = k.split(':');
|
|
902
|
-
normalizedKey = `${prefix.toLowerCase()}:${rest.join(':')}`;
|
|
903
|
-
}
|
|
904
|
-
// Store with normalized key
|
|
905
|
-
mids[normalizedKey] = v;
|
|
906
|
-
// Also store with original key for backward compatibility
|
|
907
|
-
if (k !== normalizedKey) {
|
|
908
|
-
mids[k] = v;
|
|
909
|
-
}
|
|
910
|
-
// Also store with display symbol for backward compatibility
|
|
911
|
-
const displayKey = toDisplaySymbol(k);
|
|
912
|
-
// Only set display key if it doesn't already exist (avoid overwriting market-specific prices)
|
|
913
|
-
if (!(displayKey in mids)) {
|
|
914
|
-
mids[displayKey] = v;
|
|
915
|
-
}
|
|
916
|
-
});
|
|
917
|
-
setAllMids({ mids });
|
|
991
|
+
setAllMids(data);
|
|
918
992
|
}
|
|
919
993
|
break;
|
|
920
994
|
case 'activeAssetData':
|
|
921
995
|
{
|
|
922
996
|
const assetData = response.data;
|
|
923
|
-
|
|
924
|
-
const normalized = {
|
|
925
|
-
...assetData,
|
|
926
|
-
coin: symbol,
|
|
927
|
-
};
|
|
928
|
-
upsertActiveAssetData(symbol, normalized);
|
|
997
|
+
upsertActiveAssetData(assetData.coin, assetData);
|
|
929
998
|
}
|
|
930
999
|
break;
|
|
931
1000
|
case 'candle':
|
|
932
1001
|
{
|
|
933
1002
|
const candleDataItem = response.data;
|
|
934
|
-
const symbol =
|
|
935
|
-
|
|
936
|
-
addCandleData(symbol, normalized);
|
|
1003
|
+
const symbol = candleDataItem.s || '';
|
|
1004
|
+
addCandleData(symbol, candleDataItem);
|
|
937
1005
|
}
|
|
938
1006
|
break;
|
|
939
1007
|
case 'spotState':
|
|
@@ -958,10 +1026,10 @@ const useHyperliquidNativeWebSocket = ({ address, enabled = true, onUserFills, }
|
|
|
958
1026
|
setAllMids,
|
|
959
1027
|
upsertActiveAssetData,
|
|
960
1028
|
addCandleData,
|
|
961
|
-
setFinalAssetContexts,
|
|
962
1029
|
setFinalAtOICaps,
|
|
963
1030
|
setAggregatedClearingHouseState,
|
|
964
1031
|
setRawClearinghouseStates,
|
|
1032
|
+
setAssetContextsByDex,
|
|
965
1033
|
setSpotState,
|
|
966
1034
|
onUserFills,
|
|
967
1035
|
]);
|
|
@@ -1352,367 +1420,102 @@ const useAccountSummary = () => {
|
|
|
1352
1420
|
throw new Error('useAccountSummary must be used within a PearHyperliquidProvider');
|
|
1353
1421
|
}
|
|
1354
1422
|
const platformAccountSummary = useUserData((state) => state.accountSummary);
|
|
1355
|
-
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
1356
|
-
const registeredAgentWallets = useUserData((state) => state.userExtraAgents);
|
|
1357
|
-
const isLoading = useMemo(() => {
|
|
1358
|
-
return !platformAccountSummary || !registeredAgentWallets || !aggregatedClearingHouseState;
|
|
1359
|
-
}, [platformAccountSummary, registeredAgentWallets, aggregatedClearingHouseState]);
|
|
1360
|
-
// Create calculator and compute account summary
|
|
1361
|
-
const calculator = new AccountSummaryCalculator(aggregatedClearingHouseState);
|
|
1362
|
-
const calculated = calculator.calculateAccountSummary(platformAccountSummary, registeredAgentWallets || []);
|
|
1363
|
-
return { data: calculated, isLoading };
|
|
1364
|
-
};
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
if (coinName.includes(':')) {
|
|
1381
|
-
const [prefix, symbol] = coinName.split(':');
|
|
1382
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
1383
|
-
var _a;
|
|
1384
|
-
return a.name === symbol &&
|
|
1385
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
1386
|
-
});
|
|
1387
|
-
if (exactMatch) {
|
|
1388
|
-
return {
|
|
1389
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
1390
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
1391
|
-
};
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
if (knownPrefix) {
|
|
1395
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
1396
|
-
var _a;
|
|
1397
|
-
return a.name === coinName &&
|
|
1398
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
1399
|
-
});
|
|
1400
|
-
if (exactMatch) {
|
|
1401
|
-
return {
|
|
1402
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
1403
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
1404
|
-
};
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
const exactMatch = perpMetaAssets.find((a) => a.name === coinName && !a.marketPrefix);
|
|
1408
|
-
if (exactMatch) {
|
|
1409
|
-
return {
|
|
1410
|
-
collateralToken: (_g = exactMatch.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
1411
|
-
marketPrefix: (_h = exactMatch.marketPrefix) !== null && _h !== void 0 ? _h : null,
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1414
|
-
const hip3Matches = perpMetaAssets.filter((a) => a.name === coinName && a.marketPrefix);
|
|
1415
|
-
if (hip3Matches.length > 0) {
|
|
1416
|
-
if (desiredCollateral) {
|
|
1417
|
-
const collateralMatch = hip3Matches.find((a) => a.collateralToken === desiredCollateral);
|
|
1418
|
-
if (collateralMatch) {
|
|
1419
|
-
return {
|
|
1420
|
-
collateralToken: (_j = collateralMatch.collateralToken) !== null && _j !== void 0 ? _j : 'USDC',
|
|
1421
|
-
marketPrefix: (_k = collateralMatch.marketPrefix) !== null && _k !== void 0 ? _k : null,
|
|
1422
|
-
};
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
const usdHMatch = hip3Matches.find((a) => a.collateralToken === 'USDH');
|
|
1426
|
-
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Matches[0];
|
|
1427
|
-
return {
|
|
1428
|
-
collateralToken: (_l = chosen.collateralToken) !== null && _l !== void 0 ? _l : 'USDC',
|
|
1429
|
-
marketPrefix: (_m = chosen.marketPrefix) !== null && _m !== void 0 ? _m : null,
|
|
1430
|
-
};
|
|
1431
|
-
}
|
|
1432
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
1433
|
-
}
|
|
1434
|
-
function enrichTradeHistoryAssets(assets, perpMetaAssets) {
|
|
1435
|
-
return assets.map((asset) => {
|
|
1436
|
-
var _a;
|
|
1437
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
1438
|
-
return asset;
|
|
1439
|
-
}
|
|
1440
|
-
const meta = findAssetMeta$4(asset.coin, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
1441
|
-
return {
|
|
1442
|
-
...asset,
|
|
1443
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
1444
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
1445
|
-
};
|
|
1446
|
-
});
|
|
1447
|
-
}
|
|
1448
|
-
function enrichTradeHistories(histories, perpMetaAssets) {
|
|
1449
|
-
return histories.map((history) => ({
|
|
1450
|
-
...history,
|
|
1451
|
-
closedLongAssets: enrichTradeHistoryAssets(history.closedLongAssets, perpMetaAssets),
|
|
1452
|
-
closedShortAssets: enrichTradeHistoryAssets(history.closedShortAssets, perpMetaAssets),
|
|
1453
|
-
}));
|
|
1454
|
-
}
|
|
1455
|
-
const useTradeHistories = () => {
|
|
1456
|
-
const context = useContext(PearHyperliquidContext);
|
|
1457
|
-
if (!context) {
|
|
1458
|
-
throw new Error('useTradeHistories must be used within a PearHyperliquidProvider');
|
|
1459
|
-
}
|
|
1460
|
-
const tradeHistories = useUserData((state) => state.tradeHistories);
|
|
1461
|
-
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
1462
|
-
const isLoading = useMemo(() => {
|
|
1463
|
-
return tradeHistories === null && context.isConnected;
|
|
1464
|
-
}, [tradeHistories, context.isConnected]);
|
|
1465
|
-
const enrichedTradeHistories = useMemo(() => {
|
|
1466
|
-
if (!tradeHistories)
|
|
1467
|
-
return null;
|
|
1468
|
-
return enrichTradeHistories(tradeHistories, allPerpMetaAssets);
|
|
1469
|
-
}, [tradeHistories, allPerpMetaAssets]);
|
|
1470
|
-
return { data: enrichedTradeHistories, isLoading };
|
|
1471
|
-
};
|
|
1472
|
-
const useOpenOrders = () => {
|
|
1473
|
-
const context = useContext(PearHyperliquidContext);
|
|
1474
|
-
if (!context) {
|
|
1475
|
-
throw new Error('useOpenOrders must be used within a PearHyperliquidProvider');
|
|
1476
|
-
}
|
|
1477
|
-
const openOrders = useUserData((state) => state.openOrders);
|
|
1478
|
-
const isLoading = useMemo(() => {
|
|
1479
|
-
return openOrders === null && context.isConnected;
|
|
1480
|
-
}, [openOrders, context.isConnected]);
|
|
1481
|
-
return { data: openOrders, isLoading };
|
|
1482
|
-
};
|
|
1483
|
-
|
|
1484
|
-
const useUserSelection = () => {
|
|
1485
|
-
return useUserSelection$1();
|
|
1486
|
-
};
|
|
1487
|
-
|
|
1488
|
-
/**
|
|
1489
|
-
* Hook to access webData and native WebSocket state
|
|
1490
|
-
*/
|
|
1491
|
-
const useWebData = () => {
|
|
1492
|
-
const context = useContext(PearHyperliquidContext);
|
|
1493
|
-
if (!context) {
|
|
1494
|
-
throw new Error('useWebData must be used within a PearHyperliquidProvider');
|
|
1495
|
-
}
|
|
1496
|
-
const finalAssetContexts = useHyperliquidData((state) => state.finalAssetContexts);
|
|
1497
|
-
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
1498
|
-
const aggregatedClearinghouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
1499
|
-
const finalAtOICaps = useHyperliquidData((state) => state.finalAtOICaps);
|
|
1500
|
-
const hip3Assets = useHyperliquidData((state) => state.hip3Assets);
|
|
1501
|
-
const hip3MarketPrefixes = useHyperliquidData((state) => state.hip3MarketPrefixes);
|
|
1502
|
-
let marketDataBySymbol = {};
|
|
1503
|
-
if (finalAssetContexts && perpMetaAssets) {
|
|
1504
|
-
const result = {};
|
|
1505
|
-
// Build a map of display name -> asset context index (for unique display names)
|
|
1506
|
-
const displayNameToContextIndex = new Map();
|
|
1507
|
-
const seenNames = new Set();
|
|
1508
|
-
let contextIndex = 0;
|
|
1509
|
-
// First pass: map unique display names to their context index
|
|
1510
|
-
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1511
|
-
const name = perpMetaAssets[index].name;
|
|
1512
|
-
if (!seenNames.has(name)) {
|
|
1513
|
-
seenNames.add(name);
|
|
1514
|
-
if (contextIndex < finalAssetContexts.length) {
|
|
1515
|
-
displayNameToContextIndex.set(name, contextIndex);
|
|
1516
|
-
contextIndex++;
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
// Second pass: create nested entries for all market variants
|
|
1521
|
-
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
1522
|
-
const universeAsset = perpMetaAssets[index];
|
|
1523
|
-
const displayName = universeAsset.name;
|
|
1524
|
-
const marketPrefix = universeAsset.marketPrefix;
|
|
1525
|
-
const ctxIndex = displayNameToContextIndex.get(displayName);
|
|
1526
|
-
if (ctxIndex !== undefined) {
|
|
1527
|
-
const assetContext = finalAssetContexts[ctxIndex];
|
|
1528
|
-
// Initialize the symbol entry if it doesn't exist
|
|
1529
|
-
if (!result[displayName]) {
|
|
1530
|
-
result[displayName] = {};
|
|
1531
|
-
}
|
|
1532
|
-
// Use marketPrefix as key for HIP-3 assets, "default" for regular assets
|
|
1533
|
-
const variantKey = marketPrefix || 'default';
|
|
1534
|
-
result[displayName][variantKey] = {
|
|
1535
|
-
asset: assetContext,
|
|
1536
|
-
universe: universeAsset,
|
|
1537
|
-
};
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
marketDataBySymbol = result;
|
|
1541
|
-
}
|
|
1542
|
-
return {
|
|
1543
|
-
hip3Assets,
|
|
1544
|
-
hip3MarketPrefixes,
|
|
1545
|
-
clearinghouseState: aggregatedClearinghouseState,
|
|
1546
|
-
perpsAtOpenInterestCap: finalAtOICaps,
|
|
1547
|
-
marketDataBySymbol,
|
|
1548
|
-
isConnected: context.nativeIsConnected,
|
|
1549
|
-
error: context.nativeLastError,
|
|
1550
|
-
};
|
|
1551
|
-
};
|
|
1552
|
-
|
|
1553
|
-
/**
|
|
1554
|
-
* Check if two symbols match, handling kPEPE/KPEPE variations
|
|
1555
|
-
* Returns true if symbols match (case-insensitive for k-prefix tokens)
|
|
1556
|
-
*/
|
|
1557
|
-
function symbolsMatch(assetName, searchSymbol) {
|
|
1558
|
-
// Exact match
|
|
1559
|
-
if (assetName === searchSymbol)
|
|
1560
|
-
return true;
|
|
1561
|
-
// Try case-insensitive match for k-prefix tokens (kPEPE vs KPEPE)
|
|
1562
|
-
if (assetName.toUpperCase() === searchSymbol.toUpperCase()) {
|
|
1563
|
-
return true;
|
|
1564
|
-
}
|
|
1565
|
-
return false;
|
|
1566
|
-
}
|
|
1567
|
-
/**
|
|
1568
|
-
* Extracts token metadata from aggregated WebData3 contexts and AllMids data
|
|
1569
|
-
*/
|
|
1570
|
-
class TokenMetadataExtractor {
|
|
1571
|
-
/**
|
|
1572
|
-
* Extracts comprehensive token metadata
|
|
1573
|
-
* @param symbol - Token symbol (base symbol without prefix, e.g., "TSLA")
|
|
1574
|
-
* @param perpMetaAssets - Aggregated universe assets (flattened across dexes)
|
|
1575
|
-
* @param finalAssetContexts - Aggregated asset contexts (flattened across dexes)
|
|
1576
|
-
* @param allMids - AllMids data containing current prices
|
|
1577
|
-
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1578
|
-
* @param marketPrefix - Optional market prefix (e.g., "xyz", "flx") for HIP3 multi-market assets
|
|
1579
|
-
* @returns TokenMetadata or null if token not found
|
|
1580
|
-
*/
|
|
1581
|
-
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketPrefix) {
|
|
1582
|
-
if (!perpMetaAssets || !finalAssetContexts || !allMids) {
|
|
1583
|
-
return null;
|
|
1584
|
-
}
|
|
1585
|
-
// Find token index in aggregated universe
|
|
1586
|
-
// For HIP3 assets, match both name AND marketPrefix
|
|
1587
|
-
// Uses symbolsMatch to handle kPEPE/KPEPE case variations
|
|
1588
|
-
const universeIndex = perpMetaAssets.findIndex((asset) => {
|
|
1589
|
-
if (!symbolsMatch(asset.name, symbol))
|
|
1590
|
-
return false;
|
|
1591
|
-
// If marketPrefix is specified, match it; otherwise match assets without prefix
|
|
1592
|
-
if (marketPrefix) {
|
|
1593
|
-
return asset.marketPrefix === marketPrefix;
|
|
1594
|
-
}
|
|
1595
|
-
// No prefix specified - match non-HIP3 asset (no marketPrefix) or first matching asset
|
|
1596
|
-
return !asset.marketPrefix;
|
|
1597
|
-
});
|
|
1598
|
-
if (universeIndex === -1) {
|
|
1599
|
-
return null;
|
|
1600
|
-
}
|
|
1601
|
-
const universeAsset = perpMetaAssets[universeIndex];
|
|
1602
|
-
const assetCtx = finalAssetContexts[universeIndex];
|
|
1603
|
-
if (!assetCtx) {
|
|
1604
|
-
return null;
|
|
1605
|
-
}
|
|
1606
|
-
// Get current price - prefer assetCtx.midPx as it's already index-matched,
|
|
1607
|
-
// fall back to allMids lookup if midPx is null
|
|
1608
|
-
const actualSymbol = universeAsset.name; // Use actual symbol from universe (handles kPEPE vs KPEPE)
|
|
1609
|
-
const prefixedKeyColon = marketPrefix
|
|
1610
|
-
? `${marketPrefix}:${actualSymbol}`
|
|
1611
|
-
: null;
|
|
1612
|
-
let currentPrice = 0;
|
|
1613
|
-
// Primary source: assetCtx.midPx (already properly indexed)
|
|
1614
|
-
if (assetCtx.midPx) {
|
|
1615
|
-
currentPrice = parseFloat(assetCtx.midPx);
|
|
1616
|
-
}
|
|
1617
|
-
// Fallback: allMids lookup with multiple key formats for HIP3 markets
|
|
1618
|
-
// Try actual symbol from universe first, then input symbol
|
|
1619
|
-
if (!currentPrice || isNaN(currentPrice)) {
|
|
1620
|
-
const currentPriceStr = (prefixedKeyColon && allMids.mids[prefixedKeyColon]) ||
|
|
1621
|
-
allMids.mids[actualSymbol] ||
|
|
1622
|
-
allMids.mids[symbol];
|
|
1623
|
-
currentPrice = currentPriceStr ? parseFloat(currentPriceStr) : 0;
|
|
1624
|
-
}
|
|
1625
|
-
// Get previous day price
|
|
1626
|
-
const prevDayPrice = parseFloat(assetCtx.prevDayPx);
|
|
1627
|
-
// Calculate 24h price change
|
|
1628
|
-
const priceChange24h = currentPrice - prevDayPrice;
|
|
1629
|
-
const priceChange24hPercent = prevDayPrice !== 0 ? (priceChange24h / prevDayPrice) * 100 : 0;
|
|
1630
|
-
// Parse other metadata
|
|
1631
|
-
const netFunding = parseFloat(assetCtx.funding) * 100;
|
|
1632
|
-
const markPrice = parseFloat(assetCtx.markPx);
|
|
1633
|
-
const oraclePrice = parseFloat(assetCtx.oraclePx);
|
|
1634
|
-
// Extract leverage info from activeAssetData if available
|
|
1635
|
-
// Try prefixed key first (e.g., "xyz:TSLA"), then actual symbol, then input symbol
|
|
1636
|
-
const activeDataKey = prefixedKeyColon && (activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[prefixedKeyColon])
|
|
1637
|
-
? prefixedKeyColon
|
|
1638
|
-
: (activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[actualSymbol])
|
|
1639
|
-
? actualSymbol
|
|
1640
|
-
: symbol;
|
|
1641
|
-
const tokenActiveData = activeAssetData === null || activeAssetData === void 0 ? void 0 : activeAssetData[activeDataKey];
|
|
1642
|
-
const leverage = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.leverage;
|
|
1643
|
-
const maxTradeSzs = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.maxTradeSzs;
|
|
1644
|
-
const availableToTrade = tokenActiveData === null || tokenActiveData === void 0 ? void 0 : tokenActiveData.availableToTrade;
|
|
1645
|
-
return {
|
|
1646
|
-
currentPrice,
|
|
1647
|
-
prevDayPrice,
|
|
1648
|
-
priceChange24h,
|
|
1649
|
-
priceChange24hPercent,
|
|
1650
|
-
netFunding,
|
|
1651
|
-
maxLeverage: universeAsset.maxLeverage,
|
|
1652
|
-
markPrice,
|
|
1653
|
-
oraclePrice,
|
|
1654
|
-
openInterest: assetCtx.openInterest,
|
|
1655
|
-
dayVolume: assetCtx.dayNtlVlm,
|
|
1656
|
-
leverage,
|
|
1657
|
-
maxTradeSzs,
|
|
1658
|
-
availableToTrade,
|
|
1659
|
-
collateralToken: universeAsset.collateralToken,
|
|
1660
|
-
};
|
|
1661
|
-
}
|
|
1662
|
-
/**
|
|
1663
|
-
* Extracts metadata for multiple tokens
|
|
1664
|
-
* @param tokens - Array of token objects with symbol and optional marketPrefix
|
|
1665
|
-
* @param perpMetaAssets - Aggregated universe assets
|
|
1666
|
-
* @param finalAssetContexts - Aggregated asset contexts
|
|
1667
|
-
* @param allMids - AllMids data
|
|
1668
|
-
* @param activeAssetData - Optional active asset data containing leverage information
|
|
1669
|
-
* @returns Record of unique key to TokenMetadata. Key is "{prefix}:{symbol}" for HIP3 assets, or just "{symbol}" otherwise
|
|
1670
|
-
*/
|
|
1671
|
-
static extractMultipleTokensMetadata(tokens, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
1672
|
-
const result = {};
|
|
1673
|
-
for (const token of tokens) {
|
|
1674
|
-
// Use a unique key that includes the prefix for HIP3 assets
|
|
1675
|
-
// This ensures xyz:TSLA and flx:TSLA get separate entries
|
|
1676
|
-
const resultKey = token.marketPrefix
|
|
1677
|
-
? `${token.marketPrefix}:${token.symbol}`
|
|
1678
|
-
: token.symbol;
|
|
1679
|
-
result[resultKey] = this.extractTokenMetadata(token.symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData, token.marketPrefix);
|
|
1680
|
-
}
|
|
1681
|
-
return result;
|
|
1682
|
-
}
|
|
1683
|
-
/**
|
|
1684
|
-
* Checks if token data is available in aggregated universe assets
|
|
1685
|
-
* @param symbol - Token symbol
|
|
1686
|
-
* @param perpMetaAssets - Aggregated universe assets
|
|
1687
|
-
* @returns boolean indicating if token exists in universe
|
|
1688
|
-
*/
|
|
1689
|
-
static isTokenAvailable(symbol, perpMetaAssets) {
|
|
1690
|
-
if (!perpMetaAssets)
|
|
1691
|
-
return false;
|
|
1692
|
-
return perpMetaAssets.some((asset) => symbolsMatch(asset.name, symbol));
|
|
1423
|
+
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
1424
|
+
const registeredAgentWallets = useUserData((state) => state.userExtraAgents);
|
|
1425
|
+
const isLoading = useMemo(() => {
|
|
1426
|
+
return !platformAccountSummary || !registeredAgentWallets || !aggregatedClearingHouseState;
|
|
1427
|
+
}, [platformAccountSummary, registeredAgentWallets, aggregatedClearingHouseState]);
|
|
1428
|
+
// Create calculator and compute account summary
|
|
1429
|
+
const calculator = new AccountSummaryCalculator(aggregatedClearingHouseState);
|
|
1430
|
+
const calculated = calculator.calculateAccountSummary(platformAccountSummary, registeredAgentWallets || []);
|
|
1431
|
+
return { data: calculated, isLoading };
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
const selectTokenMetadataBySymbols = (tokenMetadata, symbols) => {
|
|
1435
|
+
const result = {};
|
|
1436
|
+
symbols.forEach((symbol) => {
|
|
1437
|
+
var _a;
|
|
1438
|
+
result[symbol] = (_a = tokenMetadata[symbol]) !== null && _a !== void 0 ? _a : null;
|
|
1439
|
+
});
|
|
1440
|
+
return result;
|
|
1441
|
+
};
|
|
1442
|
+
const getAssetByName = (tokenMetadata, symbol) => {
|
|
1443
|
+
var _a, _b;
|
|
1444
|
+
if (symbol in tokenMetadata) {
|
|
1445
|
+
return (_a = tokenMetadata[symbol]) !== null && _a !== void 0 ? _a : null;
|
|
1693
1446
|
}
|
|
1694
|
-
|
|
1447
|
+
const normalizedSymbol = symbol.toUpperCase();
|
|
1448
|
+
const matchKey = Object.keys(tokenMetadata).find((key) => key.toUpperCase() === normalizedSymbol);
|
|
1449
|
+
return matchKey ? (_b = tokenMetadata[matchKey]) !== null && _b !== void 0 ? _b : null : null;
|
|
1450
|
+
};
|
|
1695
1451
|
|
|
1696
1452
|
/**
|
|
1697
|
-
*
|
|
1698
|
-
* This allows us to keep the full name (xyz:GOOGL) for URLs/tags while extracting just the symbol for SDK lookups.
|
|
1453
|
+
* Hook to access webData
|
|
1699
1454
|
*/
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1455
|
+
const useMarket = () => {
|
|
1456
|
+
const tokenMetadata = useHyperliquidData((state) => state.tokenMetadata);
|
|
1457
|
+
const allTokenMetadata = useMemo(() => Object.values(tokenMetadata).filter((metadata) => Boolean(metadata)), [tokenMetadata]);
|
|
1458
|
+
const getAssetByName$1 = useCallback((symbol) => getAssetByName(tokenMetadata, symbol), [tokenMetadata]);
|
|
1459
|
+
return { allTokenMetadata, getAssetByName: getAssetByName$1 };
|
|
1460
|
+
};
|
|
1461
|
+
|
|
1462
|
+
const useTradeHistories = () => {
|
|
1463
|
+
const context = useContext(PearHyperliquidContext);
|
|
1464
|
+
if (!context) {
|
|
1465
|
+
throw new Error('useTradeHistories must be used within a PearHyperliquidProvider');
|
|
1709
1466
|
}
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1467
|
+
const tradeHistories = useUserData((state) => state.tradeHistories);
|
|
1468
|
+
const { getAssetByName } = useMarket();
|
|
1469
|
+
const enrichedTradeHistories = useMemo(() => {
|
|
1470
|
+
if (!tradeHistories)
|
|
1471
|
+
return null;
|
|
1472
|
+
return tradeHistories.map((history) => ({
|
|
1473
|
+
...history,
|
|
1474
|
+
closedLongAssets: history.closedLongAssets.map((asset) => ({
|
|
1475
|
+
...asset,
|
|
1476
|
+
metadata: getAssetByName(asset.coin),
|
|
1477
|
+
})),
|
|
1478
|
+
closedShortAssets: history.closedShortAssets.map((asset) => ({
|
|
1479
|
+
...asset,
|
|
1480
|
+
metadata: getAssetByName(asset.coin),
|
|
1481
|
+
})),
|
|
1482
|
+
}));
|
|
1483
|
+
}, [tradeHistories, getAssetByName]);
|
|
1484
|
+
const isLoading = useMemo(() => {
|
|
1485
|
+
return tradeHistories === null && context.isConnected;
|
|
1486
|
+
}, [tradeHistories, context.isConnected]);
|
|
1487
|
+
return { data: enrichedTradeHistories, isLoading };
|
|
1488
|
+
};
|
|
1489
|
+
const useOpenOrders = () => {
|
|
1490
|
+
const context = useContext(PearHyperliquidContext);
|
|
1491
|
+
if (!context) {
|
|
1492
|
+
throw new Error('useOpenOrders must be used within a PearHyperliquidProvider');
|
|
1493
|
+
}
|
|
1494
|
+
const openOrders = useUserData((state) => state.openOrders);
|
|
1495
|
+
const { getAssetByName } = useMarket();
|
|
1496
|
+
const enrichedOpenOrders = useMemo(() => {
|
|
1497
|
+
if (!openOrders)
|
|
1498
|
+
return null;
|
|
1499
|
+
const mapAssets = (assets) => (assets !== null && assets !== void 0 ? assets : []).map((asset) => ({
|
|
1500
|
+
...asset,
|
|
1501
|
+
metadata: getAssetByName(asset.asset),
|
|
1502
|
+
}));
|
|
1503
|
+
return openOrders.map((order) => ({
|
|
1504
|
+
...order,
|
|
1505
|
+
longAssets: mapAssets(order.longAssets),
|
|
1506
|
+
shortAssets: mapAssets(order.shortAssets),
|
|
1507
|
+
}));
|
|
1508
|
+
}, [openOrders, getAssetByName]);
|
|
1509
|
+
const isLoading = useMemo(() => {
|
|
1510
|
+
return openOrders === null && context.isConnected;
|
|
1511
|
+
}, [openOrders, context.isConnected]);
|
|
1512
|
+
return { data: enrichedOpenOrders, isLoading };
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
const useUserSelection = () => {
|
|
1516
|
+
return useUserSelection$1();
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1716
1519
|
const useTokenSelectionMetadataStore = create((set) => ({
|
|
1717
1520
|
isPriceDataReady: false,
|
|
1718
1521
|
isLoading: true,
|
|
@@ -1728,59 +1531,18 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1728
1531
|
maxLeverage: 0,
|
|
1729
1532
|
minMargin: 0,
|
|
1730
1533
|
leverageMatched: true,
|
|
1731
|
-
recompute: ({ perpMetaAssets,
|
|
1732
|
-
const isPriceDataReady =
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
//
|
|
1737
|
-
const
|
|
1738
|
-
|
|
1739
|
-
parsed: parseTokenWithPrefix(t.symbol),
|
|
1740
|
-
}));
|
|
1741
|
-
const parsedShortTokens = shortTokens.map((t) => ({
|
|
1742
|
-
...t,
|
|
1743
|
-
parsed: parseTokenWithPrefix(t.symbol),
|
|
1744
|
-
}));
|
|
1745
|
-
// Extract base symbols with their market prefixes for SDK lookups
|
|
1746
|
-
// This ensures xyz:TSLA and flx:TSLA get different market data
|
|
1747
|
-
const longTokensForLookup = parsedLongTokens.map((t) => ({
|
|
1748
|
-
symbol: t.parsed.symbol,
|
|
1749
|
-
marketPrefix: t.parsed.prefix,
|
|
1750
|
-
}));
|
|
1751
|
-
const shortTokensForLookup = parsedShortTokens.map((t) => ({
|
|
1752
|
-
symbol: t.parsed.symbol,
|
|
1753
|
-
marketPrefix: t.parsed.prefix,
|
|
1754
|
-
}));
|
|
1755
|
-
// Also extract just the base symbols (without prefix) for lookups that don't support prefixes
|
|
1756
|
-
const longBaseSymbols = longTokensForLookup.map((t) => t.symbol);
|
|
1757
|
-
const shortBaseSymbols = shortTokensForLookup.map((t) => t.symbol);
|
|
1758
|
-
// Get metadata using base symbols with market prefix for proper market differentiation
|
|
1759
|
-
const longBaseMetadata = isPriceDataReady
|
|
1760
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(longTokensForLookup, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
1534
|
+
recompute: ({ perpMetaAssets, tokenMetadata, marketData, longTokens, shortTokens, }) => {
|
|
1535
|
+
const isPriceDataReady = Object.keys(tokenMetadata).length > 0;
|
|
1536
|
+
// Get token symbols for lookups
|
|
1537
|
+
const longSymbols = longTokens.map((t) => t.symbol);
|
|
1538
|
+
const shortSymbols = shortTokens.map((t) => t.symbol);
|
|
1539
|
+
// Get metadata
|
|
1540
|
+
const longTokensMetadata = isPriceDataReady
|
|
1541
|
+
? selectTokenMetadataBySymbols(tokenMetadata, longSymbols)
|
|
1761
1542
|
: {};
|
|
1762
|
-
const
|
|
1763
|
-
?
|
|
1543
|
+
const shortTokensMetadata = isPriceDataReady
|
|
1544
|
+
? selectTokenMetadataBySymbols(tokenMetadata, shortSymbols)
|
|
1764
1545
|
: {};
|
|
1765
|
-
// Re-map metadata using original full names (with prefix) as keys for UI consistency
|
|
1766
|
-
// The extractor now keys by "{prefix}:{symbol}" for prefixed tokens, which matches our parsed.fullName
|
|
1767
|
-
const longTokensMetadata = {};
|
|
1768
|
-
parsedLongTokens.forEach((t) => {
|
|
1769
|
-
var _a;
|
|
1770
|
-
// Use the full name (e.g., "xyz:TSLA") as the lookup key since extractor uses the same format
|
|
1771
|
-
const lookupKey = t.parsed.prefix
|
|
1772
|
-
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1773
|
-
: t.parsed.symbol;
|
|
1774
|
-
longTokensMetadata[t.symbol] = (_a = longBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1775
|
-
});
|
|
1776
|
-
const shortTokensMetadata = {};
|
|
1777
|
-
parsedShortTokens.forEach((t) => {
|
|
1778
|
-
var _a;
|
|
1779
|
-
const lookupKey = t.parsed.prefix
|
|
1780
|
-
? `${t.parsed.prefix}:${t.parsed.symbol}`
|
|
1781
|
-
: t.parsed.symbol;
|
|
1782
|
-
shortTokensMetadata[t.symbol] = (_a = shortBaseMetadata[lookupKey]) !== null && _a !== void 0 ? _a : null;
|
|
1783
|
-
});
|
|
1784
1546
|
// Determine loading state
|
|
1785
1547
|
const allTokens = [...longTokens, ...shortTokens];
|
|
1786
1548
|
const isLoading = (() => {
|
|
@@ -1795,13 +1557,12 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1795
1557
|
return allTokens.some((token) => !allMetadata[token.symbol]);
|
|
1796
1558
|
})();
|
|
1797
1559
|
// Open interest and volume (from market data for matching asset basket)
|
|
1798
|
-
// Use base symbols (without prefix) for matching against market data
|
|
1799
1560
|
const { openInterest, volume } = (() => {
|
|
1800
1561
|
const empty = { openInterest: "0", volume: "0" };
|
|
1801
1562
|
if (!(marketData === null || marketData === void 0 ? void 0 : marketData.active) || (!longTokens.length && !shortTokens.length))
|
|
1802
1563
|
return empty;
|
|
1803
|
-
const selectedLong =
|
|
1804
|
-
const selectedShort =
|
|
1564
|
+
const selectedLong = longSymbols.slice().sort();
|
|
1565
|
+
const selectedShort = shortSymbols.slice().sort();
|
|
1805
1566
|
const match = marketData.active.find((item) => {
|
|
1806
1567
|
const longs = [...item.longAssets].sort();
|
|
1807
1568
|
const shorts = [...item.shortAssets].sort();
|
|
@@ -1894,27 +1655,18 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
1894
1655
|
return totalFunding;
|
|
1895
1656
|
})();
|
|
1896
1657
|
// Max leverage (maximum across all tokens)
|
|
1897
|
-
// Use tokens with their market prefixes for proper lookup in perpMetaAssets
|
|
1898
1658
|
const maxLeverage = (() => {
|
|
1899
1659
|
if (!perpMetaAssets)
|
|
1900
1660
|
return 0;
|
|
1901
|
-
const
|
|
1902
|
-
|
|
1903
|
-
...shortTokensForLookup,
|
|
1904
|
-
];
|
|
1905
|
-
if (allTokensForLookup.length === 0)
|
|
1661
|
+
const allSymbols = [...longSymbols, ...shortSymbols];
|
|
1662
|
+
if (allSymbols.length === 0)
|
|
1906
1663
|
return 0;
|
|
1907
1664
|
let maxLev = 0;
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
(
|
|
1912
|
-
|
|
1913
|
-
: !u.marketPrefix));
|
|
1914
|
-
// Fallback to just matching by name if no exact match
|
|
1915
|
-
const fallbackUniverse = tokenUniverse || perpMetaAssets.find((u) => u.name === symbol);
|
|
1916
|
-
if (fallbackUniverse === null || fallbackUniverse === void 0 ? void 0 : fallbackUniverse.maxLeverage)
|
|
1917
|
-
maxLev = Math.max(maxLev, fallbackUniverse.maxLeverage);
|
|
1665
|
+
allSymbols.forEach((symbol) => {
|
|
1666
|
+
const tokenUniverse = perpMetaAssets.find((u) => u.name === symbol);
|
|
1667
|
+
if (tokenUniverse === null || tokenUniverse === void 0 ? void 0 : tokenUniverse.maxLeverage) {
|
|
1668
|
+
maxLev = Math.max(maxLev, tokenUniverse.maxLeverage);
|
|
1669
|
+
}
|
|
1918
1670
|
});
|
|
1919
1671
|
return maxLev;
|
|
1920
1672
|
})();
|
|
@@ -1968,9 +1720,7 @@ const useTokenSelectionMetadata = () => {
|
|
|
1968
1720
|
throw new Error('useTokenSelection must be used within PearHyperliquidProvider');
|
|
1969
1721
|
}
|
|
1970
1722
|
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
1971
|
-
const
|
|
1972
|
-
const allMids = useHyperliquidData((state) => state.allMids);
|
|
1973
|
-
const activeAssetData = useHyperliquidData((state) => state.activeAssetData);
|
|
1723
|
+
const tokenMetadata = useHyperliquidData((state) => state.tokenMetadata);
|
|
1974
1724
|
const marketData = useMarketData((state) => state.marketData);
|
|
1975
1725
|
const { longTokens, shortTokens } = useUserSelection$1();
|
|
1976
1726
|
const { isLoading, isPriceDataReady, longTokensMetadata, shortTokensMetadata, weightedRatio, weightedRatio24h, priceRatio, priceRatio24h, openInterest, volume, sumNetFunding, maxLeverage, minMargin, leverageMatched, recompute, } = useTokenSelectionMetadataStore();
|
|
@@ -1978,16 +1728,14 @@ const useTokenSelectionMetadata = () => {
|
|
|
1978
1728
|
useEffect(() => {
|
|
1979
1729
|
recompute({
|
|
1980
1730
|
perpMetaAssets,
|
|
1981
|
-
|
|
1982
|
-
allMids,
|
|
1983
|
-
activeAssetData: activeAssetData || null,
|
|
1731
|
+
tokenMetadata,
|
|
1984
1732
|
marketData: marketData || null,
|
|
1985
1733
|
longTokens,
|
|
1986
1734
|
shortTokens,
|
|
1987
1735
|
});
|
|
1988
1736
|
// We want to recompute when token lists or upstream data change
|
|
1989
1737
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1990
|
-
}, [perpMetaAssets,
|
|
1738
|
+
}, [perpMetaAssets, tokenMetadata, JSON.stringify(longTokens), JSON.stringify(shortTokens)]);
|
|
1991
1739
|
return {
|
|
1992
1740
|
// Loading states
|
|
1993
1741
|
isLoading,
|
|
@@ -6114,10 +5862,9 @@ function addAuthInterceptors(params) {
|
|
|
6114
5862
|
/**
|
|
6115
5863
|
* Fetch historical candle data from HyperLiquid API
|
|
6116
5864
|
*/
|
|
6117
|
-
const fetchHistoricalCandles = async (coin, startTime, endTime, interval
|
|
6118
|
-
const backendCoin = toBackendSymbol(coin, hip3Assets);
|
|
5865
|
+
const fetchHistoricalCandles = async (coin, startTime, endTime, interval) => {
|
|
6119
5866
|
const request = {
|
|
6120
|
-
req: { coin
|
|
5867
|
+
req: { coin, startTime, endTime, interval },
|
|
6121
5868
|
type: 'candleSnapshot',
|
|
6122
5869
|
};
|
|
6123
5870
|
try {
|
|
@@ -6194,6 +5941,26 @@ const fetchExtraAgents = async (user) => {
|
|
|
6194
5941
|
throw toApiError(error);
|
|
6195
5942
|
}
|
|
6196
5943
|
};
|
|
5944
|
+
/**
|
|
5945
|
+
* Fetch perp dexes from HyperLiquid API
|
|
5946
|
+
* Endpoint: https://api.hyperliquid.xyz/info
|
|
5947
|
+
* Payload: { "type": "perpDexs" }
|
|
5948
|
+
* Returns array where index 0 is null (HYPERLIQUID), index 1+ are named DEXes
|
|
5949
|
+
*/
|
|
5950
|
+
const fetchPerpDexs = async () => {
|
|
5951
|
+
const request = { type: 'perpDexs' };
|
|
5952
|
+
try {
|
|
5953
|
+
const response = await axios$1.post('https://api.hyperliquid.xyz/info', request, { headers: { 'Content-Type': 'application/json' } });
|
|
5954
|
+
return {
|
|
5955
|
+
data: response.data,
|
|
5956
|
+
status: response.status,
|
|
5957
|
+
headers: response.headers,
|
|
5958
|
+
};
|
|
5959
|
+
}
|
|
5960
|
+
catch (error) {
|
|
5961
|
+
throw toApiError(error);
|
|
5962
|
+
}
|
|
5963
|
+
};
|
|
6197
5964
|
|
|
6198
5965
|
const useHistoricalPriceData = () => {
|
|
6199
5966
|
const context = useContext(PearHyperliquidContext);
|
|
@@ -6274,10 +6041,9 @@ const useHistoricalPriceData = () => {
|
|
|
6274
6041
|
setTokenLoading(token.symbol, true);
|
|
6275
6042
|
});
|
|
6276
6043
|
try {
|
|
6277
|
-
const hip3Assets = useHyperliquidData.getState().hip3Assets;
|
|
6278
6044
|
const fetchPromises = tokensToFetch.map(async (token) => {
|
|
6279
6045
|
try {
|
|
6280
|
-
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval
|
|
6046
|
+
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval);
|
|
6281
6047
|
addHistoricalPriceData(token.symbol, interval, response.data, { start: startTime, end: endTime });
|
|
6282
6048
|
return { symbol: token.symbol, candles: response.data, success: true };
|
|
6283
6049
|
}
|
|
@@ -6756,7 +6522,6 @@ const usePerformanceOverlays = () => {
|
|
|
6756
6522
|
overlays.forEach(overlay => {
|
|
6757
6523
|
symbols.push(overlay.symbol);
|
|
6758
6524
|
});
|
|
6759
|
-
console.log("final symbols", symbols);
|
|
6760
6525
|
return symbols;
|
|
6761
6526
|
}, [overlays]);
|
|
6762
6527
|
return {
|
|
@@ -6825,24 +6590,14 @@ function useAgentWallet() {
|
|
|
6825
6590
|
* @throws MinimumPositionSizeError if any asset has less than $11 USD value
|
|
6826
6591
|
* @throws MaxAssetsPerLegError if any leg exceeds the maximum allowed assets (15)
|
|
6827
6592
|
*/
|
|
6828
|
-
async function createPosition(baseUrl, payload
|
|
6593
|
+
async function createPosition(baseUrl, payload) {
|
|
6829
6594
|
// Validate maximum assets per leg before creating position
|
|
6830
6595
|
validateMaxAssetsPerLeg(payload.longAssets, payload.shortAssets);
|
|
6831
6596
|
// Validate minimum asset size before creating position
|
|
6832
6597
|
validateMinimumAssetSize(payload.usdValue, payload.longAssets, payload.shortAssets);
|
|
6833
6598
|
const url = joinUrl(baseUrl, "/positions");
|
|
6834
|
-
// Translate display symbols to backend format
|
|
6835
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, hip3Assets) }));
|
|
6836
|
-
const translatedPayload = {
|
|
6837
|
-
...payload,
|
|
6838
|
-
longAssets: mapAssets(payload.longAssets),
|
|
6839
|
-
shortAssets: mapAssets(payload.shortAssets),
|
|
6840
|
-
assetName: payload.assetName
|
|
6841
|
-
? toBackendSymbol(payload.assetName, hip3Assets)
|
|
6842
|
-
: undefined,
|
|
6843
|
-
};
|
|
6844
6599
|
try {
|
|
6845
|
-
const resp = await apiClient.post(url,
|
|
6600
|
+
const resp = await apiClient.post(url, payload, {
|
|
6846
6601
|
headers: {
|
|
6847
6602
|
"Content-Type": "application/json",
|
|
6848
6603
|
},
|
|
@@ -6934,15 +6689,10 @@ async function adjustPosition(baseUrl, positionId, payload) {
|
|
|
6934
6689
|
throw toApiError(error);
|
|
6935
6690
|
}
|
|
6936
6691
|
}
|
|
6937
|
-
async function adjustAdvancePosition(baseUrl, positionId, payload
|
|
6692
|
+
async function adjustAdvancePosition(baseUrl, positionId, payload) {
|
|
6938
6693
|
const url = joinUrl(baseUrl, `/positions/${positionId}/adjust-advance`);
|
|
6939
|
-
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, hip3Assets) }));
|
|
6940
|
-
const translatedPayload = (payload || []).map((item) => ({
|
|
6941
|
-
longAssets: mapAssets(item.longAssets),
|
|
6942
|
-
shortAssets: mapAssets(item.shortAssets),
|
|
6943
|
-
}));
|
|
6944
6694
|
try {
|
|
6945
|
-
const resp = await apiClient.post(url,
|
|
6695
|
+
const resp = await apiClient.post(url, payload, {
|
|
6946
6696
|
headers: {
|
|
6947
6697
|
"Content-Type": "application/json",
|
|
6948
6698
|
},
|
|
@@ -7002,7 +6752,7 @@ async function updateLeverage(baseUrl, positionId, payload) {
|
|
|
7002
6752
|
}
|
|
7003
6753
|
}
|
|
7004
6754
|
|
|
7005
|
-
const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, leverage, isLong = true) => {
|
|
6755
|
+
const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, leverage, metadata, isLong = true) => {
|
|
7006
6756
|
var _a;
|
|
7007
6757
|
const entryNotional = asset.entryPrice * asset.size;
|
|
7008
6758
|
const currentNotional = currentPrice * asset.size;
|
|
@@ -7021,13 +6771,12 @@ const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, l
|
|
|
7021
6771
|
entryPositionValue: entryNotional,
|
|
7022
6772
|
initialWeight: totalInitialPositionSize > 0 ? entryNotional / totalInitialPositionSize : 0,
|
|
7023
6773
|
fundingPaid: (_a = asset.fundingPaid) !== null && _a !== void 0 ? _a : 0,
|
|
7024
|
-
|
|
7025
|
-
marketPrefix: asset.marketPrefix,
|
|
7026
|
-
collateralToken: asset.collateralToken,
|
|
6774
|
+
metadata,
|
|
7027
6775
|
};
|
|
7028
6776
|
};
|
|
7029
|
-
const buildPositionValue = (rawPositions, clearinghouseState,
|
|
6777
|
+
const buildPositionValue = (rawPositions, clearinghouseState, getAssetByName) => {
|
|
7030
6778
|
return rawPositions.map((position) => {
|
|
6779
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
7031
6780
|
let mappedPosition = {
|
|
7032
6781
|
positionId: position.positionId,
|
|
7033
6782
|
address: position.address,
|
|
@@ -7045,11 +6794,12 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
7045
6794
|
const totalInitialPositionSize = position.longAssets.reduce((acc, asset) => acc + asset.entryPrice * asset.size, 0) +
|
|
7046
6795
|
position.shortAssets.reduce((acc, asset) => acc + asset.entryPrice * asset.size, 0);
|
|
7047
6796
|
mappedPosition.longAssets = position.longAssets.map((longAsset) => {
|
|
7048
|
-
var _a, _b, _c;
|
|
7049
|
-
const
|
|
7050
|
-
const
|
|
7051
|
-
const
|
|
7052
|
-
const
|
|
6797
|
+
var _a, _b, _c, _d;
|
|
6798
|
+
const metadata = getAssetByName(longAsset.coin);
|
|
6799
|
+
const currentPrice = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.currentPrice) !== null && _a !== void 0 ? _a : 0;
|
|
6800
|
+
const assetState = (_b = clearinghouseState.assetPositions.find((ap) => ap.position.coin === longAsset.coin)) === null || _b === void 0 ? void 0 : _b.position;
|
|
6801
|
+
const leverage = (_d = (_c = assetState === null || assetState === void 0 ? void 0 : assetState.leverage) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : longAsset.leverage;
|
|
6802
|
+
const mappedPositionAssets = calculatePositionAsset(longAsset, currentPrice, totalInitialPositionSize, leverage, metadata, true);
|
|
7053
6803
|
mappedPosition.entryPositionValue +=
|
|
7054
6804
|
mappedPositionAssets.entryPositionValue;
|
|
7055
6805
|
mappedPosition.unrealizedPnl += mappedPositionAssets.unrealizedPnl;
|
|
@@ -7060,11 +6810,12 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
7060
6810
|
return mappedPositionAssets;
|
|
7061
6811
|
});
|
|
7062
6812
|
mappedPosition.shortAssets = position.shortAssets.map((shortAsset) => {
|
|
7063
|
-
var _a, _b, _c;
|
|
7064
|
-
const
|
|
7065
|
-
const
|
|
7066
|
-
const
|
|
7067
|
-
const
|
|
6813
|
+
var _a, _b, _c, _d;
|
|
6814
|
+
const metadata = getAssetByName(shortAsset.coin);
|
|
6815
|
+
const currentPrice = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.currentPrice) !== null && _a !== void 0 ? _a : 0;
|
|
6816
|
+
const assetState = (_b = clearinghouseState.assetPositions.find((ap) => ap.position.coin === shortAsset.coin)) === null || _b === void 0 ? void 0 : _b.position;
|
|
6817
|
+
const leverage = (_d = (_c = assetState === null || assetState === void 0 ? void 0 : assetState.leverage) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : shortAsset.leverage;
|
|
6818
|
+
const mappedPositionAssets = calculatePositionAsset(shortAsset, currentPrice, totalInitialPositionSize, leverage, metadata, false);
|
|
7068
6819
|
mappedPosition.entryPositionValue +=
|
|
7069
6820
|
mappedPositionAssets.entryPositionValue;
|
|
7070
6821
|
mappedPosition.unrealizedPnl += mappedPositionAssets.unrealizedPnl;
|
|
@@ -7079,8 +6830,8 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
7079
6830
|
if (position.longAssets.length === 1 && position.shortAssets.length === 1) {
|
|
7080
6831
|
const long = position.longAssets[0];
|
|
7081
6832
|
const short = position.shortAssets[0];
|
|
7082
|
-
const longMark =
|
|
7083
|
-
const shortMark =
|
|
6833
|
+
const longMark = (_b = (_a = getAssetByName(long.coin)) === null || _a === void 0 ? void 0 : _a.currentPrice) !== null && _b !== void 0 ? _b : 0;
|
|
6834
|
+
const shortMark = (_d = (_c = getAssetByName(short.coin)) === null || _c === void 0 ? void 0 : _c.currentPrice) !== null && _d !== void 0 ? _d : 0;
|
|
7084
6835
|
if (long.size > 0 && short.size > 0) {
|
|
7085
6836
|
mappedPosition.entryPriceRatio = long.entryPrice / short.entryPrice;
|
|
7086
6837
|
mappedPosition.markPriceRatio = longMark / shortMark;
|
|
@@ -7096,13 +6847,13 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
7096
6847
|
}
|
|
7097
6848
|
if (position.longAssets.length === 1 && position.shortAssets.length === 0) {
|
|
7098
6849
|
const long = position.longAssets[0];
|
|
7099
|
-
const longMark =
|
|
6850
|
+
const longMark = (_f = (_e = getAssetByName(long.coin)) === null || _e === void 0 ? void 0 : _e.currentPrice) !== null && _f !== void 0 ? _f : 0;
|
|
7100
6851
|
mappedPosition.entryPriceRatio = long.entryPrice;
|
|
7101
6852
|
mappedPosition.markPriceRatio = longMark;
|
|
7102
6853
|
}
|
|
7103
6854
|
if (position.longAssets.length === 0 && position.shortAssets.length === 1) {
|
|
7104
6855
|
const short = position.shortAssets[0];
|
|
7105
|
-
const shortMark =
|
|
6856
|
+
const shortMark = (_h = (_g = getAssetByName(short.coin)) === null || _g === void 0 ? void 0 : _g.currentPrice) !== null && _h !== void 0 ? _h : 0;
|
|
7106
6857
|
mappedPosition.entryPriceRatio = short.entryPrice;
|
|
7107
6858
|
mappedPosition.markPriceRatio = shortMark;
|
|
7108
6859
|
}
|
|
@@ -7112,93 +6863,14 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
7112
6863
|
});
|
|
7113
6864
|
};
|
|
7114
6865
|
|
|
7115
|
-
function findAssetMeta$3(coinName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7116
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
7117
|
-
if (!perpMetaAssets) {
|
|
7118
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7119
|
-
}
|
|
7120
|
-
if (desiredCollateral) {
|
|
7121
|
-
const collateralMatch = perpMetaAssets.find((a) => a.name === coinName && a.collateralToken === desiredCollateral);
|
|
7122
|
-
if (collateralMatch) {
|
|
7123
|
-
return {
|
|
7124
|
-
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7125
|
-
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7126
|
-
};
|
|
7127
|
-
}
|
|
7128
|
-
}
|
|
7129
|
-
if (coinName.includes(':')) {
|
|
7130
|
-
const [prefix, symbol] = coinName.split(':');
|
|
7131
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7132
|
-
var _a;
|
|
7133
|
-
return a.name === symbol &&
|
|
7134
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7135
|
-
});
|
|
7136
|
-
if (exactMatch) {
|
|
7137
|
-
return {
|
|
7138
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7139
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7140
|
-
};
|
|
7141
|
-
}
|
|
7142
|
-
}
|
|
7143
|
-
if (knownPrefix) {
|
|
7144
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7145
|
-
var _a;
|
|
7146
|
-
return a.name === coinName &&
|
|
7147
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7148
|
-
});
|
|
7149
|
-
if (exactMatch) {
|
|
7150
|
-
return {
|
|
7151
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7152
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7153
|
-
};
|
|
7154
|
-
}
|
|
7155
|
-
}
|
|
7156
|
-
const regularAsset = perpMetaAssets.find((a) => a.name === coinName && !a.marketPrefix);
|
|
7157
|
-
if (regularAsset) {
|
|
7158
|
-
return {
|
|
7159
|
-
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7160
|
-
marketPrefix: null,
|
|
7161
|
-
};
|
|
7162
|
-
}
|
|
7163
|
-
const hip3Asset = perpMetaAssets.find((a) => a.name === coinName && a.marketPrefix);
|
|
7164
|
-
if (hip3Asset) {
|
|
7165
|
-
return {
|
|
7166
|
-
collateralToken: (_h = hip3Asset.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7167
|
-
marketPrefix: (_j = hip3Asset.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7168
|
-
};
|
|
7169
|
-
}
|
|
7170
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7171
|
-
}
|
|
7172
|
-
function enrichPositionAssets(assets, perpMetaAssets) {
|
|
7173
|
-
return assets.map((asset) => {
|
|
7174
|
-
var _a;
|
|
7175
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
7176
|
-
return asset;
|
|
7177
|
-
}
|
|
7178
|
-
const meta = findAssetMeta$3(asset.coin, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7179
|
-
return {
|
|
7180
|
-
...asset,
|
|
7181
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7182
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7183
|
-
};
|
|
7184
|
-
});
|
|
7185
|
-
}
|
|
7186
|
-
function enrichPositions(positions, perpMetaAssets) {
|
|
7187
|
-
return positions.map((position) => ({
|
|
7188
|
-
...position,
|
|
7189
|
-
longAssets: enrichPositionAssets(position.longAssets, perpMetaAssets),
|
|
7190
|
-
shortAssets: enrichPositionAssets(position.shortAssets, perpMetaAssets),
|
|
7191
|
-
}));
|
|
7192
|
-
}
|
|
7193
6866
|
function usePosition() {
|
|
7194
6867
|
const context = useContext(PearHyperliquidContext);
|
|
7195
6868
|
if (!context) {
|
|
7196
6869
|
throw new Error('usePosition must be used within a PearHyperliquidProvider');
|
|
7197
6870
|
}
|
|
7198
6871
|
const { apiBaseUrl, isConnected } = context;
|
|
7199
|
-
const hip3Assets = useHyperliquidData((s) => s.hip3Assets);
|
|
7200
6872
|
const createPosition$1 = async (payload) => {
|
|
7201
|
-
return createPosition(apiBaseUrl, payload
|
|
6873
|
+
return createPosition(apiBaseUrl, payload);
|
|
7202
6874
|
};
|
|
7203
6875
|
const updateRiskParameters$1 = async (positionId, payload) => {
|
|
7204
6876
|
return updateRiskParameters(apiBaseUrl, positionId, payload);
|
|
@@ -7213,7 +6885,7 @@ function usePosition() {
|
|
|
7213
6885
|
return adjustPosition(apiBaseUrl, positionId, payload);
|
|
7214
6886
|
};
|
|
7215
6887
|
const adjustAdvancePosition$1 = async (positionId, payload) => {
|
|
7216
|
-
return adjustAdvancePosition(apiBaseUrl, positionId, payload
|
|
6888
|
+
return adjustAdvancePosition(apiBaseUrl, positionId, payload);
|
|
7217
6889
|
};
|
|
7218
6890
|
const updateLeverage$1 = async (positionId, leverage) => {
|
|
7219
6891
|
return updateLeverage(apiBaseUrl, positionId, { leverage });
|
|
@@ -7221,22 +6893,18 @@ function usePosition() {
|
|
|
7221
6893
|
// Open positions using WS data, with derived values
|
|
7222
6894
|
const userOpenPositions = useUserData((state) => state.rawOpenPositions);
|
|
7223
6895
|
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
7224
|
-
const
|
|
7225
|
-
const
|
|
6896
|
+
const tokenMetadata = useHyperliquidData((state) => state.tokenMetadata);
|
|
6897
|
+
const { getAssetByName } = useMarket();
|
|
7226
6898
|
const isLoading = useMemo(() => {
|
|
7227
6899
|
return userOpenPositions === null && isConnected;
|
|
7228
6900
|
}, [userOpenPositions, isConnected]);
|
|
7229
6901
|
const openPositions = useMemo(() => {
|
|
7230
|
-
if (!userOpenPositions ||
|
|
6902
|
+
if (!userOpenPositions ||
|
|
6903
|
+
!aggregatedClearingHouseState ||
|
|
6904
|
+
Object.keys(tokenMetadata).length === 0)
|
|
7231
6905
|
return null;
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
}, [
|
|
7235
|
-
userOpenPositions,
|
|
7236
|
-
aggregatedClearingHouseState,
|
|
7237
|
-
allMids,
|
|
7238
|
-
allPerpMetaAssets,
|
|
7239
|
-
]);
|
|
6906
|
+
return buildPositionValue(userOpenPositions, aggregatedClearingHouseState, getAssetByName);
|
|
6907
|
+
}, [userOpenPositions, aggregatedClearingHouseState, tokenMetadata, getAssetByName]);
|
|
7240
6908
|
return {
|
|
7241
6909
|
createPosition: createPosition$1,
|
|
7242
6910
|
updateRiskParameters: updateRiskParameters$1,
|
|
@@ -7319,98 +6987,14 @@ async function executeSpotOrder(baseUrl, payload) {
|
|
|
7319
6987
|
}
|
|
7320
6988
|
}
|
|
7321
6989
|
|
|
7322
|
-
function findAssetMeta$2(assetName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7323
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
7324
|
-
if (!perpMetaAssets) {
|
|
7325
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7326
|
-
}
|
|
7327
|
-
if (desiredCollateral) {
|
|
7328
|
-
const collateralMatch = perpMetaAssets.find((a) => a.name === assetName && a.collateralToken === desiredCollateral);
|
|
7329
|
-
if (collateralMatch) {
|
|
7330
|
-
return {
|
|
7331
|
-
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7332
|
-
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7333
|
-
};
|
|
7334
|
-
}
|
|
7335
|
-
}
|
|
7336
|
-
if (assetName.includes(':')) {
|
|
7337
|
-
const [prefix, symbol] = assetName.split(':');
|
|
7338
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7339
|
-
var _a;
|
|
7340
|
-
return a.name === symbol &&
|
|
7341
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7342
|
-
});
|
|
7343
|
-
if (exactMatch) {
|
|
7344
|
-
return {
|
|
7345
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7346
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7347
|
-
};
|
|
7348
|
-
}
|
|
7349
|
-
}
|
|
7350
|
-
if (knownPrefix) {
|
|
7351
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7352
|
-
var _a;
|
|
7353
|
-
return a.name === assetName &&
|
|
7354
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7355
|
-
});
|
|
7356
|
-
if (exactMatch) {
|
|
7357
|
-
return {
|
|
7358
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7359
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7360
|
-
};
|
|
7361
|
-
}
|
|
7362
|
-
}
|
|
7363
|
-
const regularAsset = perpMetaAssets.find((a) => a.name === assetName && !a.marketPrefix);
|
|
7364
|
-
if (regularAsset) {
|
|
7365
|
-
return {
|
|
7366
|
-
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7367
|
-
marketPrefix: null,
|
|
7368
|
-
};
|
|
7369
|
-
}
|
|
7370
|
-
const hip3Assets = perpMetaAssets.filter((a) => a.name === assetName && a.marketPrefix);
|
|
7371
|
-
if (hip3Assets.length > 0) {
|
|
7372
|
-
if (desiredCollateral) {
|
|
7373
|
-
const collateralMatch = hip3Assets.find((a) => a.collateralToken === desiredCollateral);
|
|
7374
|
-
if (collateralMatch) {
|
|
7375
|
-
return {
|
|
7376
|
-
collateralToken: (_h = collateralMatch.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7377
|
-
marketPrefix: (_j = collateralMatch.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7378
|
-
};
|
|
7379
|
-
}
|
|
7380
|
-
}
|
|
7381
|
-
const usdHMatch = hip3Assets.find((a) => a.collateralToken === 'USDH');
|
|
7382
|
-
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Assets[0];
|
|
7383
|
-
return {
|
|
7384
|
-
collateralToken: (_k = chosen.collateralToken) !== null && _k !== void 0 ? _k : 'USDC',
|
|
7385
|
-
marketPrefix: (_l = chosen.marketPrefix) !== null && _l !== void 0 ? _l : null,
|
|
7386
|
-
};
|
|
7387
|
-
}
|
|
7388
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7389
|
-
}
|
|
7390
|
-
function enrichOrderAssets$1(assets, perpMetaAssets) {
|
|
7391
|
-
if (!assets)
|
|
7392
|
-
return [];
|
|
7393
|
-
return assets.map((asset) => {
|
|
7394
|
-
var _a;
|
|
7395
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
7396
|
-
return asset;
|
|
7397
|
-
}
|
|
7398
|
-
const meta = findAssetMeta$2(asset.asset, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7399
|
-
return {
|
|
7400
|
-
...asset,
|
|
7401
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7402
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7403
|
-
};
|
|
7404
|
-
});
|
|
7405
|
-
}
|
|
7406
6990
|
function useOrders() {
|
|
7407
6991
|
const context = useContext(PearHyperliquidContext);
|
|
7408
6992
|
if (!context)
|
|
7409
6993
|
throw new Error('useOrders must be used within a PearHyperliquidProvider');
|
|
7410
6994
|
const { apiBaseUrl } = context;
|
|
7411
6995
|
const openOrders = useUserData((state) => state.openOrders);
|
|
7412
|
-
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
7413
6996
|
const isLoading = useMemo(() => openOrders === null && context.isConnected, [openOrders, context.isConnected]);
|
|
6997
|
+
const { getAssetByName } = useMarket();
|
|
7414
6998
|
const { openPositions } = usePosition();
|
|
7415
6999
|
const positionsById = useMemo(() => {
|
|
7416
7000
|
const map = new Map();
|
|
@@ -7423,22 +7007,26 @@ function useOrders() {
|
|
|
7423
7007
|
const enrichedOpenOrders = useMemo(() => {
|
|
7424
7008
|
if (!openOrders)
|
|
7425
7009
|
return null;
|
|
7010
|
+
const mapOrderAssets = (assets) => assets.map((asset) => ({
|
|
7011
|
+
...asset,
|
|
7012
|
+
metadata: getAssetByName(asset.asset),
|
|
7013
|
+
}));
|
|
7426
7014
|
return openOrders.map((ord) => {
|
|
7427
|
-
var _a, _b, _c, _d, _e;
|
|
7015
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
7428
7016
|
const isTpSl = ord.orderType === 'TP' || ord.orderType === 'SL';
|
|
7429
7017
|
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;
|
|
7430
7018
|
const pos = positionsById.get((_e = ord.positionId) !== null && _e !== void 0 ? _e : '');
|
|
7431
7019
|
let enrichedOrd = {
|
|
7432
7020
|
...ord,
|
|
7433
|
-
longAssets:
|
|
7434
|
-
shortAssets:
|
|
7021
|
+
longAssets: mapOrderAssets((_f = ord.longAssets) !== null && _f !== void 0 ? _f : []),
|
|
7022
|
+
shortAssets: mapOrderAssets((_g = ord.shortAssets) !== null && _g !== void 0 ? _g : []),
|
|
7435
7023
|
};
|
|
7024
|
+
// For TP/SL orders without assets, derive them from the position
|
|
7436
7025
|
if (isTpSl && !hasAssets && pos) {
|
|
7437
7026
|
const mapAssets = (arr) => arr.map((a) => ({
|
|
7438
7027
|
asset: a.coin,
|
|
7439
7028
|
weight: a.initialWeight,
|
|
7440
|
-
|
|
7441
|
-
collateralToken: a.collateralToken,
|
|
7029
|
+
metadata: getAssetByName(a.coin),
|
|
7442
7030
|
}));
|
|
7443
7031
|
enrichedOrd = {
|
|
7444
7032
|
...enrichedOrd,
|
|
@@ -7448,7 +7036,7 @@ function useOrders() {
|
|
|
7448
7036
|
}
|
|
7449
7037
|
return enrichedOrd;
|
|
7450
7038
|
});
|
|
7451
|
-
}, [openOrders, positionsById,
|
|
7039
|
+
}, [openOrders, positionsById, getAssetByName]);
|
|
7452
7040
|
const adjustOrder$1 = async (orderId, payload) => {
|
|
7453
7041
|
return adjustOrder(apiBaseUrl, orderId, payload);
|
|
7454
7042
|
};
|
|
@@ -7506,108 +7094,27 @@ function useSpotOrder() {
|
|
|
7506
7094
|
};
|
|
7507
7095
|
}
|
|
7508
7096
|
|
|
7509
|
-
function findAssetMeta$1(assetName, perpMetaAssets, knownPrefix, desiredCollateral) {
|
|
7510
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
7511
|
-
if (!perpMetaAssets) {
|
|
7512
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7513
|
-
}
|
|
7514
|
-
if (desiredCollateral) {
|
|
7515
|
-
const collateralMatch = perpMetaAssets.find((a) => a.name === assetName && a.collateralToken === desiredCollateral);
|
|
7516
|
-
if (collateralMatch) {
|
|
7517
|
-
return {
|
|
7518
|
-
collateralToken: (_a = collateralMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7519
|
-
marketPrefix: (_b = collateralMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7520
|
-
};
|
|
7521
|
-
}
|
|
7522
|
-
}
|
|
7523
|
-
if (assetName.includes(':')) {
|
|
7524
|
-
const [prefix, symbol] = assetName.split(':');
|
|
7525
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7526
|
-
var _a;
|
|
7527
|
-
return a.name === symbol &&
|
|
7528
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === prefix.toLowerCase();
|
|
7529
|
-
});
|
|
7530
|
-
if (exactMatch) {
|
|
7531
|
-
return {
|
|
7532
|
-
collateralToken: (_c = exactMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7533
|
-
marketPrefix: (_d = exactMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7534
|
-
};
|
|
7535
|
-
}
|
|
7536
|
-
}
|
|
7537
|
-
if (knownPrefix) {
|
|
7538
|
-
const exactMatch = perpMetaAssets.find((a) => {
|
|
7539
|
-
var _a;
|
|
7540
|
-
return a.name === assetName &&
|
|
7541
|
-
((_a = a.marketPrefix) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === knownPrefix.toLowerCase();
|
|
7542
|
-
});
|
|
7543
|
-
if (exactMatch) {
|
|
7544
|
-
return {
|
|
7545
|
-
collateralToken: (_e = exactMatch.collateralToken) !== null && _e !== void 0 ? _e : 'USDC',
|
|
7546
|
-
marketPrefix: (_f = exactMatch.marketPrefix) !== null && _f !== void 0 ? _f : null,
|
|
7547
|
-
};
|
|
7548
|
-
}
|
|
7549
|
-
}
|
|
7550
|
-
const regularAsset = perpMetaAssets.find((a) => a.name === assetName && !a.marketPrefix);
|
|
7551
|
-
if (regularAsset) {
|
|
7552
|
-
return {
|
|
7553
|
-
collateralToken: (_g = regularAsset.collateralToken) !== null && _g !== void 0 ? _g : 'USDC',
|
|
7554
|
-
marketPrefix: null,
|
|
7555
|
-
};
|
|
7556
|
-
}
|
|
7557
|
-
const hip3Assets = perpMetaAssets.filter((a) => a.name === assetName && a.marketPrefix);
|
|
7558
|
-
if (hip3Assets.length > 0) {
|
|
7559
|
-
if (desiredCollateral) {
|
|
7560
|
-
const collateralMatch = hip3Assets.find((a) => a.collateralToken === desiredCollateral);
|
|
7561
|
-
if (collateralMatch) {
|
|
7562
|
-
return {
|
|
7563
|
-
collateralToken: (_h = collateralMatch.collateralToken) !== null && _h !== void 0 ? _h : 'USDC',
|
|
7564
|
-
marketPrefix: (_j = collateralMatch.marketPrefix) !== null && _j !== void 0 ? _j : null,
|
|
7565
|
-
};
|
|
7566
|
-
}
|
|
7567
|
-
}
|
|
7568
|
-
const usdHMatch = hip3Assets.find((a) => a.collateralToken === 'USDH');
|
|
7569
|
-
const chosen = usdHMatch !== null && usdHMatch !== void 0 ? usdHMatch : hip3Assets[0];
|
|
7570
|
-
return {
|
|
7571
|
-
collateralToken: (_k = chosen.collateralToken) !== null && _k !== void 0 ? _k : 'USDC',
|
|
7572
|
-
marketPrefix: (_l = chosen.marketPrefix) !== null && _l !== void 0 ? _l : null,
|
|
7573
|
-
};
|
|
7574
|
-
}
|
|
7575
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7576
|
-
}
|
|
7577
|
-
function enrichOrderAssets(assets, perpMetaAssets) {
|
|
7578
|
-
if (!assets)
|
|
7579
|
-
return [];
|
|
7580
|
-
return assets.map((asset) => {
|
|
7581
|
-
var _a;
|
|
7582
|
-
if (asset.marketPrefix && asset.collateralToken) {
|
|
7583
|
-
return asset;
|
|
7584
|
-
}
|
|
7585
|
-
const meta = findAssetMeta$1(asset.asset, perpMetaAssets, asset.marketPrefix, asset.collateralToken);
|
|
7586
|
-
return {
|
|
7587
|
-
...asset,
|
|
7588
|
-
marketPrefix: asset.marketPrefix || meta.marketPrefix,
|
|
7589
|
-
collateralToken: (_a = asset.collateralToken) !== null && _a !== void 0 ? _a : meta.collateralToken,
|
|
7590
|
-
};
|
|
7591
|
-
});
|
|
7592
|
-
}
|
|
7593
|
-
function enrichTwapOrders(orders, perpMetaAssets) {
|
|
7594
|
-
return orders.map((order) => ({
|
|
7595
|
-
...order,
|
|
7596
|
-
longAssets: enrichOrderAssets(order.longAssets, perpMetaAssets),
|
|
7597
|
-
shortAssets: enrichOrderAssets(order.shortAssets, perpMetaAssets),
|
|
7598
|
-
}));
|
|
7599
|
-
}
|
|
7600
7097
|
function useTwap() {
|
|
7601
7098
|
const twapDetails = useUserData((state) => state.twapDetails);
|
|
7602
|
-
const allPerpMetaAssets = useHyperliquidData((state) => state.allPerpMetaAssets);
|
|
7603
7099
|
const context = useContext(PearHyperliquidContext);
|
|
7604
7100
|
if (!context)
|
|
7605
7101
|
throw new Error('useTwap must be used within a PearHyperliquidProvider');
|
|
7606
7102
|
const { apiBaseUrl } = context;
|
|
7103
|
+
const { getAssetByName } = useMarket();
|
|
7607
7104
|
const orders = useMemo(() => {
|
|
7608
|
-
const
|
|
7609
|
-
|
|
7610
|
-
|
|
7105
|
+
const mapAssets = (assets) => assets.map((asset) => ({
|
|
7106
|
+
...asset,
|
|
7107
|
+
metadata: getAssetByName(asset.asset),
|
|
7108
|
+
}));
|
|
7109
|
+
return (twapDetails !== null && twapDetails !== void 0 ? twapDetails : []).map((order) => {
|
|
7110
|
+
var _a, _b;
|
|
7111
|
+
return ({
|
|
7112
|
+
...order,
|
|
7113
|
+
longAssets: mapAssets((_a = order.longAssets) !== null && _a !== void 0 ? _a : []),
|
|
7114
|
+
shortAssets: mapAssets((_b = order.shortAssets) !== null && _b !== void 0 ? _b : []),
|
|
7115
|
+
});
|
|
7116
|
+
});
|
|
7117
|
+
}, [twapDetails, getAssetByName]);
|
|
7611
7118
|
const cancelTwap$1 = async (orderId) => {
|
|
7612
7119
|
return cancelTwap(apiBaseUrl, orderId);
|
|
7613
7120
|
};
|
|
@@ -7690,62 +7197,19 @@ function useNotifications() {
|
|
|
7690
7197
|
};
|
|
7691
7198
|
}
|
|
7692
7199
|
|
|
7693
|
-
//
|
|
7694
|
-
function
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
if (exactMatch) {
|
|
7702
|
-
return {
|
|
7703
|
-
collateralToken: (_a = exactMatch.collateralToken) !== null && _a !== void 0 ? _a : 'USDC',
|
|
7704
|
-
marketPrefix: (_b = exactMatch.marketPrefix) !== null && _b !== void 0 ? _b : null,
|
|
7705
|
-
};
|
|
7706
|
-
}
|
|
7707
|
-
// Try matching by base symbol (for non-prefixed names in data)
|
|
7708
|
-
const baseMatch = perpMetaAssets.find((a) => {
|
|
7709
|
-
const baseName = a.name.includes(':') ? a.name.split(':')[1] : a.name;
|
|
7710
|
-
return baseName === assetName;
|
|
7711
|
-
});
|
|
7712
|
-
if (baseMatch) {
|
|
7713
|
-
return {
|
|
7714
|
-
collateralToken: (_c = baseMatch.collateralToken) !== null && _c !== void 0 ? _c : 'USDC',
|
|
7715
|
-
marketPrefix: (_d = baseMatch.marketPrefix) !== null && _d !== void 0 ? _d : null,
|
|
7716
|
-
};
|
|
7717
|
-
}
|
|
7718
|
-
return { collateralToken: 'USDC', marketPrefix: null };
|
|
7719
|
-
}
|
|
7720
|
-
// Enrich a single asset with metadata
|
|
7721
|
-
function enrichAsset(asset, perpMetaAssets) {
|
|
7722
|
-
const meta = findAssetMeta(asset.asset, perpMetaAssets);
|
|
7723
|
-
return {
|
|
7724
|
-
...asset,
|
|
7725
|
-
collateralToken: meta.collateralToken,
|
|
7726
|
-
marketPrefix: meta.marketPrefix,
|
|
7727
|
-
};
|
|
7728
|
-
}
|
|
7729
|
-
// Enrich a basket item with collateral info
|
|
7730
|
-
function enrichBasketItem(item, perpMetaAssets) {
|
|
7731
|
-
const enrichedLongs = item.longAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7732
|
-
const enrichedShorts = item.shortAssets.map((a) => enrichAsset(a, perpMetaAssets));
|
|
7733
|
-
// Determine collateral type
|
|
7734
|
-
const allAssets = [...enrichedLongs, ...enrichedShorts];
|
|
7735
|
-
const hasUsdc = allAssets.some((a) => a.collateralToken === 'USDC');
|
|
7736
|
-
const hasUsdh = allAssets.some((a) => a.collateralToken === 'USDH');
|
|
7737
|
-
let collateralType = 'USDC';
|
|
7738
|
-
if (hasUsdc && hasUsdh) {
|
|
7739
|
-
collateralType = 'MIXED';
|
|
7740
|
-
}
|
|
7741
|
-
else if (hasUsdh) {
|
|
7742
|
-
collateralType = 'USDH';
|
|
7743
|
-
}
|
|
7200
|
+
// Convert a basket item to the expected type
|
|
7201
|
+
function enrichBasketItem(item) {
|
|
7202
|
+
const enrichedLongs = item.longAssets.map((a) => ({
|
|
7203
|
+
...a,
|
|
7204
|
+
}));
|
|
7205
|
+
const enrichedShorts = item.shortAssets.map((a) => ({
|
|
7206
|
+
...a,
|
|
7207
|
+
}));
|
|
7744
7208
|
return {
|
|
7745
7209
|
...item,
|
|
7746
7210
|
longAssets: enrichedLongs,
|
|
7747
7211
|
shortAssets: enrichedShorts,
|
|
7748
|
-
collateralType,
|
|
7212
|
+
collateralType: 'USDC', //TODO: change
|
|
7749
7213
|
};
|
|
7750
7214
|
}
|
|
7751
7215
|
/**
|
|
@@ -7774,86 +7238,61 @@ function filterByCollateral(baskets, filter) {
|
|
|
7774
7238
|
const useMarketDataPayload = () => {
|
|
7775
7239
|
return useMarketData((s) => s.marketData);
|
|
7776
7240
|
};
|
|
7777
|
-
//
|
|
7778
|
-
const useMarketDataAllPayload = () => {
|
|
7779
|
-
return useMarketData((s) => s.marketDataAll);
|
|
7780
|
-
};
|
|
7781
|
-
// Access perpMetaAssets for enrichment
|
|
7782
|
-
const usePerpMetaAssets = () => {
|
|
7783
|
-
return useHyperliquidData((s) => s.perpMetaAssets);
|
|
7784
|
-
};
|
|
7785
|
-
// Active baskets (with collateral and market prefix info)
|
|
7241
|
+
// Active baskets
|
|
7786
7242
|
const useActiveBaskets = (collateralFilter) => {
|
|
7787
7243
|
const data = useMarketDataPayload();
|
|
7788
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7789
7244
|
return useMemo(() => {
|
|
7790
7245
|
if (!(data === null || data === void 0 ? void 0 : data.active))
|
|
7791
7246
|
return [];
|
|
7792
|
-
const enriched = data.active.map((item) => enrichBasketItem(item
|
|
7247
|
+
const enriched = data.active.map((item) => enrichBasketItem(item));
|
|
7793
7248
|
return filterByCollateral(enriched, collateralFilter);
|
|
7794
|
-
}, [data,
|
|
7249
|
+
}, [data, collateralFilter]);
|
|
7795
7250
|
};
|
|
7796
|
-
// Top gainers
|
|
7251
|
+
// Top gainers
|
|
7797
7252
|
const useTopGainers = (limit, collateralFilter) => {
|
|
7798
7253
|
const data = useMarketDataPayload();
|
|
7799
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7800
7254
|
return useMemo(() => {
|
|
7801
7255
|
var _a;
|
|
7802
7256
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topGainers) !== null && _a !== void 0 ? _a : [];
|
|
7803
7257
|
const limited = typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
7804
|
-
const enriched = limited.map((item) => enrichBasketItem(item
|
|
7258
|
+
const enriched = limited.map((item) => enrichBasketItem(item));
|
|
7805
7259
|
return filterByCollateral(enriched, collateralFilter);
|
|
7806
|
-
}, [data,
|
|
7260
|
+
}, [data, limit, collateralFilter]);
|
|
7807
7261
|
};
|
|
7808
|
-
// Top losers
|
|
7262
|
+
// Top losers
|
|
7809
7263
|
const useTopLosers = (limit, collateralFilter) => {
|
|
7810
7264
|
const data = useMarketDataPayload();
|
|
7811
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7812
7265
|
return useMemo(() => {
|
|
7813
7266
|
var _a;
|
|
7814
7267
|
const list = (_a = data === null || data === void 0 ? void 0 : data.topLosers) !== null && _a !== void 0 ? _a : [];
|
|
7815
7268
|
const limited = typeof limit === 'number' ? list.slice(0, Math.max(0, limit)) : list;
|
|
7816
|
-
const enriched = limited.map((item) => enrichBasketItem(item
|
|
7269
|
+
const enriched = limited.map((item) => enrichBasketItem(item));
|
|
7817
7270
|
return filterByCollateral(enriched, collateralFilter);
|
|
7818
|
-
}, [data,
|
|
7271
|
+
}, [data, limit, collateralFilter]);
|
|
7819
7272
|
};
|
|
7820
|
-
// Highlighted baskets
|
|
7273
|
+
// Highlighted baskets
|
|
7821
7274
|
const useHighlightedBaskets = (collateralFilter) => {
|
|
7822
7275
|
const data = useMarketDataPayload();
|
|
7823
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7824
7276
|
return useMemo(() => {
|
|
7825
7277
|
if (!(data === null || data === void 0 ? void 0 : data.highlighted))
|
|
7826
7278
|
return [];
|
|
7827
|
-
const enriched = data.highlighted.map((item) => enrichBasketItem(item
|
|
7279
|
+
const enriched = data.highlighted.map((item) => enrichBasketItem(item));
|
|
7828
7280
|
return filterByCollateral(enriched, collateralFilter);
|
|
7829
|
-
}, [data,
|
|
7281
|
+
}, [data, collateralFilter]);
|
|
7830
7282
|
};
|
|
7831
|
-
// Watchlist baskets
|
|
7283
|
+
// Watchlist baskets
|
|
7832
7284
|
const useWatchlistBaskets = (collateralFilter) => {
|
|
7833
7285
|
const data = useMarketDataPayload();
|
|
7834
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7835
7286
|
return useMemo(() => {
|
|
7836
7287
|
if (!(data === null || data === void 0 ? void 0 : data.watchlist))
|
|
7837
7288
|
return [];
|
|
7838
|
-
const enriched = data.watchlist.map((item) => enrichBasketItem(item
|
|
7839
|
-
return filterByCollateral(enriched, collateralFilter);
|
|
7840
|
-
}, [data, perpMetaAssets, collateralFilter]);
|
|
7841
|
-
};
|
|
7842
|
-
// All baskets (with collateral and market prefix info)
|
|
7843
|
-
const useAllBaskets = (collateralFilter) => {
|
|
7844
|
-
const dataAll = useMarketDataAllPayload();
|
|
7845
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7846
|
-
return useMemo(() => {
|
|
7847
|
-
if (!(dataAll === null || dataAll === void 0 ? void 0 : dataAll.all))
|
|
7848
|
-
return [];
|
|
7849
|
-
const enriched = dataAll.all.map((item) => enrichBasketItem(item, perpMetaAssets));
|
|
7289
|
+
const enriched = data.watchlist.map((item) => enrichBasketItem(item));
|
|
7850
7290
|
return filterByCollateral(enriched, collateralFilter);
|
|
7851
|
-
}, [
|
|
7291
|
+
}, [data, collateralFilter]);
|
|
7852
7292
|
};
|
|
7853
7293
|
// Find a basket by its exact asset composition (order-insensitive)
|
|
7854
7294
|
const useFindBasket = (longs, shorts) => {
|
|
7855
7295
|
const data = useMarketDataPayload();
|
|
7856
|
-
const perpMetaAssets = usePerpMetaAssets();
|
|
7857
7296
|
return useMemo(() => {
|
|
7858
7297
|
if (!data)
|
|
7859
7298
|
return undefined;
|
|
@@ -7871,18 +7310,17 @@ const useFindBasket = (longs, shorts) => {
|
|
|
7871
7310
|
normalize(item.shortAssets) === sKey;
|
|
7872
7311
|
const found = data.active.find(match) || data.highlighted.find(match);
|
|
7873
7312
|
return found
|
|
7874
|
-
? enrichBasketItem(found
|
|
7313
|
+
? enrichBasketItem(found)
|
|
7875
7314
|
: undefined;
|
|
7876
|
-
}, [data, longs, shorts
|
|
7315
|
+
}, [data, longs, shorts]);
|
|
7877
7316
|
};
|
|
7878
7317
|
|
|
7879
|
-
async function toggleWatchlist(baseUrl, longAssets, shortAssets
|
|
7318
|
+
async function toggleWatchlist(baseUrl, longAssets, shortAssets) {
|
|
7880
7319
|
const url = joinUrl(baseUrl, '/watchlist');
|
|
7881
|
-
const mapAssets = (arr) => arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, hip3Assets) }));
|
|
7882
7320
|
try {
|
|
7883
7321
|
const response = await apiClient.post(url, {
|
|
7884
|
-
longAssets
|
|
7885
|
-
shortAssets
|
|
7322
|
+
longAssets,
|
|
7323
|
+
shortAssets,
|
|
7886
7324
|
}, { headers: { 'Content-Type': 'application/json' } });
|
|
7887
7325
|
return {
|
|
7888
7326
|
data: response.data,
|
|
@@ -7900,11 +7338,10 @@ function useWatchlist() {
|
|
|
7900
7338
|
if (!context)
|
|
7901
7339
|
throw new Error('useWatchlist must be used within a PearHyperliquidProvider');
|
|
7902
7340
|
const { apiBaseUrl, isConnected } = context;
|
|
7903
|
-
const hip3Assets = useHyperliquidData((s) => s.hip3Assets);
|
|
7904
7341
|
const marketData = useMarketDataPayload();
|
|
7905
7342
|
const isLoading = useMemo(() => !marketData && isConnected, [marketData, isConnected]);
|
|
7906
7343
|
const toggle = async (longAssets, shortAssets) => {
|
|
7907
|
-
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets
|
|
7344
|
+
const resp = await toggleWatchlist(apiBaseUrl, longAssets, shortAssets);
|
|
7908
7345
|
// Server will push updated market-data over WS; nothing to set here
|
|
7909
7346
|
return resp;
|
|
7910
7347
|
};
|
|
@@ -8162,7 +7599,6 @@ const useAllUserBalances = () => {
|
|
|
8162
7599
|
const spotState = useUserData((state) => state.spotState);
|
|
8163
7600
|
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
8164
7601
|
const rawClearinghouseStates = useHyperliquidData((state) => state.rawClearinghouseStates);
|
|
8165
|
-
const activeAssetData = useHyperliquidData((state) => state.activeAssetData);
|
|
8166
7602
|
const { longTokensMetadata, shortTokensMetadata } = useTokenSelectionMetadata();
|
|
8167
7603
|
return useMemo(() => {
|
|
8168
7604
|
const isLoading = !spotState || !aggregatedClearingHouseState;
|
|
@@ -8185,39 +7621,50 @@ const useAllUserBalances = () => {
|
|
|
8185
7621
|
}
|
|
8186
7622
|
}
|
|
8187
7623
|
}
|
|
7624
|
+
// Get available to trade from tokenMetadata for both USDC and USDH markets
|
|
7625
|
+
let availableToTradeUsdcFromAsset = 0;
|
|
8188
7626
|
let availableToTradeUsdhFromAsset = 0;
|
|
8189
|
-
//
|
|
7627
|
+
// Token metadata only contains availableToTrade for SELECTED tokens (user's long and short Tokens)
|
|
8190
7628
|
// It does NOT contain data for all tokens, so we cannot reliably use it for available to trade as used on hl trade page
|
|
8191
7629
|
// so intead, we rely on rawClearinghouseStates which provides market-specific data
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
7630
|
+
const selectedMetadataEntries = [
|
|
7631
|
+
...Object.entries(longTokensMetadata),
|
|
7632
|
+
...Object.entries(shortTokensMetadata),
|
|
7633
|
+
];
|
|
7634
|
+
selectedMetadataEntries.forEach(([symbol, metadata]) => {
|
|
7635
|
+
var _a;
|
|
7636
|
+
const availableStr = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.availableToTrade) === null || _a === void 0 ? void 0 : _a[0];
|
|
7637
|
+
if (!availableStr)
|
|
7638
|
+
return;
|
|
7639
|
+
const availableValue = truncateToTwoDecimals(parseFloat(availableStr || '0'));
|
|
7640
|
+
if ((metadata === null || metadata === void 0 ? void 0 : metadata.collateralToken) === 'USDH') {
|
|
7641
|
+
availableToTradeUsdhFromAsset = Math.max(availableToTradeUsdhFromAsset, availableValue);
|
|
7642
|
+
return;
|
|
7643
|
+
}
|
|
7644
|
+
if ((metadata === null || metadata === void 0 ? void 0 : metadata.collateralToken) === 'USDC') {
|
|
7645
|
+
availableToTradeUsdcFromAsset = Math.max(availableToTradeUsdcFromAsset, availableValue);
|
|
7646
|
+
return;
|
|
7647
|
+
}
|
|
7648
|
+
if (symbol.includes(':')) {
|
|
7649
|
+
const prefix = symbol.split(':')[0];
|
|
7650
|
+
if (prefix === 'xyz') {
|
|
7651
|
+
availableToTradeUsdcFromAsset = Math.max(availableToTradeUsdcFromAsset, availableValue);
|
|
7652
|
+
}
|
|
7653
|
+
else {
|
|
7654
|
+
availableToTradeUsdhFromAsset = Math.max(availableToTradeUsdhFromAsset, availableValue);
|
|
7655
|
+
}
|
|
7656
|
+
return;
|
|
7657
|
+
}
|
|
7658
|
+
availableToTradeUsdcFromAsset = Math.max(availableToTradeUsdcFromAsset, availableValue);
|
|
7659
|
+
});
|
|
8216
7660
|
// Calculate USDC available to trade
|
|
8217
7661
|
// Priority 1: Use value from activeAssetData if available (> 0)
|
|
8218
7662
|
// Priority 2: Calculate from USDC-specific clearinghouseState (empty prefix)
|
|
8219
7663
|
let availableToTradeUsdcValue = undefined;
|
|
8220
|
-
if (
|
|
7664
|
+
if (availableToTradeUsdcFromAsset > 0) {
|
|
7665
|
+
availableToTradeUsdcValue = availableToTradeUsdcFromAsset;
|
|
7666
|
+
}
|
|
7667
|
+
else if (rawClearinghouseStates) {
|
|
8221
7668
|
// Find USDC market (empty prefix)
|
|
8222
7669
|
const usdcMarket = rawClearinghouseStates.find(([prefix]) => prefix === '');
|
|
8223
7670
|
const usdcState = usdcMarket === null || usdcMarket === void 0 ? void 0 : usdcMarket[1];
|
|
@@ -8245,7 +7692,6 @@ const useAllUserBalances = () => {
|
|
|
8245
7692
|
spotState,
|
|
8246
7693
|
aggregatedClearingHouseState,
|
|
8247
7694
|
rawClearinghouseStates,
|
|
8248
|
-
activeAssetData,
|
|
8249
7695
|
longTokensMetadata,
|
|
8250
7696
|
shortTokensMetadata,
|
|
8251
7697
|
]);
|
|
@@ -8390,12 +7836,10 @@ const PearHyperliquidContext = createContext(undefined);
|
|
|
8390
7836
|
const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearprotocol.io', clientId = 'PEARPROTOCOLUI', wsUrl = 'wss://hl-ui.pearprotocol.io/ws', }) => {
|
|
8391
7837
|
const address = useUserData((s) => s.address);
|
|
8392
7838
|
const setAddress = useUserData((s) => s.setAddress);
|
|
8393
|
-
const
|
|
8394
|
-
const
|
|
8395
|
-
const
|
|
8396
|
-
const
|
|
8397
|
-
const setHip3MarketPrefixes = useHyperliquidData((state) => state.setHip3MarketPrefixes);
|
|
8398
|
-
const websocketsEnabled = useMemo(() => Array.isArray(perpsMetaAssets) && perpsMetaAssets.length > 0, [perpsMetaAssets]);
|
|
7839
|
+
const perpMetasByDex = useHyperliquidData((state) => state.perpMetasByDex);
|
|
7840
|
+
const setPerpDexs = useHyperliquidData((state) => state.setPerpDexs);
|
|
7841
|
+
const setPerpMetasByDex = useHyperliquidData((state) => state.setPerpMetasByDex);
|
|
7842
|
+
const websocketsEnabled = useMemo(() => perpMetasByDex !== null && perpMetasByDex.size > 0, [perpMetasByDex]);
|
|
8399
7843
|
const { handleUserFillsEvent } = useHyperliquidUserFills({
|
|
8400
7844
|
baseUrl: apiBaseUrl,
|
|
8401
7845
|
address,
|
|
@@ -8412,110 +7856,42 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-ui.pearpro
|
|
|
8412
7856
|
onUserFills: handleUserFillsEvent,
|
|
8413
7857
|
});
|
|
8414
7858
|
useEffect(() => {
|
|
8415
|
-
if (
|
|
8416
|
-
fetchAllPerpMetas()
|
|
8417
|
-
.then((
|
|
8418
|
-
const
|
|
8419
|
-
const
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
const assetWithMeta = {
|
|
8446
|
-
...asset,
|
|
8447
|
-
name: displayName,
|
|
8448
|
-
marketPrefix: prefix,
|
|
8449
|
-
collateralToken,
|
|
8450
|
-
};
|
|
8451
|
-
// Group by market prefix
|
|
8452
|
-
const allList = allAssetsByPrefix.get(prefix) || [];
|
|
8453
|
-
allList.push(assetWithMeta);
|
|
8454
|
-
allAssetsByPrefix.set(prefix, allList);
|
|
8455
|
-
if (!FILTERED_PREFIXES.includes(prefix)) {
|
|
8456
|
-
const cleanedList = assetsByPrefix.get(prefix) || [];
|
|
8457
|
-
cleanedList.push(assetWithMeta);
|
|
8458
|
-
assetsByPrefix.set(prefix, cleanedList);
|
|
8459
|
-
}
|
|
8460
|
-
}
|
|
8461
|
-
else {
|
|
8462
|
-
// Default market asset (no prefix)
|
|
8463
|
-
const assetWithMeta = {
|
|
8464
|
-
...asset,
|
|
8465
|
-
collateralToken,
|
|
8466
|
-
};
|
|
8467
|
-
// Add to default market group ("")
|
|
8468
|
-
const defaultList = assetsByPrefix.get('') || [];
|
|
8469
|
-
defaultList.push(assetWithMeta);
|
|
8470
|
-
assetsByPrefix.set('', defaultList);
|
|
8471
|
-
const allDefaultList = allAssetsByPrefix.get('') || [];
|
|
8472
|
-
allDefaultList.push(assetWithMeta);
|
|
8473
|
-
allAssetsByPrefix.set('', allDefaultList);
|
|
8474
|
-
}
|
|
8475
|
-
});
|
|
8476
|
-
});
|
|
8477
|
-
// Flatten in consistent order: default market first, then HIP3 markets alphabetically
|
|
8478
|
-
// This ensures both REST API and WebSocket data align properly
|
|
8479
|
-
const cleanedPrefixes = Array.from(assetsByPrefix.keys()).sort((a, b) => {
|
|
8480
|
-
// Empty prefix (default market) always comes first
|
|
8481
|
-
if (a === '' && b !== '')
|
|
8482
|
-
return -1;
|
|
8483
|
-
if (a !== '' && b === '')
|
|
8484
|
-
return 1;
|
|
8485
|
-
// HIP3 markets sorted alphabetically
|
|
8486
|
-
return a.localeCompare(b);
|
|
8487
|
-
});
|
|
8488
|
-
const allPrefixes = Array.from(allAssetsByPrefix.keys()).sort((a, b) => {
|
|
8489
|
-
if (a === '' && b !== '')
|
|
8490
|
-
return -1;
|
|
8491
|
-
if (a !== '' && b === '')
|
|
8492
|
-
return 1;
|
|
8493
|
-
return a.localeCompare(b);
|
|
8494
|
-
});
|
|
8495
|
-
const cleanedPerpMetas = [];
|
|
8496
|
-
const allPerpMetas = [];
|
|
8497
|
-
cleanedPrefixes.forEach((prefix) => {
|
|
8498
|
-
const assets = assetsByPrefix.get(prefix) || [];
|
|
8499
|
-
cleanedPerpMetas.push(...assets);
|
|
8500
|
-
});
|
|
8501
|
-
allPrefixes.forEach((prefix) => {
|
|
8502
|
-
const assets = allAssetsByPrefix.get(prefix) || [];
|
|
8503
|
-
allPerpMetas.push(...assets);
|
|
7859
|
+
if (perpMetasByDex === null) {
|
|
7860
|
+
Promise.all([fetchPerpDexs(), fetchAllPerpMetas()])
|
|
7861
|
+
.then(([perpDexsRes, perpMetasRes]) => {
|
|
7862
|
+
const perpDexs = perpDexsRes.data;
|
|
7863
|
+
const perpMetas = perpMetasRes.data;
|
|
7864
|
+
setPerpDexs(perpDexs);
|
|
7865
|
+
const metasByDex = new Map();
|
|
7866
|
+
perpMetas.forEach((item, perpIndex) => {
|
|
7867
|
+
var _a, _b;
|
|
7868
|
+
const dexName = perpIndex === 0
|
|
7869
|
+
? 'HYPERLIQUID'
|
|
7870
|
+
: ((_b = (_a = perpDexs[perpIndex]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : `DEX_${perpIndex}`);
|
|
7871
|
+
var collateralToken;
|
|
7872
|
+
if (item.collateralToken === 360) {
|
|
7873
|
+
collateralToken = 'USDH';
|
|
7874
|
+
}
|
|
7875
|
+
if (item.collateralToken === 0) {
|
|
7876
|
+
collateralToken = 'USDC';
|
|
7877
|
+
}
|
|
7878
|
+
if (item.collateralToken === 235) {
|
|
7879
|
+
collateralToken = 'USDE';
|
|
7880
|
+
}
|
|
7881
|
+
if (item.collateralToken === 268) {
|
|
7882
|
+
collateralToken = 'USDT';
|
|
7883
|
+
}
|
|
7884
|
+
const universeAssets = item.universe.map((asset) => ({
|
|
7885
|
+
...asset,
|
|
7886
|
+
collateralToken,
|
|
7887
|
+
}));
|
|
7888
|
+
metasByDex.set(dexName, universeAssets);
|
|
8504
7889
|
});
|
|
8505
|
-
|
|
8506
|
-
setHip3MarketPrefixes(marketPrefixes);
|
|
8507
|
-
setPerpMetaAssets(cleanedPerpMetas);
|
|
8508
|
-
setAllPerpMetaAssets(allPerpMetas);
|
|
7890
|
+
setPerpMetasByDex(metasByDex);
|
|
8509
7891
|
})
|
|
8510
7892
|
.catch(() => { });
|
|
8511
7893
|
}
|
|
8512
|
-
}, [
|
|
8513
|
-
perpsMetaAssets,
|
|
8514
|
-
setPerpMetaAssets,
|
|
8515
|
-
setAllPerpMetaAssets,
|
|
8516
|
-
setHip3Assets,
|
|
8517
|
-
setHip3MarketPrefixes,
|
|
8518
|
-
]);
|
|
7894
|
+
}, [perpMetasByDex, setPerpDexs, setPerpMetasByDex]);
|
|
8519
7895
|
const contextValue = useMemo(() => ({
|
|
8520
7896
|
// Config
|
|
8521
7897
|
clientId,
|
|
@@ -8799,4 +8175,4 @@ function getOrderTrailingInfo(order) {
|
|
|
8799
8175
|
return undefined;
|
|
8800
8176
|
}
|
|
8801
8177
|
|
|
8802
|
-
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,
|
|
8178
|
+
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, getAssetByName, getCompleteTimestamps, getKalshiMarkets, getOrderDirection, getOrderLadderConfig, getOrderLeverage, getOrderReduceOnly, getOrderTpSlTriggerType, getOrderTrailingInfo, getOrderTriggerType, getOrderTriggerValue, getOrderTwapDuration, getOrderUsdValue, getPortfolio, isBtcDomOrder, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, selectTokenMetadataBySymbols, toggleWatchlist, updateLeverage, updateRiskParameters, useAccountSummary, useActiveBaskets, useAgentWallet, useAllUserBalances, useAuth, useBasketCandles, useFindBasket, useHighlightedBaskets, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidUserFills, useHyperliquidWebSocket, useMarket, useMarketData, useMarketDataPayload, useNotifications, useOpenOrders, useOrders, usePearHyperliquid, usePerformanceOverlays, usePortfolio, usePosition, useSpotOrder, useTokenSelectionMetadata, useTopGainers, useTopLosers, useTradeHistories, useTwap, useUserSelection, useWatchlist, useWatchlistBaskets, validateMaxAssetsPerLeg, validateMinimumAssetSize, validatePositionSize };
|