@pear-protocol/hyperliquid-sdk 0.0.49-hip3-alpha → 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 +8 -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 +32 -64
- package/dist/index.js +267 -244
- package/dist/provider.d.ts +0 -20
- package/dist/types.d.ts +13 -4
- package/dist/utils/account-summary-calculator.d.ts +2 -6
- package/dist/utils/symbol-translator.d.ts +11 -0
- 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) {
|
|
@@ -232,6 +298,7 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
232
298
|
finalAtOICaps: null,
|
|
233
299
|
aggregatedClearingHouseState: null,
|
|
234
300
|
perpMetaAssets: null,
|
|
301
|
+
hip3DisplayToFull: new Map(),
|
|
235
302
|
setAllMids: (value) => set({ allMids: value }),
|
|
236
303
|
setActiveAssetData: (value) => set((state) => ({
|
|
237
304
|
activeAssetData: typeof value === 'function' ? value(state.activeAssetData) : value
|
|
@@ -274,7 +341,8 @@ const useHyperliquidData = create((set, get) => ({
|
|
|
274
341
|
setFinalAssetContexts: (value) => set({ finalAssetContexts: value }),
|
|
275
342
|
setFinalAtOICaps: (value) => set({ finalAtOICaps: value }),
|
|
276
343
|
setAggregatedClearingHouseState: (value) => set({ aggregatedClearingHouseState: value }),
|
|
277
|
-
setPerpMetaAssets: (value) => set({ perpMetaAssets: value })
|
|
344
|
+
setPerpMetaAssets: (value) => set({ perpMetaAssets: value }),
|
|
345
|
+
setHip3DisplayToFull: (value) => set({ hip3DisplayToFull: value })
|
|
278
346
|
}));
|
|
279
347
|
|
|
280
348
|
const DEFAULT_STATE = {
|
|
@@ -414,7 +482,7 @@ const useUserSelection$1 = create((set, get) => ({
|
|
|
414
482
|
resetToDefaults: () => set((prev) => ({ ...prev, ...DEFAULT_STATE })),
|
|
415
483
|
}));
|
|
416
484
|
|
|
417
|
-
const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
485
|
+
const useHyperliquidNativeWebSocket = ({ address, enabled = true, }) => {
|
|
418
486
|
const { setAllMids, setActiveAssetData, upsertActiveAssetData, setCandleData, deleteCandleSymbol, deleteActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState } = useHyperliquidData();
|
|
419
487
|
const { candleInterval } = useUserSelection$1();
|
|
420
488
|
const longTokens = useUserSelection$1((s) => s.longTokens);
|
|
@@ -488,15 +556,29 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
488
556
|
setAggregatedClearingHouseState(aggregatedClearingHouseState);
|
|
489
557
|
break;
|
|
490
558
|
case 'allMids':
|
|
491
|
-
|
|
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
|
+
}
|
|
492
566
|
break;
|
|
493
567
|
case 'activeAssetData':
|
|
494
|
-
|
|
495
|
-
|
|
568
|
+
{
|
|
569
|
+
const assetData = response.data;
|
|
570
|
+
const symbol = toDisplaySymbol(assetData.coin);
|
|
571
|
+
const normalized = { ...assetData, coin: symbol };
|
|
572
|
+
upsertActiveAssetData(symbol, normalized);
|
|
573
|
+
}
|
|
496
574
|
break;
|
|
497
575
|
case 'candle':
|
|
498
|
-
|
|
499
|
-
|
|
576
|
+
{
|
|
577
|
+
const candleDataItem = response.data;
|
|
578
|
+
const symbol = toDisplaySymbol(candleDataItem.s || '');
|
|
579
|
+
const normalized = { ...candleDataItem, s: symbol };
|
|
580
|
+
addCandleData(symbol, normalized);
|
|
581
|
+
}
|
|
500
582
|
break;
|
|
501
583
|
default:
|
|
502
584
|
console.warn(`[HyperLiquid WS] Unknown channel: ${response.channel}`);
|
|
@@ -510,7 +592,15 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
510
592
|
}
|
|
511
593
|
}, [setAllMids, upsertActiveAssetData, addCandleData, setFinalAssetContexts, setFinalAtOICaps, setAggregatedClearingHouseState]);
|
|
512
594
|
const connect = useCallback(() => {
|
|
595
|
+
if (!enabled)
|
|
596
|
+
return;
|
|
513
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
|
+
}
|
|
514
604
|
manualCloseRef.current = false;
|
|
515
605
|
setReadyState(ReadyState.CONNECTING);
|
|
516
606
|
const ws = new WebSocket('wss://api.hyperliquid.xyz/ws');
|
|
@@ -539,7 +629,7 @@ const useHyperliquidNativeWebSocket = ({ address, }) => {
|
|
|
539
629
|
catch (e) {
|
|
540
630
|
setLastError(`WebSocket connection failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
541
631
|
}
|
|
542
|
-
}, [handleMessage]);
|
|
632
|
+
}, [handleMessage, enabled]);
|
|
543
633
|
useEffect(() => {
|
|
544
634
|
connect();
|
|
545
635
|
return () => {
|
|
@@ -4634,121 +4724,6 @@ async function logout(baseUrl, refreshTokenVal) {
|
|
|
4634
4724
|
}
|
|
4635
4725
|
}
|
|
4636
4726
|
|
|
4637
|
-
async function getAgentWallet(baseUrl, accessToken) {
|
|
4638
|
-
const url = joinUrl(baseUrl, '/agentWallet');
|
|
4639
|
-
try {
|
|
4640
|
-
const resp = await axios$1.get(url, { headers: { Authorization: `Bearer ${accessToken}` }, timeout: 30000 });
|
|
4641
|
-
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
4642
|
-
}
|
|
4643
|
-
catch (error) {
|
|
4644
|
-
throw toApiError(error);
|
|
4645
|
-
}
|
|
4646
|
-
}
|
|
4647
|
-
async function createAgentWallet(baseUrl, accessToken) {
|
|
4648
|
-
const url = joinUrl(baseUrl, '/agentWallet');
|
|
4649
|
-
try {
|
|
4650
|
-
const resp = await axios$1.post(url, undefined, { headers: { Authorization: `Bearer ${accessToken}` }, timeout: 30000 });
|
|
4651
|
-
return { data: resp.data, status: resp.status, headers: resp.headers };
|
|
4652
|
-
}
|
|
4653
|
-
catch (error) {
|
|
4654
|
-
throw toApiError(error);
|
|
4655
|
-
}
|
|
4656
|
-
}
|
|
4657
|
-
|
|
4658
|
-
function useAgentWallet({ baseUrl }) {
|
|
4659
|
-
var _a, _b, _c;
|
|
4660
|
-
const accountSummary = useUserData((state) => state.accountSummary);
|
|
4661
|
-
const setAccountSummary = useUserData((state) => state.setAccountSummary);
|
|
4662
|
-
const agentWallet = {
|
|
4663
|
-
address: ((_a = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _a === void 0 ? void 0 : _a.address) || null,
|
|
4664
|
-
name: 'Pear Protocol',
|
|
4665
|
-
status: ((_b = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _b === void 0 ? void 0 : _b.status) || null,
|
|
4666
|
-
isActive: ((_c = accountSummary === null || accountSummary === void 0 ? void 0 : accountSummary.agentWallet) === null || _c === void 0 ? void 0 : _c.status) === 'ACTIVE',
|
|
4667
|
-
};
|
|
4668
|
-
// Derive loading/error locally for now
|
|
4669
|
-
let error = null;
|
|
4670
|
-
let loading = false;
|
|
4671
|
-
const getAuthHeader = () => {
|
|
4672
|
-
const token = localStorage.getItem('accessToken');
|
|
4673
|
-
if (!token)
|
|
4674
|
-
throw new Error('Not authenticated');
|
|
4675
|
-
return token;
|
|
4676
|
-
};
|
|
4677
|
-
const refreshAgentWalletStatus = useCallback(async () => {
|
|
4678
|
-
loading = true;
|
|
4679
|
-
error = null;
|
|
4680
|
-
try {
|
|
4681
|
-
const token = getAuthHeader();
|
|
4682
|
-
const { data } = await getAgentWallet(baseUrl, token);
|
|
4683
|
-
// Update store account summary's agentWallet
|
|
4684
|
-
const current = useUserData.getState().accountSummary;
|
|
4685
|
-
const updated = current
|
|
4686
|
-
? { ...current, agentWallet: { address: data.agentWalletAddress || '', status: data.status } }
|
|
4687
|
-
: { 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 } };
|
|
4688
|
-
setAccountSummary(updated);
|
|
4689
|
-
return data;
|
|
4690
|
-
}
|
|
4691
|
-
catch (e) {
|
|
4692
|
-
error = (e === null || e === void 0 ? void 0 : e.message) || 'Failed to fetch agent wallet';
|
|
4693
|
-
throw e;
|
|
4694
|
-
}
|
|
4695
|
-
finally {
|
|
4696
|
-
loading = false;
|
|
4697
|
-
}
|
|
4698
|
-
}, [baseUrl]);
|
|
4699
|
-
const createAgentWallet$1 = useCallback(async () => {
|
|
4700
|
-
loading = true;
|
|
4701
|
-
error = null;
|
|
4702
|
-
try {
|
|
4703
|
-
const token = getAuthHeader();
|
|
4704
|
-
const { data } = await createAgentWallet(baseUrl, token);
|
|
4705
|
-
// Update store account summary's agentWallet to reflect newly created address
|
|
4706
|
-
const current = useUserData.getState().accountSummary;
|
|
4707
|
-
const updated = current
|
|
4708
|
-
? { ...current, agentWallet: { address: data.agentWalletAddress, status: 'ACTIVE' } }
|
|
4709
|
-
: { 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' } };
|
|
4710
|
-
setAccountSummary(updated);
|
|
4711
|
-
return data;
|
|
4712
|
-
}
|
|
4713
|
-
catch (e) {
|
|
4714
|
-
error = (e === null || e === void 0 ? void 0 : e.message) || 'Failed to create agent wallet';
|
|
4715
|
-
throw e;
|
|
4716
|
-
}
|
|
4717
|
-
finally {
|
|
4718
|
-
loading = false;
|
|
4719
|
-
}
|
|
4720
|
-
}, [baseUrl]);
|
|
4721
|
-
// For user to notify that approvals are done; we re-check status
|
|
4722
|
-
const notifyAgentWalletApproved = useCallback(async () => {
|
|
4723
|
-
return refreshAgentWalletStatus();
|
|
4724
|
-
}, [refreshAgentWalletStatus]);
|
|
4725
|
-
return {
|
|
4726
|
-
agentWallet,
|
|
4727
|
-
isReady: agentWallet.isActive,
|
|
4728
|
-
loading,
|
|
4729
|
-
error,
|
|
4730
|
-
refreshAgentWalletStatus,
|
|
4731
|
-
createAgentWallet: createAgentWallet$1,
|
|
4732
|
-
notifyAgentWalletApproved,
|
|
4733
|
-
};
|
|
4734
|
-
}
|
|
4735
|
-
|
|
4736
|
-
/**
|
|
4737
|
-
* Hook to manage address (login/logout functionality)
|
|
4738
|
-
*/
|
|
4739
|
-
const useAddress = () => {
|
|
4740
|
-
const context = useContext(PearHyperliquidContext);
|
|
4741
|
-
if (!context) {
|
|
4742
|
-
throw new Error('useAddress must be used within a PearHyperliquidProvider');
|
|
4743
|
-
}
|
|
4744
|
-
return {
|
|
4745
|
-
address: context.address,
|
|
4746
|
-
setAddress: context.setAddress,
|
|
4747
|
-
clearAddress: () => context.setAddress(null),
|
|
4748
|
-
isLoggedIn: !!context.address,
|
|
4749
|
-
};
|
|
4750
|
-
};
|
|
4751
|
-
|
|
4752
4727
|
/**
|
|
4753
4728
|
* Account summary calculation utility class
|
|
4754
4729
|
*/
|
|
@@ -4759,54 +4734,40 @@ class AccountSummaryCalculator {
|
|
|
4759
4734
|
/**
|
|
4760
4735
|
* Calculate account summary from real-time clearinghouse state and platform orders
|
|
4761
4736
|
*/
|
|
4762
|
-
calculateAccountSummary(platformAccountSummary,
|
|
4737
|
+
calculateAccountSummary(platformAccountSummary, registeredAgentWallets) {
|
|
4763
4738
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
4764
|
-
// If we don't have real-time state, return platform data as-is
|
|
4765
4739
|
if (!this.clearinghouseState) {
|
|
4766
|
-
return
|
|
4740
|
+
return null;
|
|
4767
4741
|
}
|
|
4768
4742
|
const clearinghouseState = this.clearinghouseState;
|
|
4769
|
-
// Calculate total limit order value from platform orders
|
|
4770
|
-
const totalLimitOrderValue = this.calculateTotalLimitOrderValue(platformOpenOrders || []);
|
|
4771
|
-
// Use real-time data from clearinghouseState
|
|
4772
4743
|
const withdrawableAmount = parseFloat(clearinghouseState.withdrawable || '0');
|
|
4773
|
-
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));
|
|
4774
4745
|
const accountSummary = {
|
|
4775
4746
|
balanceSummary: {
|
|
4776
4747
|
crossMaintenanceMarginUsed: clearinghouseState.crossMaintenanceMarginUsed || '0',
|
|
4777
4748
|
crossMarginSummary: {
|
|
4778
|
-
accountValue: ((
|
|
4779
|
-
totalMarginUsed: ((
|
|
4780
|
-
totalNtlPos: ((
|
|
4781
|
-
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'
|
|
4782
4753
|
},
|
|
4783
4754
|
marginSummary: {
|
|
4784
|
-
accountValue: ((
|
|
4785
|
-
totalMarginUsed: ((
|
|
4786
|
-
totalNtlPos: ((
|
|
4787
|
-
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'
|
|
4788
4759
|
},
|
|
4789
4760
|
time: clearinghouseState.time || Date.now(),
|
|
4790
4761
|
withdrawable: adjustedWithdrawable.toString()
|
|
4791
|
-
},
|
|
4792
|
-
agentWallet: {
|
|
4793
|
-
address: agentWalletAddress || ((_j = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWallet) === null || _j === void 0 ? void 0 : _j.address) || '',
|
|
4794
|
-
status: agentWalletStatus || ((_k = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWallet) === null || _k === void 0 ? void 0 : _k.status) || 'UNKNOWN'
|
|
4795
4762
|
}
|
|
4796
4763
|
};
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
calculateTotalLimitOrderValue(openOrders) {
|
|
4803
|
-
if (!(openOrders === null || openOrders === void 0 ? void 0 : openOrders.length)) {
|
|
4804
|
-
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
|
+
};
|
|
4805
4769
|
}
|
|
4806
|
-
|
|
4807
|
-
.filter(order => order.status === 'OPEN' || order.status === 'PROCESSING')
|
|
4808
|
-
.reduce((sum, order) => sum + order.usdValue / order.leverage, 0);
|
|
4809
|
-
return totalValue;
|
|
4770
|
+
return accountSummary;
|
|
4810
4771
|
}
|
|
4811
4772
|
getClearinghouseState() {
|
|
4812
4773
|
return this.clearinghouseState || null;
|
|
@@ -4819,6 +4780,23 @@ class AccountSummaryCalculator {
|
|
|
4819
4780
|
}
|
|
4820
4781
|
}
|
|
4821
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
|
+
|
|
4822
4800
|
const useTradeHistories = () => {
|
|
4823
4801
|
const context = useContext(PearHyperliquidContext);
|
|
4824
4802
|
if (!context) {
|
|
@@ -4844,29 +4822,7 @@ const useOpenOrders = () => {
|
|
|
4844
4822
|
}, [openOrders, context.isConnected]);
|
|
4845
4823
|
return { data: openOrders, isLoading };
|
|
4846
4824
|
};
|
|
4847
|
-
/**
|
|
4848
|
-
* Hook to access account summary with real-time calculations and loading state
|
|
4849
|
-
*/
|
|
4850
|
-
const useAccountSummary = () => {
|
|
4851
|
-
var _a, _b;
|
|
4852
|
-
const context = useContext(PearHyperliquidContext);
|
|
4853
|
-
if (!context) {
|
|
4854
|
-
throw new Error('useAccountSummary must be used within a PearHyperliquidProvider');
|
|
4855
|
-
}
|
|
4856
|
-
const openOrders = useUserData((state) => state.openOrders);
|
|
4857
|
-
const accountSummary = useUserData((state) => state.accountSummary);
|
|
4858
|
-
const aggregatedClearingHouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
4859
|
-
const isLoading = useMemo(() => {
|
|
4860
|
-
// Loading is true initially and becomes false once we get the first data
|
|
4861
|
-
return accountSummary === null && context.isConnected;
|
|
4862
|
-
}, [accountSummary, context.isConnected]);
|
|
4863
|
-
// Create calculator and compute account summary
|
|
4864
|
-
const calculator = new AccountSummaryCalculator(aggregatedClearingHouseState);
|
|
4865
|
-
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);
|
|
4866
|
-
return { data: calculated, isLoading };
|
|
4867
|
-
};
|
|
4868
4825
|
|
|
4869
|
-
// Re-expose as a React hook without Zustand's selector signature
|
|
4870
4826
|
const useUserSelection = () => {
|
|
4871
4827
|
return useUserSelection$1();
|
|
4872
4828
|
};
|
|
@@ -4883,6 +4839,7 @@ const useWebData = () => {
|
|
|
4883
4839
|
const perpMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
4884
4840
|
const aggregatedClearinghouseState = useHyperliquidData((state) => state.aggregatedClearingHouseState);
|
|
4885
4841
|
const finalAtOICaps = useHyperliquidData((state) => state.finalAtOICaps);
|
|
4842
|
+
const hip3Assets = useHyperliquidData((state) => state.hip3DisplayToFull);
|
|
4886
4843
|
let marketDataBySymbol = {};
|
|
4887
4844
|
if (finalAssetContexts && perpMetaAssets && finalAssetContexts.length === perpMetaAssets.length) {
|
|
4888
4845
|
const result = {};
|
|
@@ -4896,6 +4853,7 @@ const useWebData = () => {
|
|
|
4896
4853
|
marketDataBySymbol = result;
|
|
4897
4854
|
}
|
|
4898
4855
|
return {
|
|
4856
|
+
hip3Assets,
|
|
4899
4857
|
clearinghouseState: aggregatedClearinghouseState,
|
|
4900
4858
|
perpsAtOpenInterestCap: finalAtOICaps,
|
|
4901
4859
|
marketDataBySymbol,
|
|
@@ -5350,9 +5308,10 @@ const useHistoricalPriceDataStore = create((set, get) => ({
|
|
|
5350
5308
|
/**
|
|
5351
5309
|
* Fetch historical candle data from HyperLiquid API
|
|
5352
5310
|
*/
|
|
5353
|
-
const fetchHistoricalCandles = async (coin, startTime, endTime, interval) => {
|
|
5311
|
+
const fetchHistoricalCandles = async (coin, startTime, endTime, interval, displayToFull) => {
|
|
5312
|
+
const backendCoin = toBackendSymbol(coin, displayToFull);
|
|
5354
5313
|
const request = {
|
|
5355
|
-
req: { coin, startTime, endTime, interval },
|
|
5314
|
+
req: { coin: backendCoin, startTime, endTime, interval },
|
|
5356
5315
|
type: 'candleSnapshot',
|
|
5357
5316
|
};
|
|
5358
5317
|
try {
|
|
@@ -5397,6 +5356,23 @@ const fetchAllPerpMetas = async () => {
|
|
|
5397
5356
|
throw toApiError(error);
|
|
5398
5357
|
}
|
|
5399
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
|
+
};
|
|
5400
5376
|
|
|
5401
5377
|
const useHistoricalPriceData = () => {
|
|
5402
5378
|
const context = useContext(PearHyperliquidContext);
|
|
@@ -5477,9 +5453,10 @@ const useHistoricalPriceData = () => {
|
|
|
5477
5453
|
setTokenLoading(token.symbol, true);
|
|
5478
5454
|
});
|
|
5479
5455
|
try {
|
|
5456
|
+
const displayToFull = useHyperliquidData.getState().hip3DisplayToFull;
|
|
5480
5457
|
const fetchPromises = tokensToFetch.map(async (token) => {
|
|
5481
5458
|
try {
|
|
5482
|
-
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval);
|
|
5459
|
+
const response = await fetchHistoricalCandles(token.symbol, startTime, endTime, interval, displayToFull);
|
|
5483
5460
|
addHistoricalPriceData(token.symbol, interval, response.data, { start: startTime, end: endTime });
|
|
5484
5461
|
return { symbol: token.symbol, candles: response.data, success: true };
|
|
5485
5462
|
}
|
|
@@ -5967,6 +5944,50 @@ const usePerformanceOverlays = () => {
|
|
|
5967
5944
|
};
|
|
5968
5945
|
};
|
|
5969
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
|
+
|
|
5970
5991
|
/**
|
|
5971
5992
|
* Sync external fills into Pear Hyperliquid service (POST /sync/fills)
|
|
5972
5993
|
*/
|
|
@@ -5986,8 +6007,8 @@ const syncFills = async (baseUrl, accessToken, payload) => {
|
|
|
5986
6007
|
/**
|
|
5987
6008
|
* Convenience: fetch user fills from HyperLiquid, then sync them to Pear backend
|
|
5988
6009
|
*/
|
|
5989
|
-
const syncUserFillsFromHyperliquid = async (baseUrl, accessToken, user, aggregateByTime = true) => {
|
|
5990
|
-
const firstStartTime =
|
|
6010
|
+
const syncUserFillsFromHyperliquid = async (baseUrl, accessToken, user, aggregateByTime = true, lastSyncAt = null) => {
|
|
6011
|
+
const firstStartTime = lastSyncAt ? Number(lastSyncAt) : 1735660800000;
|
|
5991
6012
|
const allFills = [];
|
|
5992
6013
|
const seenTids = new Set();
|
|
5993
6014
|
let startTime = firstStartTime;
|
|
@@ -6024,6 +6045,7 @@ function useAutoSyncFills(options) {
|
|
|
6024
6045
|
const [isSyncing, setIsSyncing] = useState(false);
|
|
6025
6046
|
const mountedRef = useRef(true);
|
|
6026
6047
|
const runningRef = useRef(null);
|
|
6048
|
+
const lastSyncedAt = useUserData((state) => { var _a; return (_a = state.accountSummary) === null || _a === void 0 ? void 0 : _a.lastSyncedAt; });
|
|
6027
6049
|
useEffect(() => {
|
|
6028
6050
|
mountedRef.current = true;
|
|
6029
6051
|
return () => { mountedRef.current = false; };
|
|
@@ -6035,13 +6057,15 @@ function useAutoSyncFills(options) {
|
|
|
6035
6057
|
if (!canRun)
|
|
6036
6058
|
return;
|
|
6037
6059
|
if (runningRef.current)
|
|
6038
|
-
return;
|
|
6060
|
+
return;
|
|
6061
|
+
if (!useUserData.getState().accountSummary)
|
|
6062
|
+
return;
|
|
6039
6063
|
setIsSyncing(true);
|
|
6040
6064
|
setError(null);
|
|
6041
6065
|
const promise = (async () => {
|
|
6042
6066
|
var _a;
|
|
6043
6067
|
try {
|
|
6044
|
-
const { data } = await syncUserFillsFromHyperliquid(baseUrl, accessToken, address, aggregateByTime);
|
|
6068
|
+
const { data } = await syncUserFillsFromHyperliquid(baseUrl, accessToken, address, aggregateByTime, lastSyncedAt);
|
|
6045
6069
|
if (!mountedRef.current)
|
|
6046
6070
|
return;
|
|
6047
6071
|
setLastResult(data);
|
|
@@ -6060,7 +6084,7 @@ function useAutoSyncFills(options) {
|
|
|
6060
6084
|
})();
|
|
6061
6085
|
runningRef.current = promise;
|
|
6062
6086
|
await promise;
|
|
6063
|
-
}, [canRun, baseUrl, accessToken, address, aggregateByTime]);
|
|
6087
|
+
}, [canRun, baseUrl, accessToken, address, aggregateByTime, lastSyncedAt]);
|
|
6064
6088
|
useEffect(() => {
|
|
6065
6089
|
if (!canRun)
|
|
6066
6090
|
return;
|
|
@@ -6166,12 +6190,19 @@ function validatePositionSize(usdValue, longAssets, shortAssets) {
|
|
|
6166
6190
|
* Caller should supply an accessToken from localStorage.getItem('accessToken')
|
|
6167
6191
|
* @throws MinimumPositionSizeError if any asset has less than $11 USD value
|
|
6168
6192
|
*/
|
|
6169
|
-
async function createPosition(baseUrl, accessToken, payload) {
|
|
6193
|
+
async function createPosition(baseUrl, accessToken, payload, displayToFull) {
|
|
6170
6194
|
// Validate minimum asset size before creating position
|
|
6171
6195
|
validateMinimumAssetSize(payload.usdValue, payload.longAssets, payload.shortAssets);
|
|
6172
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
|
+
};
|
|
6173
6204
|
try {
|
|
6174
|
-
const resp = await axios$1.post(url,
|
|
6205
|
+
const resp = await axios$1.post(url, translatedPayload, {
|
|
6175
6206
|
headers: {
|
|
6176
6207
|
"Content-Type": "application/json",
|
|
6177
6208
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -6329,7 +6360,7 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
6329
6360
|
mappedPosition.longAssets = position.longAssets.map(longAsset => {
|
|
6330
6361
|
var _a, _b, _c;
|
|
6331
6362
|
const currentPrice = parseFloat(allMids.mids[longAsset.coin]);
|
|
6332
|
-
const assetState = (_a = clearinghouseState.assetPositions.find(ap => ap.position.coin === longAsset.coin)) === null || _a === void 0 ? void 0 : _a.position;
|
|
6363
|
+
const assetState = (_a = clearinghouseState.assetPositions.find(ap => toDisplaySymbol(ap.position.coin) === longAsset.coin)) === null || _a === void 0 ? void 0 : _a.position;
|
|
6333
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;
|
|
6334
6365
|
const mappedPositionAssets = calculatePositionAsset(longAsset, currentPrice, totalInitialPositionSize, leverage, true);
|
|
6335
6366
|
mappedPosition.entryPositionValue += mappedPositionAssets.entryPositionValue;
|
|
@@ -6343,7 +6374,7 @@ const buildPositionValue = (rawPositions, clearinghouseState, allMids) => {
|
|
|
6343
6374
|
mappedPosition.shortAssets = position.shortAssets.map(shortAsset => {
|
|
6344
6375
|
var _a, _b, _c;
|
|
6345
6376
|
const currentPrice = parseFloat(allMids.mids[shortAsset.coin]);
|
|
6346
|
-
const assetState = (_a = clearinghouseState.assetPositions.find(ap => ap.position.coin === shortAsset.coin)) === null || _a === void 0 ? void 0 : _a.position;
|
|
6377
|
+
const assetState = (_a = clearinghouseState.assetPositions.find(ap => toDisplaySymbol(ap.position.coin) === shortAsset.coin)) === null || _a === void 0 ? void 0 : _a.position;
|
|
6347
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;
|
|
6348
6379
|
const mappedPositionAssets = calculatePositionAsset(shortAsset, currentPrice, totalInitialPositionSize, leverage, false);
|
|
6349
6380
|
mappedPosition.entryPositionValue += mappedPositionAssets.entryPositionValue;
|
|
@@ -6376,11 +6407,12 @@ function usePosition() {
|
|
|
6376
6407
|
throw new Error('usePosition must be used within a PearHyperliquidProvider');
|
|
6377
6408
|
}
|
|
6378
6409
|
const { apiBaseUrl, accessToken, isConnected } = context;
|
|
6410
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
6379
6411
|
// Create position API action
|
|
6380
6412
|
const createPosition$1 = async (payload) => {
|
|
6381
6413
|
if (!accessToken)
|
|
6382
6414
|
throw new Error('Not authenticated');
|
|
6383
|
-
return createPosition(apiBaseUrl, accessToken, payload);
|
|
6415
|
+
return createPosition(apiBaseUrl, accessToken, payload, displayToFull);
|
|
6384
6416
|
};
|
|
6385
6417
|
// Update TP/SL risk parameters for a position
|
|
6386
6418
|
const updateRiskParameters$1 = async (positionId, payload) => {
|
|
@@ -6478,7 +6510,6 @@ function useOrders() {
|
|
|
6478
6510
|
const pos = positionsById.get((_e = ord.positionId) !== null && _e !== void 0 ? _e : '');
|
|
6479
6511
|
if (!isTpSl || !pos)
|
|
6480
6512
|
return ord;
|
|
6481
|
-
// Build order assets from position weights when TP/SL has no assets
|
|
6482
6513
|
const mapAssets = (arr) => arr.map((a) => ({ asset: a.coin, weight: a.initialWeight }));
|
|
6483
6514
|
if (!hasAssets) {
|
|
6484
6515
|
return {
|
|
@@ -6487,7 +6518,6 @@ function useOrders() {
|
|
|
6487
6518
|
shortAssets: mapAssets(pos.shortAssets),
|
|
6488
6519
|
};
|
|
6489
6520
|
}
|
|
6490
|
-
// Leverage is now tracked per-asset in positions; keep order leverage as-is
|
|
6491
6521
|
return ord;
|
|
6492
6522
|
});
|
|
6493
6523
|
}, [openOrders, positionsById]);
|
|
@@ -6571,7 +6601,6 @@ function useNotifications() {
|
|
|
6571
6601
|
if (!isAuthenticated || !accessToken)
|
|
6572
6602
|
throw new Error('Not authenticated');
|
|
6573
6603
|
const { data } = await markNotificationsRead(apiBaseUrl, accessToken, timestampMs);
|
|
6574
|
-
// Optimistic local update for immediate UI feedback
|
|
6575
6604
|
if (notifications) {
|
|
6576
6605
|
const updated = notifications.map((n) => {
|
|
6577
6606
|
const created = Date.parse(n.created_at);
|
|
@@ -6668,10 +6697,11 @@ const useFindBasket = (longs, shorts) => {
|
|
|
6668
6697
|
}, [data, longs, shorts]);
|
|
6669
6698
|
};
|
|
6670
6699
|
|
|
6671
|
-
async function toggleWatchlist(baseUrl, accessToken, longAssets, shortAssets) {
|
|
6700
|
+
async function toggleWatchlist(baseUrl, accessToken, longAssets, shortAssets, displayToFull) {
|
|
6672
6701
|
const url = joinUrl(baseUrl, '/watchlist');
|
|
6702
|
+
const mapAssets = (arr) => arr.map(a => ({ ...a, asset: toBackendSymbol(a.asset, displayToFull) }));
|
|
6673
6703
|
try {
|
|
6674
|
-
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}` } });
|
|
6675
6705
|
return { data: response.data, status: response.status, headers: response.headers };
|
|
6676
6706
|
}
|
|
6677
6707
|
catch (error) {
|
|
@@ -6684,12 +6714,13 @@ function useWatchlist() {
|
|
|
6684
6714
|
if (!context)
|
|
6685
6715
|
throw new Error('useWatchlist must be used within a PearHyperliquidProvider');
|
|
6686
6716
|
const { apiBaseUrl, accessToken, isConnected } = context;
|
|
6717
|
+
const displayToFull = useHyperliquidData((s) => s.hip3DisplayToFull);
|
|
6687
6718
|
const marketData = useMarketDataPayload();
|
|
6688
6719
|
const isLoading = useMemo(() => !marketData && isConnected, [marketData, isConnected]);
|
|
6689
6720
|
const toggle = async (longAssets, shortAssets) => {
|
|
6690
6721
|
if (!accessToken)
|
|
6691
6722
|
throw new Error('Not authenticated');
|
|
6692
|
-
const resp = await toggleWatchlist(apiBaseUrl, accessToken, longAssets, shortAssets);
|
|
6723
|
+
const resp = await toggleWatchlist(apiBaseUrl, accessToken, longAssets, shortAssets, displayToFull);
|
|
6693
6724
|
// Server will push updated market-data over WS; nothing to set here
|
|
6694
6725
|
return resp;
|
|
6695
6726
|
};
|
|
@@ -6716,7 +6747,7 @@ async function getPortfolio(baseUrl, accessToken) {
|
|
|
6716
6747
|
/**
|
|
6717
6748
|
* Hook to fetch and manage portfolio data
|
|
6718
6749
|
* Returns bucketed volume, open interest snapshot, win/loss trade counts,
|
|
6719
|
-
* and overall metrics
|
|
6750
|
+
* and overall metrics
|
|
6720
6751
|
*/
|
|
6721
6752
|
function usePortfolio() {
|
|
6722
6753
|
const context = useContext(PearHyperliquidContext);
|
|
@@ -6760,17 +6791,21 @@ const PearHyperliquidContext = createContext(undefined);
|
|
|
6760
6791
|
*/
|
|
6761
6792
|
const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearprotocol.io', clientId = 'PEARPROTOCOLUI', wsUrl = 'wss://hl-v2.pearprotocol.io/ws', }) => {
|
|
6762
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]);
|
|
6763
6798
|
// WebSocket connection and data (Pear API)
|
|
6764
6799
|
const { isConnected, lastError } = useHyperliquidWebSocket({
|
|
6765
6800
|
wsUrl,
|
|
6766
6801
|
address,
|
|
6802
|
+
enabled: websocketsEnabled,
|
|
6767
6803
|
});
|
|
6768
6804
|
// HyperLiquid native WebSocket connection
|
|
6769
6805
|
const { isConnected: nativeIsConnected, lastError: nativeLastError } = useHyperliquidNativeWebSocket({
|
|
6770
6806
|
address,
|
|
6807
|
+
enabled: websocketsEnabled,
|
|
6771
6808
|
});
|
|
6772
|
-
const perpsMetaAssets = useHyperliquidData((state) => state.perpMetaAssets);
|
|
6773
|
-
const setPerpMetaAssets = useHyperliquidData((state) => state.setPerpMetaAssets);
|
|
6774
6809
|
// Auth hook
|
|
6775
6810
|
const [authStatus, setAuthStatus] = useState(AuthStatus.Idle);
|
|
6776
6811
|
const [user, setUser] = useState(null);
|
|
@@ -6781,11 +6816,26 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
6781
6816
|
if (perpsMetaAssets === null) {
|
|
6782
6817
|
fetchAllPerpMetas().then(res => {
|
|
6783
6818
|
const aggregatedPerpMetas = res.data.flatMap(item => item.universe);
|
|
6784
|
-
|
|
6785
|
-
|
|
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(() => { });
|
|
6786
6837
|
}
|
|
6787
|
-
}, [perpsMetaAssets]);
|
|
6788
|
-
// Hydrate from existing token
|
|
6838
|
+
}, [perpsMetaAssets, setPerpMetaAssets, setHip3DisplayToFull]);
|
|
6789
6839
|
useEffect(() => {
|
|
6790
6840
|
const access = localStorage.getItem('accessToken');
|
|
6791
6841
|
if (access) {
|
|
@@ -6876,8 +6926,6 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
6876
6926
|
setAuthError(null);
|
|
6877
6927
|
setAddress(null);
|
|
6878
6928
|
}, [apiBaseUrl]);
|
|
6879
|
-
// Agent wallet hook
|
|
6880
|
-
const { agentWallet, isReady: isAgentWalletReady, loading: agentWalletLoading, error: agentWalletError, refreshAgentWalletStatus, createAgentWallet, notifyAgentWalletApproved, } = useAgentWallet({ baseUrl: apiBaseUrl });
|
|
6881
6929
|
useAutoSyncFills({
|
|
6882
6930
|
baseUrl: apiBaseUrl,
|
|
6883
6931
|
accessToken: accessToken || '',
|
|
@@ -6911,23 +6959,13 @@ const PearHyperliquidProvider = ({ children, apiBaseUrl = 'https://hl-v2.pearpro
|
|
|
6911
6959
|
loginWithPrivyToken,
|
|
6912
6960
|
refreshTokens,
|
|
6913
6961
|
logout: logout$1,
|
|
6914
|
-
// Agent wallet
|
|
6915
|
-
agentWallet,
|
|
6916
|
-
isAgentWalletReady,
|
|
6917
|
-
agentWalletError,
|
|
6918
|
-
agentWalletLoading,
|
|
6919
|
-
refreshAgentWalletStatus,
|
|
6920
|
-
createAgentWallet,
|
|
6921
|
-
notifyAgentWalletApproved,
|
|
6922
6962
|
}), [
|
|
6923
6963
|
apiBaseUrl, wsUrl,
|
|
6924
6964
|
address, setAddress,
|
|
6925
6965
|
isConnected, lastError,
|
|
6926
6966
|
nativeIsConnected, nativeLastError,
|
|
6927
6967
|
authStatus, isAuthenticated, user, authError,
|
|
6928
|
-
agentWallet, isAgentWalletReady, agentWalletError, agentWalletLoading,
|
|
6929
6968
|
getEip712, loginWithSignedMessage, refreshTokens, logout$1,
|
|
6930
|
-
refreshAgentWalletStatus, createAgentWallet, notifyAgentWalletApproved,
|
|
6931
6969
|
]);
|
|
6932
6970
|
return (jsx(PearHyperliquidContext.Provider, { value: contextValue, children: children }));
|
|
6933
6971
|
};
|
|
@@ -6959,21 +6997,6 @@ function usePearAuth() {
|
|
|
6959
6997
|
logout: ctx.logout,
|
|
6960
6998
|
};
|
|
6961
6999
|
}
|
|
6962
|
-
/**
|
|
6963
|
-
* Provider-aware Agent Wallet hook. Uses agent wallet state/actions provided by PearHyperliquidProvider.
|
|
6964
|
-
*/
|
|
6965
|
-
function usePearAgentWallet() {
|
|
6966
|
-
const ctx = usePearHyperliquid();
|
|
6967
|
-
return {
|
|
6968
|
-
agentWallet: ctx.agentWallet,
|
|
6969
|
-
isReady: ctx.isAgentWalletReady,
|
|
6970
|
-
loading: ctx.agentWalletLoading,
|
|
6971
|
-
error: ctx.agentWalletError,
|
|
6972
|
-
refreshAgentWalletStatus: ctx.refreshAgentWalletStatus,
|
|
6973
|
-
createAgentWallet: ctx.createAgentWallet,
|
|
6974
|
-
notifyAgentWalletApproved: ctx.notifyAgentWalletApproved,
|
|
6975
|
-
};
|
|
6976
|
-
}
|
|
6977
7000
|
|
|
6978
7001
|
/**
|
|
6979
7002
|
* Detects conflicts between selected tokens and existing positions
|
|
@@ -7062,4 +7085,4 @@ function mapCandleIntervalToTradingViewInterval(interval) {
|
|
|
7062
7085
|
}
|
|
7063
7086
|
}
|
|
7064
7087
|
|
|
7065
|
-
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 };
|