@pear-protocol/hyperliquid-sdk 0.0.49 → 0.0.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clients/hyperliquid.d.ts +14 -2
- package/dist/clients/positions.d.ts +1 -1
- package/dist/clients/sync.d.ts +1 -1
- package/dist/clients/watchlist.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/useAccountSummary.d.ts +5 -0
- package/dist/hooks/useAgentWallet.d.ts +4 -9
- package/dist/hooks/usePortfolio.d.ts +1 -1
- package/dist/hooks/useTrading.d.ts +1 -8
- package/dist/hooks/useWebData.d.ts +3 -2
- package/dist/hyperliquid-websocket.d.ts +2 -1
- package/dist/index.d.ts +81 -96
- package/dist/index.js +399 -307
- package/dist/provider.d.ts +0 -20
- package/dist/store/tokenSelectionMetadataStore.d.ts +3 -2
- package/dist/types.d.ts +66 -21
- package/dist/utils/account-summary-calculator.d.ts +6 -13
- package/dist/utils/position-processor.d.ts +2 -2
- package/dist/utils/symbol-translator.d.ts +11 -0
- package/dist/utils/token-metadata-extractor.d.ts +11 -9
- package/dist/websocket.d.ts +2 -1
- package/package.json +1 -1
- package/README.md +0 -735
- package/dist/hooks/useAddress.d.ts +0 -9
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ const useUserData = create((set) => ({
|
|
|
26
26
|
accountSummary: null,
|
|
27
27
|
twapDetails: null,
|
|
28
28
|
notifications: null,
|
|
29
|
+
userExtraAgents: null,
|
|
29
30
|
setTradeHistories: (value) => set({ tradeHistories: value }),
|
|
30
31
|
setRawOpenPositions: (value) => set({ rawOpenPositions: value }),
|
|
31
32
|
setOpenOrders: (value) => set({ openOrders: value }),
|
|
@@ -40,6 +41,7 @@ const useUserData = create((set) => ({
|
|
|
40
41
|
twapDetails: null,
|
|
41
42
|
notifications: null,
|
|
42
43
|
}),
|
|
44
|
+
setUserExtraAgents: (value) => set({ userExtraAgents: value }),
|
|
43
45
|
}));
|
|
44
46
|
|
|
45
47
|
const useMarketData = create((set) => ({
|
|
@@ -50,9 +52,28 @@ const useMarketData = create((set) => ({
|
|
|
50
52
|
clean: () => set({ marketData: null, marketDataAll: null }),
|
|
51
53
|
}));
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
// Utilities for translating between display symbols and backend (prefixed) symbols
|
|
56
|
+
/**
|
|
57
|
+
* Convert a full/prefixed symbol (e.g., "xyz:XYZ100") to a display symbol (e.g., "XYZ100").
|
|
58
|
+
*/
|
|
59
|
+
function toDisplaySymbol(symbol) {
|
|
60
|
+
const parts = symbol.split(":");
|
|
61
|
+
return parts.length > 1 ? parts.slice(-1)[0] : symbol;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert a display symbol back to backend form using a provided map.
|
|
65
|
+
* If mapping is missing, returns the original symbol.
|
|
66
|
+
* @param displaySymbol e.g., "XYZ100"
|
|
67
|
+
* @param displayToFull map of display -> full (e.g., "XYZ100" -> "xyz:XYZ100")
|
|
68
|
+
*/
|
|
69
|
+
function toBackendSymbol(displaySymbol, displayToFull) {
|
|
70
|
+
var _a;
|
|
71
|
+
return (_a = displayToFull.get(displaySymbol)) !== null && _a !== void 0 ? _a : displaySymbol;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const useHyperliquidWebSocket = ({ wsUrl, address, enabled = true, }) => {
|
|
54
75
|
const { setTradeHistories, setRawOpenPositions, setOpenOrders, setAccountSummary, setTwapDetails, setNotifications, clean, } = useUserData();
|
|
55
|
-
const { setMarketData
|
|
76
|
+
const { setMarketData } = useMarketData();
|
|
56
77
|
const [lastError, setLastError] = useState(null);
|
|
57
78
|
const [lastSubscribedAddress, setLastSubscribedAddress] = useState(null);
|
|
58
79
|
// Native WebSocket connection with basic reconnection
|
|
@@ -82,30 +103,69 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
|
|
|
82
103
|
}
|
|
83
104
|
switch (dataMessage.channel) {
|
|
84
105
|
case 'trade-histories':
|
|
85
|
-
|
|
106
|
+
{
|
|
107
|
+
const list = dataMessage.data.map((item) => ({
|
|
108
|
+
...item,
|
|
109
|
+
longAssets: item.longAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
110
|
+
shortAssets: item.shortAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
111
|
+
}));
|
|
112
|
+
setTradeHistories(list);
|
|
113
|
+
}
|
|
86
114
|
break;
|
|
87
115
|
case 'open-positions':
|
|
88
|
-
|
|
116
|
+
{
|
|
117
|
+
const list = dataMessage.data.map((pos) => ({
|
|
118
|
+
...pos,
|
|
119
|
+
longAssets: pos.longAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
120
|
+
shortAssets: pos.shortAssets.map((a) => ({ ...a, coin: toDisplaySymbol(a.coin) })),
|
|
121
|
+
}));
|
|
122
|
+
setRawOpenPositions(list);
|
|
123
|
+
}
|
|
89
124
|
break;
|
|
90
125
|
case 'open-orders':
|
|
91
|
-
|
|
126
|
+
{
|
|
127
|
+
const list = dataMessage.data.map((order) => ({
|
|
128
|
+
...order,
|
|
129
|
+
longAssets: order.longAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
130
|
+
shortAssets: order.shortAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
131
|
+
}));
|
|
132
|
+
setOpenOrders(list);
|
|
133
|
+
}
|
|
92
134
|
break;
|
|
93
135
|
case 'account-summary':
|
|
94
136
|
setAccountSummary(dataMessage.data);
|
|
95
137
|
break;
|
|
96
138
|
case 'twap-details':
|
|
97
|
-
|
|
139
|
+
{
|
|
140
|
+
const list = dataMessage.data.map((twap) => ({
|
|
141
|
+
...twap,
|
|
142
|
+
longAssets: twap.longAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
143
|
+
shortAssets: twap.shortAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
144
|
+
}));
|
|
145
|
+
setTwapDetails(list);
|
|
146
|
+
}
|
|
98
147
|
break;
|
|
99
148
|
case 'notifications':
|
|
100
149
|
setNotifications(dataMessage.data);
|
|
101
150
|
break;
|
|
102
151
|
case 'market-data':
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
152
|
+
{
|
|
153
|
+
const md = dataMessage.data;
|
|
154
|
+
const mapGroup = (g) => ({
|
|
155
|
+
...g,
|
|
156
|
+
longAssets: g.longAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
157
|
+
shortAssets: g.shortAssets.map((a) => ({ ...a, asset: toDisplaySymbol(a.asset) })),
|
|
158
|
+
});
|
|
159
|
+
const mapped = {
|
|
160
|
+
active: md.active.map(mapGroup),
|
|
161
|
+
topGainers: md.topGainers.map(mapGroup),
|
|
162
|
+
topLosers: md.topLosers.map(mapGroup),
|
|
163
|
+
highlighted: md.highlighted.map(mapGroup),
|
|
164
|
+
watchlist: md.watchlist.map(mapGroup),
|
|
165
|
+
};
|
|
166
|
+
setMarketData(mapped);
|
|
167
|
+
}
|
|
107
168
|
break;
|
|
108
|
-
// 'fills-checkpoint' is intentionally ignored here
|
|
109
169
|
}
|
|
110
170
|
}
|
|
111
171
|
}
|
|
@@ -114,9 +174,15 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
|
|
|
114
174
|
}
|
|
115
175
|
}, [setTradeHistories, setRawOpenPositions, setOpenOrders, setAccountSummary, setTwapDetails, setNotifications, setMarketData]);
|
|
116
176
|
const connect = useCallback(() => {
|
|
117
|
-
if (!wsUrl)
|
|
177
|
+
if (!enabled || !wsUrl)
|
|
118
178
|
return;
|
|
119
179
|
try {
|
|
180
|
+
// Avoid opening multiple sockets if one is already active or connecting
|
|
181
|
+
if (wsRef.current &&
|
|
182
|
+
(wsRef.current.readyState === WebSocket.OPEN ||
|
|
183
|
+
wsRef.current.readyState === WebSocket.CONNECTING)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
120
186
|
manualCloseRef.current = false;
|
|
121
187
|
setReadyState(ReadyState.CONNECTING);
|
|
122
188
|
const ws = new WebSocket(wsUrl);
|
|
@@ -141,7 +207,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
|
|
|
141
207
|
catch (e) {
|
|
142
208
|
setLastError(`WebSocket connection failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
143
209
|
}
|
|
144
|
-
}, [wsUrl, handleMessage]);
|
|
210
|
+
}, [wsUrl, handleMessage, enabled]);
|
|
145
211
|
useEffect(() => {
|
|
146
212
|
connect();
|
|
147
213
|
return () => {
|
|
@@ -175,7 +241,7 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
|
|
|
175
241
|
'fills-checkpoint',
|
|
176
242
|
'notifications'
|
|
177
243
|
];
|
|
178
|
-
const globalChannels = ['market-data'
|
|
244
|
+
const globalChannels = ['market-data'];
|
|
179
245
|
if (address && address !== lastSubscribedAddress) {
|
|
180
246
|
// Unsubscribe from previous address-specific channels if exists
|
|
181
247
|
if (lastSubscribedAddress) {
|
|
@@ -225,11 +291,14 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
|
|
|
225
291
|
};
|
|
226
292
|
|
|
227
293
|
const useHyperliquidData = create((set, get) => ({
|
|
228
|
-
webData2: null,
|
|
229
294
|
allMids: null,
|
|
230
295
|
activeAssetData: null,
|
|
231
296
|
candleData: null,
|
|
232
|
-
|
|
297
|
+
finalAssetContexts: null,
|
|
298
|
+
finalAtOICaps: null,
|
|
299
|
+
aggregatedClearingHouseState: null,
|
|
300
|
+
perpMetaAssets: null,
|
|
301
|
+
hip3DisplayToFull: new Map(),
|
|
233
302
|
setAllMids: (value) => set({ allMids: value }),
|
|
234
303
|
setActiveAssetData: (value) => set((state) => ({
|
|
235
304
|
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value
|
|
@@ -268,7 +337,12 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
268
337
|
...state.activeAssetData,
|
|
269
338
|
[key]: value,
|
|
270
339
|
}
|
|
271
|
-
}))
|
|
340
|
+
})),
|
|
341
|
+
setFinalAssetContexts: (value) => set({ finalAssetContexts: value }),
|
|
342
|
+
setFinalAtOICaps: (value) => set({ finalAtOICaps: value }),
|
|
343
|
+
setAggregatedClearingHouseState: (value) => set({ aggregatedClearingHouseState: value }),
|
|
344
|
+
setPerpMetaAssets: (value) => set({ perpMetaAssets: value }),
|
|
345
|
+
setHip3DisplayToFull: (value) => set({ hip3DisplayToFull: value })
|
|
272
346
|
}));
|
|
273
347
|
|
|
274
348
|
const DEFAULT_STATE = {
|
|
@@ -408,8 +482,8 @@ const useUserSelection$1 = create((set, get) => ({
|
|
|
408
482
|
resetToDefaults: () => set((prev) => ({ ...prev, ...DEFAULT_STATE })),
|
|
409
483
|
}));
|
|
410
484
|
|
|
411
|
-
const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
412
|
-
const {
|
|
485
|
+
const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
486
|
+
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState } = useHyperliquidData();
|
|
413
487
|
const { candleInterval } = useUserSelection$1();
|
|
414
488
|
const longTokens = useUserSelection$1((s) => s.longTokens);
|
|
415
489
|
const shortTokens = useUserSelection$1((s) => s.shortTokens);
|
|
@@ -442,19 +516,69 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
442
516
|
if ('channel' in message && 'data' in message) {
|
|
443
517
|
const response = message;
|
|
444
518
|
switch (response.channel) {
|
|
445
|
-
case '
|
|
446
|
-
|
|
519
|
+
case 'webData3':
|
|
520
|
+
const webData3 = response.data;
|
|
521
|
+
const finalAssetContexts = webData3.perpDexStates.flatMap((dex) => dex.assetCtxs);
|
|
522
|
+
const finalAtOICaps = webData3.perpDexStates.flatMap((dex) => dex.perpsAtOpenInterestCap);
|
|
523
|
+
const aggregatedClearingHouseState = (() => {
|
|
524
|
+
const states = webData3.perpDexStates
|
|
525
|
+
.map((dex) => dex.clearinghouseState)
|
|
526
|
+
.filter(Boolean);
|
|
527
|
+
const sum = (values) => values.reduce((acc, v) => acc + (parseFloat(v || '0') || 0), 0);
|
|
528
|
+
const toStr = (n) => (Number.isFinite(n) ? n.toString() : '0');
|
|
529
|
+
const assetPositions = states.flatMap((s) => s.assetPositions || []);
|
|
530
|
+
const crossMaintenanceMarginUsed = toStr(sum(states.map((s) => s.crossMaintenanceMarginUsed)));
|
|
531
|
+
const crossMarginSummary = {
|
|
532
|
+
accountValue: toStr(sum(states.map((s) => { var _a; return (_a = s.crossMarginSummary) === null || _a === void 0 ? void 0 : _a.accountValue; }))),
|
|
533
|
+
totalMarginUsed: toStr(sum(states.map((s) => { var _a; return (_a = s.crossMarginSummary) === null || _a === void 0 ? void 0 : _a.totalMarginUsed; }))),
|
|
534
|
+
totalNtlPos: toStr(sum(states.map((s) => { var _a; return (_a = s.crossMarginSummary) === null || _a === void 0 ? void 0 : _a.totalNtlPos; }))),
|
|
535
|
+
totalRawUsd: toStr(sum(states.map((s) => { var _a; return (_a = s.crossMarginSummary) === null || _a === void 0 ? void 0 : _a.totalRawUsd; }))),
|
|
536
|
+
};
|
|
537
|
+
const marginSummary = {
|
|
538
|
+
accountValue: toStr(sum(states.map((s) => { var _a; return (_a = s.marginSummary) === null || _a === void 0 ? void 0 : _a.accountValue; }))),
|
|
539
|
+
totalMarginUsed: toStr(sum(states.map((s) => { var _a; return (_a = s.marginSummary) === null || _a === void 0 ? void 0 : _a.totalMarginUsed; }))),
|
|
540
|
+
totalNtlPos: toStr(sum(states.map((s) => { var _a; return (_a = s.marginSummary) === null || _a === void 0 ? void 0 : _a.totalNtlPos; }))),
|
|
541
|
+
totalRawUsd: toStr(sum(states.map((s) => { var _a; return (_a = s.marginSummary) === null || _a === void 0 ? void 0 : _a.totalRawUsd; }))),
|
|
542
|
+
};
|
|
543
|
+
const withdrawable = toStr(sum(states.map((s) => s.withdrawable)));
|
|
544
|
+
const time = Math.max(0, ...states.map((s) => s.time || 0));
|
|
545
|
+
return {
|
|
546
|
+
assetPositions,
|
|
547
|
+
crossMaintenanceMarginUsed,
|
|
548
|
+
crossMarginSummary,
|
|
549
|
+
marginSummary,
|
|
550
|
+
time,
|
|
551
|
+
withdrawable,
|
|
552
|
+
};
|
|
553
|
+
})();
|
|
554
|
+
setFinalAssetContexts(finalAssetContexts);
|
|
555
|
+
setFinalAtOICaps(finalAtOICaps);
|
|
556
|
+
setAggregatedClearingHouseState(aggregatedClearingHouseState);
|
|
447
557
|
break;
|
|
448
558
|
case 'allMids':
|
|
449
|
-
|
|
559
|
+
{
|
|
560
|
+
const data = response.data;
|
|
561
|
+
const remapped = {
|
|
562
|
+
mids: Object.fromEntries(Object.entries(data.mids || {}).map(([k, v]) => [toDisplaySymbol(k), v]))
|
|
563
|
+
};
|
|
564
|
+
setAllMids(remapped);
|
|
565
|
+
}
|
|
450
566
|
break;
|
|
451
567
|
case 'activeAssetData':
|
|
452
|
-
|
|
453
|
-
|
|
568
|
+
{
|
|
569
|
+
const assetData = response.data;
|
|
570
|
+
const symbol = toDisplaySymbol(assetData.coin);
|
|
571
|
+
const normalized = { ...assetData, coin: symbol };
|
|
572
|
+
upsertActiveAssetData(symbol, normalized);
|
|
573
|
+
}
|
|
454
574
|
break;
|
|
455
575
|
case 'candle':
|
|
456
|
-
|
|
457
|
-
|
|
576
|
+
{
|
|
577
|
+
const candleDataItem = response.data;
|
|
578
|
+
const symbol = toDisplaySymbol(candleDataItem.s || '');
|
|
579
|
+
const normalized = { ...candleDataItem, s: symbol };
|
|
580
|
+
addCandleData(symbol, normalized);
|
|
581
|
+
}
|
|
458
582
|
break;
|
|
459
583
|
default:
|
|
460
584
|
console.warn(`[HyperLiquid WS] Unknown channel: ${response.channel}`);
|
|
@@ -466,9 +590,17 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
466
590
|
console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', event.data);
|
|
467
591
|
setLastError(errorMessage);
|
|
468
592
|
}
|
|
469
|
-
}, [
|
|
593
|
+
}, [setAllMids, upsertActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState]);
|
|
470
594
|
const connect = useCallback(() => {
|
|
595
|
+
if (!enabled)
|
|
596
|
+
return;
|
|
471
597
|
try {
|
|
598
|
+
// Avoid opening multiple sockets if one is already active or connecting
|
|
599
|
+
if (wsRef.current &&
|
|
600
|
+
(wsRef.current.readyState === WebSocket.OPEN ||
|
|
601
|
+
wsRef.current.readyState === WebSocket.CONNECTING)) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
472
604
|
manualCloseRef.current = false;
|
|
473
605
|
setReadyState(ReadyState.CONNECTING);
|
|
474
606
|
const ws = new WebSocket('wss://api.hyperliquid.xyz/ws');
|
|
@@ -497,7 +629,7 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
497
629
|
catch (e) {
|
|
498
630
|
setLastError(`WebSocket connection failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
499
631
|
}
|
|
500
|
-
}, [handleMessage]);
|
|
632
|
+
}, [handleMessage, enabled]);
|
|
501
633
|
useEffect(() => {
|
|
502
634
|
connect();
|
|
503
635
|
return () => {
|
|
@@ -551,17 +683,17 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
551
683
|
const unsubscribeMessage = {
|
|
552
684
|
method: 'unsubscribe',
|
|
553
685
|
subscription: {
|
|
554
|
-
type: '
|
|
686
|
+
type: 'webData3',
|
|
555
687
|
user: subscribedAddress,
|
|
556
688
|
},
|
|
557
689
|
};
|
|
558
690
|
sendJsonMessage(unsubscribeMessage);
|
|
559
691
|
}
|
|
560
|
-
// Subscribe to
|
|
561
|
-
const
|
|
692
|
+
// Subscribe to webData3 with new address
|
|
693
|
+
const subscribeWebData3 = {
|
|
562
694
|
method: 'subscribe',
|
|
563
695
|
subscription: {
|
|
564
|
-
type: '
|
|
696
|
+
type: 'webData3',
|
|
565
697
|
user: userAddress,
|
|
566
698
|
},
|
|
567
699
|
};
|
|
@@ -570,16 +702,18 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
570
702
|
method: 'subscribe',
|
|
571
703
|
subscription: {
|
|
572
704
|
type: 'allMids',
|
|
705
|
+
dex: 'ALL_DEXS',
|
|
573
706
|
},
|
|
574
707
|
};
|
|
575
|
-
sendJsonMessage(
|
|
708
|
+
sendJsonMessage(subscribeWebData3);
|
|
576
709
|
sendJsonMessage(subscribeAllMids);
|
|
577
710
|
setSubscribedAddress(userAddress);
|
|
578
711
|
// Clear previous data when address changes
|
|
579
712
|
if (subscribedAddress && subscribedAddress !== userAddress) {
|
|
580
|
-
|
|
713
|
+
// clear aggregatedClearingHouseState
|
|
714
|
+
setAggregatedClearingHouseState(null);
|
|
581
715
|
}
|
|
582
|
-
}, [isConnected, address, subscribedAddress, sendJsonMessage,
|
|
716
|
+
}, [isConnected, address, subscribedAddress, sendJsonMessage, setAggregatedClearingHouseState]);
|
|
583
717
|
// Handle token subscriptions for activeAssetData
|
|
584
718
|
useEffect(() => {
|
|
585
719
|
if (!isConnected || !address)
|
|
@@ -4590,196 +4724,79 @@ async function logout(baseUrl, refreshTokenVal) {
|
|
|
4590
4724
|
}
|
|
4591
4725
|
}
|
|
4592
4726
|
|
|
4593
|
-
async function getAgentWallet(baseUrl, accessToken) {
|
|
4594
|
-
const url = joinUrl(baseUrl, '/agentWallet');
|
|
4595
|
-
try {
|
|
4596
|
-
const resp = await axios$1.get(url, { headers: { Authorization: `Bearer ${accessToken}` }, timeout: 30000 });
|
|
4597
|
-
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
4598
|
-
}
|
|
4599
|
-
catch (error) {
|
|
4600
|
-
throw toApiError(error);
|
|
4601
|
-
}
|
|
4602
|
-
}
|
|
4603
|
-
async function createAgentWallet(baseUrl, accessToken) {
|
|
4604
|
-
const url = joinUrl(baseUrl, '/agentWallet');
|
|
4605
|
-
try {
|
|
4606
|
-
const resp = await axios$1.post(url, undefined, { headers: { Authorization: `Bearer ${accessToken}` }, timeout: 30000 });
|
|
4607
|
-
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
4608
|
-
}
|
|
4609
|
-
catch (error) {
|
|
4610
|
-
throw toApiError(error);
|
|
4611
|
-
}
|
|
4612
|
-
}
|
|
4613
|
-
|
|
4614
|
-
function useAgentWallet({ baseUrl }) {
|
|
4615
|
-
var _a, _b, _c;
|
|
4616
|
-
const accountSummary = useUserData((state) => state.accountSummary);
|
|
4617
|
-
const setAccountSummary = useUserData((state) => state.setAccountSummary);
|
|
4618
|
-
const agentWallet = {
|
|
4619
|
-
address: ((_a = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _a === void 0 ? void 0 : _a.address) || null,
|
|
4620
|
-
name: 'Pear Protocol',
|
|
4621
|
-
status: ((_b = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _b === void 0 ? void 0 : _b.status) || null,
|
|
4622
|
-
isActive: ((_c = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _c === void 0 ? void 0 : _c.status) === 'ACTIVE',
|
|
4623
|
-
};
|
|
4624
|
-
// Derive loading/error locally for now
|
|
4625
|
-
let error = null;
|
|
4626
|
-
let loading = false;
|
|
4627
|
-
const getAuthHeader = () => {
|
|
4628
|
-
const token = localStorage.getItem('accessToken');
|
|
4629
|
-
if (!token)
|
|
4630
|
-
throw new Error('Not authenticated');
|
|
4631
|
-
return token;
|
|
4632
|
-
};
|
|
4633
|
-
const refreshAgentWalletStatus = useCallback(async () => {
|
|
4634
|
-
loading = true;
|
|
4635
|
-
error = null;
|
|
4636
|
-
try {
|
|
4637
|
-
const token = getAuthHeader();
|
|
4638
|
-
const { data } = await getAgentWallet(baseUrl, token);
|
|
4639
|
-
// Update store account summary's agentWallet
|
|
4640
|
-
const current = useUserData.getState().accountSummary;
|
|
4641
|
-
const updated = current
|
|
4642
|
-
? { ...current, agentWallet: { address: data.agentWalletAddress || '', status: data.status } }
|
|
4643
|
-
: { balanceSummary: { crossMaintenanceMarginUsed: '0', crossMarginSummary: { accountValue: '0', totalMarginUsed: '0', totalNtlPos: '0', totalRawUsd: '0' }, marginSummary: { accountValue: '0', totalMarginUsed: '0', totalNtlPos: '0', totalRawUsd: '0' }, time: Date.now(), withdrawable: '0' }, agentWallet: { address: data.agentWalletAddress || '', status: data.status } };
|
|
4644
|
-
setAccountSummary(updated);
|
|
4645
|
-
return data;
|
|
4646
|
-
}
|
|
4647
|
-
catch (e) {
|
|
4648
|
-
error = (e === null || e === void 0 ? void 0 : e.message) || 'Failed to fetch agent wallet';
|
|
4649
|
-
throw e;
|
|
4650
|
-
}
|
|
4651
|
-
finally {
|
|
4652
|
-
loading = false;
|
|
4653
|
-
}
|
|
4654
|
-
}, [baseUrl]);
|
|
4655
|
-
const createAgentWallet$1 = useCallback(async () => {
|
|
4656
|
-
loading = true;
|
|
4657
|
-
error = null;
|
|
4658
|
-
try {
|
|
4659
|
-
const token = getAuthHeader();
|
|
4660
|
-
const { data } = await createAgentWallet(baseUrl, token);
|
|
4661
|
-
// Update store account summary's agentWallet to reflect newly created address
|
|
4662
|
-
const current = useUserData.getState().accountSummary;
|
|
4663
|
-
const updated = current
|
|
4664
|
-
? { ...current, agentWallet: { address: data.agentWalletAddress, status: 'ACTIVE' } }
|
|
4665
|
-
: { balanceSummary: { crossMaintenanceMarginUsed: '0', crossMarginSummary: { accountValue: '0', totalMarginUsed: '0', totalNtlPos: '0', totalRawUsd: '0' }, marginSummary: { accountValue: '0', totalMarginUsed: '0', totalNtlPos: '0', totalRawUsd: '0' }, time: Date.now(), withdrawable: '0' }, agentWallet: { address: data.agentWalletAddress, status: 'ACTIVE' } };
|
|
4666
|
-
setAccountSummary(updated);
|
|
4667
|
-
return data;
|
|
4668
|
-
}
|
|
4669
|
-
catch (e) {
|
|
4670
|
-
error = (e === null || e === void 0 ? void 0 : e.message) || 'Failed to create agent wallet';
|
|
4671
|
-
throw e;
|
|
4672
|
-
}
|
|
4673
|
-
finally {
|
|
4674
|
-
loading = false;
|
|
4675
|
-
}
|
|
4676
|
-
}, [baseUrl]);
|
|
4677
|
-
// For user to notify that approvals are done; we re-check status
|
|
4678
|
-
const notifyAgentWalletApproved = useCallback(async () => {
|
|
4679
|
-
return refreshAgentWalletStatus();
|
|
4680
|
-
}, [refreshAgentWalletStatus]);
|
|
4681
|
-
return {
|
|
4682
|
-
agentWallet,
|
|
4683
|
-
isReady: agentWallet.isActive,
|
|
4684
|
-
loading,
|
|
4685
|
-
error,
|
|
4686
|
-
refreshAgentWalletStatus,
|
|
4687
|
-
createAgentWallet: createAgentWallet$1,
|
|
4688
|
-
notifyAgentWalletApproved,
|
|
4689
|
-
};
|
|
4690
|
-
}
|
|
4691
|
-
|
|
4692
|
-
/**
|
|
4693
|
-
* Hook to manage address (login/logout functionality)
|
|
4694
|
-
*/
|
|
4695
|
-
const useAddress = () => {
|
|
4696
|
-
const context = useContext(PearHyperliquidContext);
|
|
4697
|
-
if (!context) {
|
|
4698
|
-
throw new Error('useAddress must be used within a PearHyperliquidProvider');
|
|
4699
|
-
}
|
|
4700
|
-
return {
|
|
4701
|
-
address: context.address,
|
|
4702
|
-
setAddress: context.setAddress,
|
|
4703
|
-
clearAddress: () => context.setAddress(null),
|
|
4704
|
-
isLoggedIn: !!context.address,
|
|
4705
|
-
};
|
|
4706
|
-
};
|
|
4707
|
-
|
|
4708
4727
|
/**
|
|
4709
4728
|
* Account summary calculation utility class
|
|
4710
4729
|
*/
|
|
4711
4730
|
class AccountSummaryCalculator {
|
|
4712
|
-
constructor(
|
|
4713
|
-
this.
|
|
4731
|
+
constructor(clearinghouseState) {
|
|
4732
|
+
this.clearinghouseState = clearinghouseState;
|
|
4714
4733
|
}
|
|
4715
4734
|
/**
|
|
4716
|
-
* Calculate account summary from
|
|
4735
|
+
* Calculate account summary from real-time clearinghouse state and platform orders
|
|
4717
4736
|
*/
|
|
4718
|
-
calculateAccountSummary(platformAccountSummary,
|
|
4719
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
return platformAccountSummary;
|
|
4737
|
+
calculateAccountSummary(platformAccountSummary, registeredAgentWallets) {
|
|
4738
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
4739
|
+
if (!this.clearinghouseState) {
|
|
4740
|
+
return null;
|
|
4723
4741
|
}
|
|
4724
|
-
const clearinghouseState = this.
|
|
4725
|
-
// Calculate total limit order value from platform orders
|
|
4726
|
-
const totalLimitOrderValue = this.calculateTotalLimitOrderValue(platformOpenOrders || []);
|
|
4727
|
-
// Use real-time data from webData2 clearinghouseState
|
|
4742
|
+
const clearinghouseState = this.clearinghouseState;
|
|
4728
4743
|
const withdrawableAmount = parseFloat(clearinghouseState.withdrawable || '0');
|
|
4729
|
-
const adjustedWithdrawable = Math.max(0, withdrawableAmount -
|
|
4744
|
+
const adjustedWithdrawable = Math.max(0, withdrawableAmount - ((_a = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.totalTwapChunkUsdValue) !== null && _a !== void 0 ? _a : 0) - ((_b = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.totalLimitOrderUsdValue) !== null && _b !== void 0 ? _b : 0));
|
|
4730
4745
|
const accountSummary = {
|
|
4731
4746
|
balanceSummary: {
|
|
4732
4747
|
crossMaintenanceMarginUsed: clearinghouseState.crossMaintenanceMarginUsed || '0',
|
|
4733
4748
|
crossMarginSummary: {
|
|
4734
|
-
accountValue: ((
|
|
4735
|
-
totalMarginUsed: ((
|
|
4736
|
-
totalNtlPos: ((
|
|
4737
|
-
totalRawUsd: ((
|
|
4749
|
+
accountValue: ((_c = clearinghouseState.crossMarginSummary) === null || _c === void 0 ? void 0 : _c.accountValue) || '0',
|
|
4750
|
+
totalMarginUsed: ((_d = clearinghouseState.crossMarginSummary) === null || _d === void 0 ? void 0 : _d.totalMarginUsed) || '0',
|
|
4751
|
+
totalNtlPos: ((_e = clearinghouseState.crossMarginSummary) === null || _e === void 0 ? void 0 : _e.totalNtlPos) || '0',
|
|
4752
|
+
totalRawUsd: ((_f = clearinghouseState.crossMarginSummary) === null || _f === void 0 ? void 0 : _f.totalRawUsd) || '0'
|
|
4738
4753
|
},
|
|
4739
4754
|
marginSummary: {
|
|
4740
|
-
accountValue: ((
|
|
4741
|
-
totalMarginUsed: ((
|
|
4742
|
-
totalNtlPos: ((
|
|
4743
|
-
totalRawUsd: ((
|
|
4755
|
+
accountValue: ((_g = clearinghouseState.marginSummary) === null || _g === void 0 ? void 0 : _g.accountValue) || '0',
|
|
4756
|
+
totalMarginUsed: ((_h = clearinghouseState.marginSummary) === null || _h === void 0 ? void 0 : _h.totalMarginUsed) || '0',
|
|
4757
|
+
totalNtlPos: ((_j = clearinghouseState.marginSummary) === null || _j === void 0 ? void 0 : _j.totalNtlPos) || '0',
|
|
4758
|
+
totalRawUsd: ((_k = clearinghouseState.marginSummary) === null || _k === void 0 ? void 0 : _k.totalRawUsd) || '0'
|
|
4744
4759
|
},
|
|
4745
4760
|
time: clearinghouseState.time || Date.now(),
|
|
4746
4761
|
withdrawable: adjustedWithdrawable.toString()
|
|
4747
|
-
},
|
|
4748
|
-
agentWallet: {
|
|
4749
|
-
address: agentWalletAddress || ((_k = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWallet) === null || _k === void 0 ? void 0 : _k.address) || '',
|
|
4750
|
-
status: agentWalletStatus || ((_l = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWallet) === null || _l === void 0 ? void 0 : _l.status) || 'UNKNOWN'
|
|
4751
4762
|
}
|
|
4752
4763
|
};
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
calculateTotalLimitOrderValue(openOrders) {
|
|
4759
|
-
if (!(openOrders === null || openOrders === void 0 ? void 0 : openOrders.length)) {
|
|
4760
|
-
return 0;
|
|
4764
|
+
if (platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWalletAddress) {
|
|
4765
|
+
accountSummary.agentWallet = {
|
|
4766
|
+
address: platformAccountSummary.agentWalletAddress,
|
|
4767
|
+
status: registeredAgentWallets.find((agent) => { var _a; return agent.address.toLowerCase() === ((_a = platformAccountSummary.agentWalletAddress) === null || _a === void 0 ? void 0 : _a.toLowerCase()); }) ? 'ACTIVE' : 'EXPIRED'
|
|
4768
|
+
};
|
|
4761
4769
|
}
|
|
4762
|
-
|
|
4763
|
-
.filter(order => order.status === 'OPEN' || order.status === 'PROCESSING')
|
|
4764
|
-
.reduce((sum, order) => sum + order.usdValue / order.leverage, 0);
|
|
4765
|
-
return totalValue;
|
|
4770
|
+
return accountSummary;
|
|
4766
4771
|
}
|
|
4767
|
-
/**
|
|
4768
|
-
* Get real-time clearinghouse state from webData2
|
|
4769
|
-
*/
|
|
4770
4772
|
getClearinghouseState() {
|
|
4771
|
-
|
|
4772
|
-
return ((_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState) || null;
|
|
4773
|
+
return this.clearinghouseState || null;
|
|
4773
4774
|
}
|
|
4774
4775
|
/**
|
|
4775
4776
|
* Check if real-time data is available
|
|
4776
4777
|
*/
|
|
4777
4778
|
hasRealTimeData() {
|
|
4778
|
-
|
|
4779
|
-
return !!((_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState);
|
|
4779
|
+
return !!this.clearinghouseState;
|
|
4780
4780
|
}
|
|
4781
4781
|
}
|
|
4782
4782
|
|
|
4783
|
+
const useAccountSummary = () => {
|
|
4784
|
+
const context = useContext(PearHyperliquidContext);
|
|
4785
|
+
if (!context) {
|
|
4786
|
+
throw new Error('useAccountSummary must be used within a PearHyperliquidProvider');
|
|
4787
|
+
}
|
|
4788
|
+
const platformAccountSummary = useUserData((state) => state.accountSummary);
|
|
4789
|
+
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
4790
|
+
const registeredAgentWallets = useUserData((state) => state.userExtraAgents);
|
|
4791
|
+
const isLoading = useMemo(() => {
|
|
4792
|
+
return platformAccountSummary === null && context.isConnected && registeredAgentWallets === null && aggregatedClearingHouseState === null;
|
|
4793
|
+
}, [platformAccountSummary, context.isConnected, registeredAgentWallets, aggregatedClearingHouseState]);
|
|
4794
|
+
// Create calculator and compute account summary
|
|
4795
|
+
const calculator = new AccountSummaryCalculator(aggregatedClearingHouseState);
|
|
4796
|
+
const calculated = calculator.calculateAccountSummary(platformAccountSummary, registeredAgentWallets || []);
|
|
4797
|
+
return { data: calculated, isLoading };
|
|
4798
|
+
};
|
|
4799
|
+
|
|
4783
4800
|
const useTradeHistories = () => {
|
|
4784
4801
|
const context = useContext(PearHyperliquidContext);
|
|
4785
4802
|
if (!context) {
|
|
@@ -4805,29 +4822,7 @@ const useOpenOrders = () => {
|
|
|
4805
4822
|
}, [openOrders, context.isConnected]);
|
|
4806
4823
|
return { data: openOrders, isLoading };
|
|
4807
4824
|
};
|
|
4808
|
-
/**
|
|
4809
|
-
* Hook to access account summary with real-time calculations and loading state
|
|
4810
|
-
*/
|
|
4811
|
-
const useAccountSummary = () => {
|
|
4812
|
-
var _a, _b;
|
|
4813
|
-
const context = useContext(PearHyperliquidContext);
|
|
4814
|
-
if (!context) {
|
|
4815
|
-
throw new Error('useAccountSummary must be used within a PearHyperliquidProvider');
|
|
4816
|
-
}
|
|
4817
|
-
const openOrders = useUserData((state) => state.openOrders);
|
|
4818
|
-
const accountSummary = useUserData((state) => state.accountSummary);
|
|
4819
|
-
const webData2 = useHyperliquidData((state) => state.webData2);
|
|
4820
|
-
const isLoading = useMemo(() => {
|
|
4821
|
-
// Loading is true initially and becomes false once we get the first data
|
|
4822
|
-
return accountSummary === null && context.isConnected;
|
|
4823
|
-
}, [accountSummary, context.isConnected]);
|
|
4824
|
-
// Create calculator and compute account summary
|
|
4825
|
-
const calculator = new AccountSummaryCalculator(webData2);
|
|
4826
|
-
const calculated = calculator.calculateAccountSummary(accountSummary, openOrders, (_a = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _a === void 0 ? void 0 : _a.address, (_b = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _b === void 0 ? void 0 : _b.status);
|
|
4827
|
-
return { data: calculated, isLoading };
|
|
4828
|
-
};
|
|
4829
4825
|
|
|
4830
|
-
// Re-expose as a React hook without Zustand's selector signature
|
|
4831
4826
|
const useUserSelection = () => {
|
|
4832
4827
|
return useUserSelection$1();
|
|
4833
4828
|
};
|
|
@@ -4836,28 +4831,31 @@ const useUserSelection = () => {
|
|
|
4836
4831
|
* Hook to access webData and native WebSocket state
|
|
4837
4832
|
*/
|
|
4838
4833
|
const useWebData = () => {
|
|
4839
|
-
var _a;
|
|
4840
4834
|
const context = useContext(PearHyperliquidContext);
|
|
4841
4835
|
if (!context) {
|
|
4842
4836
|
throw new Error('useWebData must be used within a PearHyperliquidProvider');
|
|
4843
4837
|
}
|
|
4844
|
-
const
|
|
4838
|
+
const finalAssetContexts = useHyperliquidData((state) => state.finalAssetContexts);
|
|
4839
|
+
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
4840
|
+
const aggregatedClearinghouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
4841
|
+
const finalAtOICaps = useHyperliquidData((state) => state.finalAtOICaps);
|
|
4842
|
+
const hip3Assets = useHyperliquidData((state) => state.hip3DisplayToFull);
|
|
4845
4843
|
let marketDataBySymbol = {};
|
|
4846
|
-
if (
|
|
4847
|
-
const { assetCtxs, meta: { universe } } = webData2;
|
|
4844
|
+
if (finalAssetContexts && perpMetaAssets && finalAssetContexts.length === perpMetaAssets.length) {
|
|
4848
4845
|
const result = {};
|
|
4849
|
-
for (let index = 0; index <
|
|
4850
|
-
const name =
|
|
4846
|
+
for (let index = 0; index < perpMetaAssets.length; index++) {
|
|
4847
|
+
const name = perpMetaAssets[index].name;
|
|
4851
4848
|
result[name] = {
|
|
4852
|
-
asset:
|
|
4853
|
-
universe:
|
|
4849
|
+
asset: finalAssetContexts[index],
|
|
4850
|
+
universe: perpMetaAssets[index],
|
|
4854
4851
|
};
|
|
4855
4852
|
}
|
|
4856
4853
|
marketDataBySymbol = result;
|
|
4857
4854
|
}
|
|
4858
4855
|
return {
|
|
4859
|
-
|
|
4860
|
-
|
|
4856
|
+
hip3Assets,
|
|
4857
|
+
clearinghouseState: aggregatedClearinghouseState,
|
|
4858
|
+
perpsAtOpenInterestCap: finalAtOICaps,
|
|
4861
4859
|
marketDataBySymbol,
|
|
4862
4860
|
isConnected: context.nativeIsConnected,
|
|
4863
4861
|
error: context.nativeLastError,
|
|
@@ -4865,28 +4863,29 @@ const useWebData = () => {
|
|
|
4865
4863
|
};
|
|
4866
4864
|
|
|
4867
4865
|
/**
|
|
4868
|
-
* Extracts token metadata from
|
|
4866
|
+
* Extracts token metadata from aggregated WebData3 contexts and AllMids data
|
|
4869
4867
|
*/
|
|
4870
4868
|
class TokenMetadataExtractor {
|
|
4871
4869
|
/**
|
|
4872
4870
|
* Extracts comprehensive token metadata
|
|
4873
4871
|
* @param symbol - Token symbol
|
|
4874
|
-
* @param
|
|
4872
|
+
* @param perpMetaAssets - Aggregated universe assets (flattened across dexes)
|
|
4873
|
+
* @param finalAssetContexts - Aggregated asset contexts (flattened across dexes)
|
|
4875
4874
|
* @param allMids - AllMids data containing current prices
|
|
4876
4875
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
4877
4876
|
* @returns TokenMetadata or null if token not found
|
|
4878
4877
|
*/
|
|
4879
|
-
static extractTokenMetadata(symbol,
|
|
4880
|
-
if (!
|
|
4878
|
+
static extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
4879
|
+
if (!perpMetaAssets || !finalAssetContexts || !allMids) {
|
|
4881
4880
|
return null;
|
|
4882
4881
|
}
|
|
4883
|
-
// Find token index in universe
|
|
4884
|
-
const universeIndex =
|
|
4882
|
+
// Find token index in aggregated universe
|
|
4883
|
+
const universeIndex = perpMetaAssets.findIndex(asset => asset.name === symbol);
|
|
4885
4884
|
if (universeIndex === -1) {
|
|
4886
4885
|
return null;
|
|
4887
4886
|
}
|
|
4888
|
-
const universeAsset =
|
|
4889
|
-
const assetCtx =
|
|
4887
|
+
const universeAsset = perpMetaAssets[universeIndex];
|
|
4888
|
+
const assetCtx = finalAssetContexts[universeIndex];
|
|
4890
4889
|
if (!assetCtx) {
|
|
4891
4890
|
return null;
|
|
4892
4891
|
}
|
|
@@ -4926,28 +4925,29 @@ class TokenMetadataExtractor {
|
|
|
4926
4925
|
/**
|
|
4927
4926
|
* Extracts metadata for multiple tokens
|
|
4928
4927
|
* @param symbols - Array of token symbols
|
|
4929
|
-
* @param
|
|
4928
|
+
* @param perpMetaAssets - Aggregated universe assets
|
|
4929
|
+
* @param finalAssetContexts - Aggregated asset contexts
|
|
4930
4930
|
* @param allMids - AllMids data
|
|
4931
4931
|
* @param activeAssetData - Optional active asset data containing leverage information
|
|
4932
4932
|
* @returns Record of symbol to TokenMetadata
|
|
4933
4933
|
*/
|
|
4934
|
-
static extractMultipleTokensMetadata(symbols,
|
|
4934
|
+
static extractMultipleTokensMetadata(symbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData) {
|
|
4935
4935
|
const result = {};
|
|
4936
4936
|
for (const symbol of symbols) {
|
|
4937
|
-
result[symbol] = this.extractTokenMetadata(symbol,
|
|
4937
|
+
result[symbol] = this.extractTokenMetadata(symbol, perpMetaAssets, finalAssetContexts, allMids, activeAssetData);
|
|
4938
4938
|
}
|
|
4939
4939
|
return result;
|
|
4940
4940
|
}
|
|
4941
4941
|
/**
|
|
4942
|
-
* Checks if token data is available in
|
|
4942
|
+
* Checks if token data is available in aggregated universe assets
|
|
4943
4943
|
* @param symbol - Token symbol
|
|
4944
|
-
* @param
|
|
4944
|
+
* @param perpMetaAssets - Aggregated universe assets
|
|
4945
4945
|
* @returns boolean indicating if token exists in universe
|
|
4946
4946
|
*/
|
|
4947
|
-
static isTokenAvailable(symbol,
|
|
4948
|
-
if (!
|
|
4947
|
+
static isTokenAvailable(symbol, perpMetaAssets) {
|
|
4948
|
+
if (!perpMetaAssets)
|
|
4949
4949
|
return false;
|
|
4950
|
-
return
|
|
4950
|
+
return perpMetaAssets.some(asset => asset.name === symbol);
|
|
4951
4951
|
}
|
|
4952
4952
|
}
|
|
4953
4953
|
|
|
@@ -4966,16 +4966,16 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
4966
4966
|
maxLeverage: 0,
|
|
4967
4967
|
minMargin: 0,
|
|
4968
4968
|
leverageMatched: true,
|
|
4969
|
-
recompute: ({
|
|
4970
|
-
const isPriceDataReady = !!(
|
|
4969
|
+
recompute: ({ perpMetaAssets, finalAssetContexts, allMids, activeAssetData, marketData, longTokens, shortTokens }) => {
|
|
4970
|
+
const isPriceDataReady = !!(perpMetaAssets && finalAssetContexts && allMids);
|
|
4971
4971
|
// Compute metadata when ready
|
|
4972
4972
|
const longSymbols = longTokens.map((t) => t.symbol);
|
|
4973
4973
|
const shortSymbols = shortTokens.map((t) => t.symbol);
|
|
4974
4974
|
const longTokensMetadata = isPriceDataReady
|
|
4975
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(longSymbols,
|
|
4975
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(longSymbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
4976
4976
|
: {};
|
|
4977
4977
|
const shortTokensMetadata = isPriceDataReady
|
|
4978
|
-
? TokenMetadataExtractor.extractMultipleTokensMetadata(shortSymbols,
|
|
4978
|
+
? TokenMetadataExtractor.extractMultipleTokensMetadata(shortSymbols, perpMetaAssets, finalAssetContexts, allMids, activeAssetData)
|
|
4979
4979
|
: {};
|
|
4980
4980
|
// Determine loading state
|
|
4981
4981
|
const allTokens = [...longTokens, ...shortTokens];
|
|
@@ -5084,15 +5084,14 @@ const useTokenSelectionMetadataStore = create((set) => ({
|
|
|
5084
5084
|
})();
|
|
5085
5085
|
// Max leverage (minimum across all tokens)
|
|
5086
5086
|
const maxLeverage = (() => {
|
|
5087
|
-
|
|
5088
|
-
if (!((_a = webData2 === null || webData2 === void 0 ? void 0 : webData2.meta) === null || _a === void 0 ? void 0 : _a.universe))
|
|
5087
|
+
if (!perpMetaAssets)
|
|
5089
5088
|
return 0;
|
|
5090
5089
|
const allTokenSymbols = [...longTokens, ...shortTokens].map((t) => t.symbol);
|
|
5091
5090
|
if (allTokenSymbols.length === 0)
|
|
5092
5091
|
return 0;
|
|
5093
5092
|
let minLev = Infinity;
|
|
5094
5093
|
allTokenSymbols.forEach((symbol) => {
|
|
5095
|
-
const tokenUniverse =
|
|
5094
|
+
const tokenUniverse = perpMetaAssets.find((u) => u.name === symbol);
|
|
5096
5095
|
if (tokenUniverse === null || tokenUniverse === void 0 ? void 0 : tokenUniverse.maxLeverage)
|
|
5097
5096
|
minLev = Math.min(minLev, tokenUniverse.maxLeverage);
|
|
5098
5097
|
});
|
|
@@ -5144,7 +5143,8 @@ const useTokenSelectionMetadata = () => {
|
|
|
5144
5143
|
if (!context) {
|
|
5145
5144
|
throw new Error('useTokenSelection must be used within PearHyperliquidProvider');
|
|
5146
5145
|
}
|
|
5147
|
-
const
|
|
5146
|
+
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
5147
|
+
const finalAssetContexts = useHyperliquidData((state) => state.finalAssetContexts);
|
|
5148
5148
|
const allMids = useHyperliquidData((state) => state.allMids);
|
|
5149
5149
|
const activeAssetData = useHyperliquidData((state) => state.activeAssetData);
|
|
5150
5150
|
const marketData = useMarketData((state) => state.marketData);
|
|
@@ -5153,7 +5153,8 @@ const useTokenSelectionMetadata = () => {
|
|
|
5153
5153
|
// Recompute derived metadata when inputs change
|
|
5154
5154
|
useEffect(() => {
|
|
5155
5155
|
recompute({
|
|
5156
|
-
|
|
5156
|
+
perpMetaAssets,
|
|
5157
|
+
finalAssetContexts,
|
|
5157
5158
|
allMids,
|
|
5158
5159
|
activeAssetData: activeAssetData || null,
|
|
5159
5160
|
marketData: marketData || null,
|
|
@@ -5162,7 +5163,7 @@ const useTokenSelectionMetadata = () => {
|
|
|
5162
5163
|
});
|
|
5163
5164
|
// We want to recompute when token lists or upstream data change
|
|
5164
5165
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5165
|
-
}, [
|
|
5166
|
+
}, [perpMetaAssets, finalAssetContexts, allMids, activeAssetData, JSON.stringify(longTokens), JSON.stringify(shortTokens)]);
|
|
5166
5167
|
return {
|
|
5167
5168
|
// Loading states
|
|
5168
5169
|
isLoading,
|
|
@@ -5307,9 +5308,10 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
5307
5308
|
/**
|
|
5308
5309
|
* Fetch historical candle data from HyperLiquid API
|
|
5309
5310
|
*/
|
|
5310
|
-
const fetchHistoricalCandles = async (coin, startTime, endTime, interval) => {
|
|
5311
|
+
const fetchHistoricalCandles = async (coin, startTime, endTime, interval, displayToFull) => {
|
|
5312
|
+
const backendCoin = toBackendSymbol(coin, displayToFull);
|
|
5311
5313
|
const request = {
|
|
5312
|
-
req: { coin, startTime, endTime, interval },
|
|
5314
|
+
req: { coin: backendCoin, startTime, endTime, interval },
|
|
5313
5315
|
type: 'candleSnapshot',
|
|
5314
5316
|
};
|
|
5315
5317
|
try {
|
|
@@ -5337,6 +5339,40 @@ const fetchUserFillsFromHyperliquid = async (user, startTime, aggregateByTime =
|
|
|
5337
5339
|
throw toApiError(error);
|
|
5338
5340
|
}
|
|
5339
5341
|
};
|
|
5342
|
+
/**
|
|
5343
|
+
* Fetch all perp metas from HyperLiquid API
|
|
5344
|
+
* Endpoint: https://api.hyperliquid.xyz/info
|
|
5345
|
+
* Payload: { "type": "allPerpMetas" }
|
|
5346
|
+
*/
|
|
5347
|
+
const fetchAllPerpMetas = async () => {
|
|
5348
|
+
const request = { type: 'allPerpMetas' };
|
|
5349
|
+
try {
|
|
5350
|
+
const response = await axios$1.post('https://api.hyperliquid.xyz/info', request, {
|
|
5351
|
+
headers: { 'Content-Type': 'application/json' },
|
|
5352
|
+
});
|
|
5353
|
+
return { data: response.data, status: response.status, headers: response.headers };
|
|
5354
|
+
}
|
|
5355
|
+
catch (error) {
|
|
5356
|
+
throw toApiError(error);
|
|
5357
|
+
}
|
|
5358
|
+
};
|
|
5359
|
+
/**
|
|
5360
|
+
* Fetch extra agent approvals for a given user from HyperLiquid API
|
|
5361
|
+
* Endpoint: https://api.hyperliquid.xyz/info
|
|
5362
|
+
* Payload: { "type": "extraAgents", "user": "0x..." }
|
|
5363
|
+
*/
|
|
5364
|
+
const fetchExtraAgents = async (user) => {
|
|
5365
|
+
const request = { type: 'extraAgents', user };
|
|
5366
|
+
try {
|
|
5367
|
+
const response = await axios$1.post('https://api.hyperliquid.xyz/info', request, {
|
|
5368
|
+
headers: { 'Content-Type': 'application/json' },
|
|
5369
|
+
});
|
|
5370
|
+
return { data: response.data, status: response.status, headers: response.headers };
|
|
5371
|
+
}
|
|
5372
|
+
catch (error) {
|
|
5373
|
+
throw toApiError(error);
|
|
5374
|
+
}
|
|
5375
|
+
};
|
|
5340
5376
|
|
|
5341
5377
|
const useHistoricalPriceData = () => {
|
|
5342
5378
|
const context = useContext(PearHyperliquidContext);
|
|
@@ -5417,9 +5453,10 @@ const useHistoricalPriceData = () => {
|
|
|
5417
5453
|
setTokenLoading(token.symbol, true);
|
|
5418
5454
|
});
|
|
5419
5455
|
try {
|
|
5456
|
+
const displayToFull = useHyperliquidData.getState().hip3DisplayToFull;
|
|
5420
5457
|
const fetchPromises = tokensToFetch.map(async (token) => {
|
|
5421
5458
|
try {
|
|
5422
|
-
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval);
|
|
5459
|
+
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval, displayToFull);
|
|
5423
5460
|
addHistoricalPriceData(token.symbol, interval, response.data, { start: startTime, end: endTime });
|
|
5424
5461
|
return { symbol: token.symbol, candles: response.data, success: true };
|
|
5425
5462
|
}
|
|
@@ -5907,6 +5944,50 @@ const usePerformanceOverlays = () => {
|
|
|
5907
5944
|
};
|
|
5908
5945
|
};
|
|
5909
5946
|
|
|
5947
|
+
async function createAgentWallet(baseUrl, accessToken) {
|
|
5948
|
+
const url = joinUrl(baseUrl, '/agentWallet');
|
|
5949
|
+
try {
|
|
5950
|
+
const resp = await axios$1.post(url, undefined, { headers: { Authorization: `Bearer ${accessToken}` }, timeout: 30000 });
|
|
5951
|
+
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
5952
|
+
}
|
|
5953
|
+
catch (error) {
|
|
5954
|
+
throw toApiError(error);
|
|
5955
|
+
}
|
|
5956
|
+
}
|
|
5957
|
+
|
|
5958
|
+
function useAgentWallet() {
|
|
5959
|
+
const context = useContext(PearHyperliquidContext);
|
|
5960
|
+
if (!context) {
|
|
5961
|
+
throw new Error('usePortfolio must be used within a PearHyperliquidProvider');
|
|
5962
|
+
}
|
|
5963
|
+
const { apiBaseUrl, address, accessToken, isAuthenticated } = context;
|
|
5964
|
+
const setAgentWallets = useUserData((state) => state.setUserExtraAgents);
|
|
5965
|
+
const refreshAgentWalletStatus = useCallback(async () => {
|
|
5966
|
+
const hlAgentWallets = await fetchExtraAgents(address);
|
|
5967
|
+
setAgentWallets((hlAgentWallets === null || hlAgentWallets === void 0 ? void 0 : hlAgentWallets.data) || []);
|
|
5968
|
+
}, [address]);
|
|
5969
|
+
useEffect(() => {
|
|
5970
|
+
if (!address)
|
|
5971
|
+
return;
|
|
5972
|
+
refreshAgentWalletStatus();
|
|
5973
|
+
}, [address, refreshAgentWalletStatus]);
|
|
5974
|
+
const createAgentWallet$1 = useCallback(async () => {
|
|
5975
|
+
if (!isAuthenticated || !accessToken) {
|
|
5976
|
+
throw new Error('Not authenticated');
|
|
5977
|
+
}
|
|
5978
|
+
const response = await createAgentWallet(apiBaseUrl, accessToken);
|
|
5979
|
+
return response.data;
|
|
5980
|
+
}, [apiBaseUrl, accessToken, isAuthenticated]);
|
|
5981
|
+
const notifyAgentWalletApproved = useCallback(async () => {
|
|
5982
|
+
return refreshAgentWalletStatus();
|
|
5983
|
+
}, [refreshAgentWalletStatus]);
|
|
5984
|
+
return {
|
|
5985
|
+
refreshAgentWalletStatus,
|
|
5986
|
+
createAgentWallet: createAgentWallet$1,
|
|
5987
|
+
notifyAgentWalletApproved,
|
|
5988
|
+
};
|
|
5989
|
+
}
|
|
5990
|
+
|
|
5910
5991
|
/**
|
|
5911
5992
|
* Sync external fills into Pear Hyperliquid service (POST /sync/fills)
|
|
5912
5993
|
*/
|
|
@@ -5926,8 +6007,8 @@ const syncFills = async (baseUrl, accessToken, payload) => {
|
|
|
5926
6007
|
/**
|
|
5927
6008
|
* Convenience: fetch user fills from HyperLiquid, then sync them to Pear backend
|
|
5928
6009
|
*/
|
|
5929
|
-
const syncUserFillsFromHyperliquid = async (baseUrl, accessToken, user, aggregateByTime = true) => {
|
|
5930
|
-
const firstStartTime =
|
|
6010
|
+
const syncUserFillsFromHyperliquid = async (baseUrl, accessToken, user, aggregateByTime = true, lastSyncAt = null) => {
|
|
6011
|
+
const firstStartTime = lastSyncAt ? Number(lastSyncAt) : 1735660800000;
|
|
5931
6012
|
const allFills = [];
|
|
5932
6013
|
const seenTids = new Set();
|
|
5933
6014
|
let startTime = firstStartTime;
|
|
@@ -5964,6 +6045,7 @@ function useAutoSyncFills(options) {
|
|
|
5964
6045
|
const [isSyncing, setIsSyncing] = useState(false);
|
|
5965
6046
|
const mountedRef = useRef(true);
|
|
5966
6047
|
const runningRef = useRef(null);
|
|
6048
|
+
const lastSyncedAt = useUserData((state) => { var _a; return (_a = state.accountSummary) === null || _a === void 0 ? void 0 : _a.lastSyncedAt; });
|
|
5967
6049
|
useEffect(() => {
|
|
5968
6050
|
mountedRef.current = true;
|
|
5969
6051
|
return () => { mountedRef.current = false; };
|
|
@@ -5975,13 +6057,15 @@ function useAutoSyncFills(options) {
|
|
|
5975
6057
|
if (!canRun)
|
|
5976
6058
|
return;
|
|
5977
6059
|
if (runningRef.current)
|
|
5978
|
-
return;
|
|
6060
|
+
return;
|
|
6061
|
+
if (!useUserData.getState().accountSummary)
|
|
6062
|
+
return;
|
|
5979
6063
|
setIsSyncing(true);
|
|
5980
6064
|
setError(null);
|
|
5981
6065
|
const promise = (async () => {
|
|
5982
6066
|
var _a;
|
|
5983
6067
|
try {
|
|
5984
|
-
const { data } = await syncUserFillsFromHyperliquid(baseUrl, accessToken, address, aggregateByTime);
|
|
6068
|
+
const { data } = await syncUserFillsFromHyperliquid(baseUrl, accessToken, address, aggregateByTime, lastSyncedAt);
|
|
5985
6069
|
if (!mountedRef.current)
|
|
5986
6070
|
return;
|
|
5987
6071
|
setLastResult(data);
|
|
@@ -6000,7 +6084,7 @@ function useAutoSyncFills(options) {
|
|
|
6000
6084
|
})();
|
|
6001
6085
|
runningRef.current = promise;
|
|
6002
6086
|
await promise;
|
|
6003
|
-
}, [canRun, baseUrl, accessToken, address, aggregateByTime]);
|
|
6087
|
+
}, [canRun, baseUrl, accessToken, address, aggregateByTime, lastSyncedAt]);
|
|
6004
6088
|
useEffect(() => {
|
|
6005
6089
|
if (!canRun)
|
|
6006
6090
|
return;
|
|
@@ -6106,12 +6190,19 @@ function validatePositionSize(usdValue, longAssets, shortAssets) {
|
|
|
6106
6190
|
* Caller should supply an accessToken from localStorage.getItem('accessToken')
|
|
6107
6191
|
* @throws MinimumPositionSizeError if any asset has less than $11 USD value
|
|
6108
6192
|
*/
|
|
6109
|
-
async function createPosition(baseUrl, accessToken, payload) {
|
|
6193
|
+
async function createPosition(baseUrl, accessToken, payload, displayToFull) {
|
|
6110
6194
|
// Validate minimum asset size before creating position
|
|
6111
6195
|
validateMinimumAssetSize(payload.usdValue, payload.longAssets, payload.shortAssets);
|
|
6112
6196
|
const url = joinUrl(baseUrl, "/positions");
|
|
6197
|
+
// Translate display symbols to backend format
|
|
6198
|
+
const mapAssets = (arr) => arr === null || arr === void 0 ? void 0 : arr.map((a) => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
6199
|
+
const translatedPayload = {
|
|
6200
|
+
...payload,
|
|
6201
|
+
longAssets: mapAssets(payload.longAssets),
|
|
6202
|
+
shortAssets: mapAssets(payload.shortAssets),
|
|
6203
|
+
};
|
|
6113
6204
|
try {
|
|
6114
|
-
const resp = await axios$1.post(url,
|
|
6205
|
+
const resp = await axios$1.post(url, translatedPayload, {
|
|
6115
6206
|
headers: {
|
|
6116
6207
|
"Content-Type": "application/json",
|
|
6117
6208
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -6250,7 +6341,7 @@ const calculatePositionAsset = (asset, currentPrice, totalInitialPositionSize, l
|
|
|
6250
6341
|
initialWeight: totalInitialPositionSize > 0 ? entryNotional / totalInitialPositionSize : 0,
|
|
6251
6342
|
};
|
|
6252
6343
|
};
|
|
6253
|
-
const buildPositionValue = (rawPositions,
|
|
6344
|
+
const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
6254
6345
|
return rawPositions.map((position) => {
|
|
6255
6346
|
let mappedPosition = {
|
|
6256
6347
|
positionId: position.positionId,
|
|
@@ -6269,7 +6360,7 @@ const buildPositionValue = (rawPositions, webData2, allMids) => {
|
|
|
6269
6360
|
mappedPosition.longAssets = position.longAssets.map(longAsset => {
|
|
6270
6361
|
var _a, _b, _c;
|
|
6271
6362
|
const currentPrice = parseFloat(allMids.mids[longAsset.coin]);
|
|
6272
|
-
const assetState = (_a =
|
|
6363
|
+
const assetState = (_a = clearinghouseState.assetPositions.find(ap => toDisplaySymbol(ap.position.coin) === longAsset.coin)) === null || _a === void 0 ? void 0 : _a.position;
|
|
6273
6364
|
const leverage = (_c = (_b = assetState === null || assetState === void 0 ? void 0 : assetState.leverage) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : 0;
|
|
6274
6365
|
const mappedPositionAssets = calculatePositionAsset(longAsset, currentPrice, totalInitialPositionSize, leverage, true);
|
|
6275
6366
|
mappedPosition.entryPositionValue += mappedPositionAssets.entryPositionValue;
|
|
@@ -6283,7 +6374,7 @@ const buildPositionValue = (rawPositions, webData2, allMids) => {
|
|
|
6283
6374
|
mappedPosition.shortAssets = position.shortAssets.map(shortAsset => {
|
|
6284
6375
|
var _a, _b, _c;
|
|
6285
6376
|
const currentPrice = parseFloat(allMids.mids[shortAsset.coin]);
|
|
6286
|
-
const assetState = (_a =
|
|
6377
|
+
const assetState = (_a = clearinghouseState.assetPositions.find(ap => toDisplaySymbol(ap.position.coin) === shortAsset.coin)) === null || _a === void 0 ? void 0 : _a.position;
|
|
6287
6378
|
const leverage = (_c = (_b = assetState === null || assetState === void 0 ? void 0 : assetState.leverage) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : 0;
|
|
6288
6379
|
const mappedPositionAssets = calculatePositionAsset(shortAsset, currentPrice, totalInitialPositionSize, leverage, false);
|
|
6289
6380
|
mappedPosition.entryPositionValue += mappedPositionAssets.entryPositionValue;
|
|
@@ -6316,11 +6407,12 @@ function usePosition() {
|
|
|
6316
6407
|
throw new Error('usePosition must be used within a PearHyperliquidProvider');
|
|
6317
6408
|
}
|
|
6318
6409
|
const { apiBaseUrl, accessToken, isConnected } = context;
|
|
6410
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
6319
6411
|
// Create position API action
|
|
6320
6412
|
const createPosition$1 = async (payload) => {
|
|
6321
6413
|
if (!accessToken)
|
|
6322
6414
|
throw new Error('Not authenticated');
|
|
6323
|
-
return createPosition(apiBaseUrl, accessToken, payload);
|
|
6415
|
+
return createPosition(apiBaseUrl, accessToken, payload, displayToFull);
|
|
6324
6416
|
};
|
|
6325
6417
|
// Update TP/SL risk parameters for a position
|
|
6326
6418
|
const updateRiskParameters$1 = async (positionId, payload) => {
|
|
@@ -6348,16 +6440,16 @@ function usePosition() {
|
|
|
6348
6440
|
};
|
|
6349
6441
|
// Open positions using WS data, with derived values
|
|
6350
6442
|
const userOpenPositions = useUserData((state) => state.rawOpenPositions);
|
|
6351
|
-
const
|
|
6443
|
+
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
6352
6444
|
const allMids = useHyperliquidData((state) => state.allMids);
|
|
6353
6445
|
const isLoading = useMemo(() => {
|
|
6354
6446
|
return userOpenPositions === null && isConnected;
|
|
6355
6447
|
}, [userOpenPositions, isConnected]);
|
|
6356
6448
|
const openPositions = useMemo(() => {
|
|
6357
|
-
if (!userOpenPositions || !
|
|
6449
|
+
if (!userOpenPositions || !aggregatedClearingHouseState || !allMids)
|
|
6358
6450
|
return null;
|
|
6359
|
-
return buildPositionValue(userOpenPositions,
|
|
6360
|
-
}, [userOpenPositions,
|
|
6451
|
+
return buildPositionValue(userOpenPositions, aggregatedClearingHouseState, allMids);
|
|
6452
|
+
}, [userOpenPositions, aggregatedClearingHouseState, allMids]);
|
|
6361
6453
|
return { createPosition: createPosition$1, updateRiskParameters: updateRiskParameters$1, closePosition: closePosition$1, closeAllPositions: closeAllPositions$1, adjustPosition: adjustPosition$1, openPositions, isLoading };
|
|
6362
6454
|
}
|
|
6363
6455
|
|
|
@@ -6418,7 +6510,6 @@ function useOrders() {
|
|
|
6418
6510
|
const pos = positionsById.get((_e = ord.positionId) !== null && _e !== void 0 ? _e : '');
|
|
6419
6511
|
if (!isTpSl || !pos)
|
|
6420
6512
|
return ord;
|
|
6421
|
-
// Build order assets from position weights when TP/SL has no assets
|
|
6422
6513
|
const mapAssets = (arr) => arr.map((a) => ({ asset: a.coin, weight: a.initialWeight }));
|
|
6423
6514
|
if (!hasAssets) {
|
|
6424
6515
|
return {
|
|
@@ -6427,7 +6518,6 @@ function useOrders() {
|
|
|
6427
6518
|
shortAssets: mapAssets(pos.shortAssets),
|
|
6428
6519
|
};
|
|
6429
6520
|
}
|
|
6430
|
-
// Leverage is now tracked per-asset in positions; keep order leverage as-is
|
|
6431
6521
|
return ord;
|
|
6432
6522
|
});
|
|
6433
6523
|
}, [openOrders, positionsById]);
|
|
@@ -6511,7 +6601,6 @@ function useNotifications() {
|
|
|
6511
6601
|
if (!isAuthenticated || !accessToken)
|
|
6512
6602
|
throw new Error('Not authenticated');
|
|
6513
6603
|
const { data } = await markNotificationsRead(apiBaseUrl, accessToken, timestampMs);
|
|
6514
|
-
// Optimistic local update for immediate UI feedback
|
|
6515
6604
|
if (notifications) {
|
|
6516
6605
|
const updated = notifications.map((n) => {
|
|
6517
6606
|
const created = Date.parse(n.created_at);
|
|
@@ -6608,10 +6697,11 @@ const useFindBasket = (longs, shorts) => {
|
|
|
6608
6697
|
}, [data, longs, shorts]);
|
|
6609
6698
|
};
|
|
6610
6699
|
|
|
6611
|
-
async function toggleWatchlist(baseUrl, accessToken, longAssets, shortAssets) {
|
|
6700
|
+
async function toggleWatchlist(baseUrl, accessToken, longAssets, shortAssets, displayToFull) {
|
|
6612
6701
|
const url = joinUrl(baseUrl, '/watchlist');
|
|
6702
|
+
const mapAssets = (arr) => arr.map(a => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
6613
6703
|
try {
|
|
6614
|
-
const response = await axios$1.post(url, { longAssets, shortAssets }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` } });
|
|
6704
|
+
const response = await axios$1.post(url, { longAssets: mapAssets(longAssets), shortAssets: mapAssets(shortAssets) }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` } });
|
|
6615
6705
|
return { data: response.data, status: response.status, headers: response.headers };
|
|
6616
6706
|
}
|
|
6617
6707
|
catch (error) {
|
|
@@ -6624,12 +6714,13 @@ function useWatchlist() {
|
|
|
6624
6714
|
if (!context)
|
|
6625
6715
|
throw new Error('useWatchlist must be used within a PearHyperliquidProvider');
|
|
6626
6716
|
const { apiBaseUrl, accessToken, isConnected } = context;
|
|
6717
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
6627
6718
|
const marketData = useMarketDataPayload();
|
|
6628
6719
|
const isLoading = useMemo(() => !marketData && isConnected, [marketData, isConnected]);
|
|
6629
6720
|
const toggle = async (longAssets, shortAssets) => {
|
|
6630
6721
|
if (!accessToken)
|
|
6631
6722
|
throw new Error('Not authenticated');
|
|
6632
|
-
const resp = await toggleWatchlist(apiBaseUrl, accessToken, longAssets, shortAssets);
|
|
6723
|
+
const resp = await toggleWatchlist(apiBaseUrl, accessToken, longAssets, shortAssets, displayToFull);
|
|
6633
6724
|
// Server will push updated market-data over WS; nothing to set here
|
|
6634
6725
|
return resp;
|
|
6635
6726
|
};
|
|
@@ -6656,7 +6747,7 @@ async function getPortfolio(baseUrl, accessToken) {
|
|
|
6656
6747
|
/**
|
|
6657
6748
|
* Hook to fetch and manage portfolio data
|
|
6658
6749
|
* Returns bucketed volume, open interest snapshot, win/loss trade counts,
|
|
6659
|
-
* and overall metrics
|
|
6750
|
+
* and overall metrics
|
|
6660
6751
|
*/
|
|
6661
6752
|
function usePortfolio() {
|
|
6662
6753
|
const context = useContext(PearHyperliquidContext);
|
|
@@ -6700,23 +6791,51 @@ const PearHyperliquidContext = createContext(undefined);
|
|
|
6700
6791
|
*/
|
|
6701
6792
|
const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearprotocol.io', clientId = 'PEARPROTOCOLUI', wsUrl = 'wss://hl-v2.pearprotocol.io/ws', }) => {
|
|
6702
6793
|
const [address, setAddress] = useState(null);
|
|
6794
|
+
const perpsMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
6795
|
+
const setPerpMetaAssets = useHyperliquidData((state) => state.setPerpMetaAssets);
|
|
6796
|
+
const setHip3DisplayToFull = useHyperliquidData((state) => state.setHip3DisplayToFull);
|
|
6797
|
+
const websocketsEnabled = useMemo(() => Array.isArray(perpsMetaAssets) && perpsMetaAssets.length > 0, [perpsMetaAssets]);
|
|
6703
6798
|
// WebSocket connection and data (Pear API)
|
|
6704
6799
|
const { isConnected, lastError } = useHyperliquidWebSocket({
|
|
6705
6800
|
wsUrl,
|
|
6706
6801
|
address,
|
|
6802
|
+
enabled: websocketsEnabled,
|
|
6707
6803
|
});
|
|
6708
6804
|
// HyperLiquid native WebSocket connection
|
|
6709
6805
|
const { isConnected: nativeIsConnected, lastError: nativeLastError } = useHyperliquidNativeWebSocket({
|
|
6710
6806
|
address,
|
|
6807
|
+
enabled: websocketsEnabled,
|
|
6711
6808
|
});
|
|
6712
6809
|
// Auth hook
|
|
6713
|
-
// Auth state inside provider (replaces useAuth internal state)
|
|
6714
6810
|
const [authStatus, setAuthStatus] = useState(AuthStatus.Idle);
|
|
6715
6811
|
const [user, setUser] = useState(null);
|
|
6716
6812
|
const [authError, setAuthError] = useState(null);
|
|
6717
6813
|
const [accessToken, setAccessToken] = useState(null);
|
|
6718
6814
|
const isAuthenticated = useMemo(() => !!accessToken, [accessToken]);
|
|
6719
|
-
|
|
6815
|
+
useEffect(() => {
|
|
6816
|
+
if (perpsMetaAssets === null) {
|
|
6817
|
+
fetchAllPerpMetas().then(res => {
|
|
6818
|
+
const aggregatedPerpMetas = res.data.flatMap(item => item.universe);
|
|
6819
|
+
const hip3Map = new Map();
|
|
6820
|
+
const displayToFull = new Map();
|
|
6821
|
+
const cleanedPerpMetas = aggregatedPerpMetas.map((asset) => {
|
|
6822
|
+
var _a;
|
|
6823
|
+
const [maybePrefix, maybeMarket] = asset.name.split(":");
|
|
6824
|
+
if (maybeMarket) {
|
|
6825
|
+
const prefix = maybePrefix.toLowerCase();
|
|
6826
|
+
const market = maybeMarket;
|
|
6827
|
+
const existing = (_a = hip3Map.get(prefix)) !== null && _a !== void 0 ? _a : [];
|
|
6828
|
+
hip3Map.set(prefix, [...existing, market]);
|
|
6829
|
+
displayToFull.set(market, `${prefix}:${market}`);
|
|
6830
|
+
return { ...asset, name: market };
|
|
6831
|
+
}
|
|
6832
|
+
return asset;
|
|
6833
|
+
});
|
|
6834
|
+
setHip3DisplayToFull(displayToFull);
|
|
6835
|
+
setPerpMetaAssets(cleanedPerpMetas);
|
|
6836
|
+
}).catch(() => { });
|
|
6837
|
+
}
|
|
6838
|
+
}, [perpsMetaAssets, setPerpMetaAssets, setHip3DisplayToFull]);
|
|
6720
6839
|
useEffect(() => {
|
|
6721
6840
|
const access = localStorage.getItem('accessToken');
|
|
6722
6841
|
if (access) {
|
|
@@ -6807,8 +6926,6 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
6807
6926
|
setAuthError(null);
|
|
6808
6927
|
setAddress(null);
|
|
6809
6928
|
}, [apiBaseUrl]);
|
|
6810
|
-
// Agent wallet hook
|
|
6811
|
-
const { agentWallet, isReady: isAgentWalletReady, loading: agentWalletLoading, error: agentWalletError, refreshAgentWalletStatus, createAgentWallet, notifyAgentWalletApproved, } = useAgentWallet({ baseUrl: apiBaseUrl });
|
|
6812
6929
|
useAutoSyncFills({
|
|
6813
6930
|
baseUrl: apiBaseUrl,
|
|
6814
6931
|
accessToken: accessToken || '',
|
|
@@ -6842,23 +6959,13 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
6842
6959
|
loginWithPrivyToken,
|
|
6843
6960
|
refreshTokens,
|
|
6844
6961
|
logout: logout$1,
|
|
6845
|
-
// Agent wallet
|
|
6846
|
-
agentWallet,
|
|
6847
|
-
isAgentWalletReady,
|
|
6848
|
-
agentWalletError,
|
|
6849
|
-
agentWalletLoading,
|
|
6850
|
-
refreshAgentWalletStatus,
|
|
6851
|
-
createAgentWallet,
|
|
6852
|
-
notifyAgentWalletApproved,
|
|
6853
6962
|
}), [
|
|
6854
6963
|
apiBaseUrl, wsUrl,
|
|
6855
6964
|
address, setAddress,
|
|
6856
6965
|
isConnected, lastError,
|
|
6857
6966
|
nativeIsConnected, nativeLastError,
|
|
6858
6967
|
authStatus, isAuthenticated, user, authError,
|
|
6859
|
-
agentWallet, isAgentWalletReady, agentWalletError, agentWalletLoading,
|
|
6860
6968
|
getEip712, loginWithSignedMessage, refreshTokens, logout$1,
|
|
6861
|
-
refreshAgentWalletStatus, createAgentWallet, notifyAgentWalletApproved,
|
|
6862
6969
|
]);
|
|
6863
6970
|
return (jsx(PearHyperliquidContext.Provider, { value: contextValue, children: children }));
|
|
6864
6971
|
};
|
|
@@ -6890,21 +6997,6 @@ function usePearAuth() {
|
|
|
6890
6997
|
logout: ctx.logout,
|
|
6891
6998
|
};
|
|
6892
6999
|
}
|
|
6893
|
-
/**
|
|
6894
|
-
* Provider-aware Agent Wallet hook. Uses agent wallet state/actions provided by PearHyperliquidProvider.
|
|
6895
|
-
*/
|
|
6896
|
-
function usePearAgentWallet() {
|
|
6897
|
-
const ctx = usePearHyperliquid();
|
|
6898
|
-
return {
|
|
6899
|
-
agentWallet: ctx.agentWallet,
|
|
6900
|
-
isReady: ctx.isAgentWalletReady,
|
|
6901
|
-
loading: ctx.agentWalletLoading,
|
|
6902
|
-
error: ctx.agentWalletError,
|
|
6903
|
-
refreshAgentWalletStatus: ctx.refreshAgentWalletStatus,
|
|
6904
|
-
createAgentWallet: ctx.createAgentWallet,
|
|
6905
|
-
notifyAgentWalletApproved: ctx.notifyAgentWalletApproved,
|
|
6906
|
-
};
|
|
6907
|
-
}
|
|
6908
7000
|
|
|
6909
7001
|
/**
|
|
6910
7002
|
* Detects conflicts between selected tokens and existing positions
|
|
@@ -6993,4 +7085,4 @@ function mapCandleIntervalToTradingViewInterval(interval) {
|
|
|
6993
7085
|
}
|
|
6994
7086
|
}
|
|
6995
7087
|
|
|
6996
|
-
export { AccountSummaryCalculator, AuthStatus, ConflictDetector, MINIMUM_ASSET_USD_VALUE, MinimumPositionSizeError, PearHyperliquidProvider, TokenMetadataExtractor, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, getCompleteTimestamps, getPortfolio, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateRiskParameters, useAccountSummary, useActiveBaskets,
|
|
7088
|
+
export { AccountSummaryCalculator, AuthStatus, ConflictDetector, MINIMUM_ASSET_USD_VALUE, MinimumPositionSizeError, PearHyperliquidProvider, TokenMetadataExtractor, adjustOrder, adjustPosition, calculateMinimumPositionValue, calculateWeightedRatio, cancelOrder, cancelTwap, cancelTwapOrder, closeAllPositions, closePosition, computeBasketCandles, createCandleLookups, createPosition, getCompleteTimestamps, getPortfolio, mapCandleIntervalToTradingViewInterval, mapTradingViewIntervalToCandleInterval, markNotificationReadById, markNotificationsRead, toggleWatchlist, updateRiskParameters, useAccountSummary, useActiveBaskets, useAgentWallet, useAllBaskets, useAutoSyncFills, useBasketCandles, useFindBasket, useHighlightedBaskets, useHistoricalPriceData, useHistoricalPriceDataStore, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMarketData, useMarketDataAllPayload, useMarketDataPayload, useNotifications, useOpenOrders, useOrders, usePearAuth, usePearHyperliquid, usePerformanceOverlays, usePortfolio, usePosition, useTokenSelectionMetadata, useTopGainers, useTopLosers, useTradeHistories, useTwap, useUserSelection, useWatchlist, useWatchlistBaskets, useWebData, validateMinimumAssetSize, validatePositionSize };
|