@pear-protocol/hyperliquid-sdk 0.0.4 → 0.0.7

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/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import axios from 'axios';
2
- import require$$0, { createContext, useMemo, useState, useEffect, useContext } from 'react';
2
+ import require$$0, { useState, useEffect, useRef, createContext, useMemo, useContext } from 'react';
3
3
  import require$$1 from 'react-dom';
4
4
 
5
5
  /**
@@ -2629,15 +2629,7 @@ useEventSource$1.useEventSource = useEventSource;
2629
2629
 
2630
2630
  var useWebSocket = /*@__PURE__*/getDefaultExportFromCjs(dist);
2631
2631
 
2632
- const PearHyperliquidContext = createContext(undefined);
2633
- /**
2634
- * React Provider for PearHyperliquidClient
2635
- */
2636
- const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/ws', children, }) => {
2637
- const client = useMemo(() => new PearHyperliquidClient(config), [config]);
2638
- const migrationSDK = useMemo(() => new PearMigrationSDK(client), [client]);
2639
- // Address state
2640
- const [address, setAddress] = useState(null);
2632
+ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
2641
2633
  // WebSocket data state
2642
2634
  const [data, setData] = useState({
2643
2635
  tradeHistories: null,
@@ -2732,6 +2724,171 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
2732
2724
  });
2733
2725
  }
2734
2726
  }, [isConnected, address, sendMessage]);
2727
+ return {
2728
+ data,
2729
+ connectionStatus: readyState,
2730
+ isConnected,
2731
+ lastError,
2732
+ };
2733
+ };
2734
+
2735
+ const useHyperliquidNativeWebSocket = ({ address }) => {
2736
+ const [webData2, setWebData2] = useState(null);
2737
+ const [allMids, setAllMids] = useState(null);
2738
+ const [lastError, setLastError] = useState(null);
2739
+ const [subscribedAddress, setSubscribedAddress] = useState(null);
2740
+ const pingIntervalRef = useRef(null);
2741
+ // WebSocket connection to HyperLiquid native API
2742
+ const { lastMessage, readyState, sendJsonMessage } = useWebSocket('wss://api.hyperliquid.xyz/ws', {
2743
+ shouldReconnect: () => true,
2744
+ reconnectAttempts: 5,
2745
+ reconnectInterval: 3000,
2746
+ onOpen: () => console.log('[HyperLiquid WS] Connected to wss://api.hyperliquid.xyz/ws'),
2747
+ onClose: () => console.log('[HyperLiquid WS] Connection closed'),
2748
+ onError: (event) => console.error('[HyperLiquid WS] Connection error:', event),
2749
+ onReconnectStop: () => console.error('[HyperLiquid WS] Reconnection stopped after 5 attempts'),
2750
+ });
2751
+ const isConnected = readyState === dist.ReadyState.OPEN;
2752
+ // Setup ping mechanism
2753
+ useEffect(() => {
2754
+ if (isConnected) {
2755
+ console.log('[HyperLiquid WS] Setting up ping mechanism (30s interval)');
2756
+ // Send ping every 30 seconds
2757
+ pingIntervalRef.current = setInterval(() => {
2758
+ console.log('[HyperLiquid WS] Sending ping');
2759
+ sendJsonMessage({ method: 'ping' });
2760
+ }, 30000);
2761
+ }
2762
+ else {
2763
+ if (pingIntervalRef.current) {
2764
+ console.log('[HyperLiquid WS] Clearing ping interval');
2765
+ clearInterval(pingIntervalRef.current);
2766
+ pingIntervalRef.current = null;
2767
+ }
2768
+ }
2769
+ return () => {
2770
+ if (pingIntervalRef.current) {
2771
+ clearInterval(pingIntervalRef.current);
2772
+ pingIntervalRef.current = null;
2773
+ }
2774
+ };
2775
+ }, [isConnected, sendJsonMessage]);
2776
+ // Handle address subscription changes
2777
+ useEffect(() => {
2778
+ if (!isConnected)
2779
+ return;
2780
+ const DEFAULT_ADDRESS = '0x0000000000000000000000000000000000000000';
2781
+ const userAddress = address || DEFAULT_ADDRESS;
2782
+ if (subscribedAddress === userAddress)
2783
+ return;
2784
+ // Unsubscribe from previous address if exists
2785
+ if (subscribedAddress) {
2786
+ console.log(`[HyperLiquid WS] Unsubscribing from webData2 for previous address: ${subscribedAddress}`);
2787
+ const unsubscribeMessage = {
2788
+ method: 'unsubscribe',
2789
+ subscription: {
2790
+ type: 'webData2',
2791
+ user: subscribedAddress,
2792
+ },
2793
+ };
2794
+ sendJsonMessage(unsubscribeMessage);
2795
+ }
2796
+ // Subscribe to webData2 with new address
2797
+ console.log(`[HyperLiquid WS] Subscribing to webData2 for address: ${userAddress}`);
2798
+ const subscribeWebData2 = {
2799
+ method: 'subscribe',
2800
+ subscription: {
2801
+ type: 'webData2',
2802
+ user: userAddress,
2803
+ },
2804
+ };
2805
+ // Subscribe to allMids
2806
+ console.log('[HyperLiquid WS] Subscribing to allMids');
2807
+ const subscribeAllMids = {
2808
+ method: 'subscribe',
2809
+ subscription: {
2810
+ type: 'allMids',
2811
+ },
2812
+ };
2813
+ sendJsonMessage(subscribeWebData2);
2814
+ sendJsonMessage(subscribeAllMids);
2815
+ setSubscribedAddress(userAddress);
2816
+ // Clear previous data when address changes
2817
+ if (subscribedAddress && subscribedAddress !== userAddress) {
2818
+ console.log('[HyperLiquid WS] Address changed, clearing previous webData2');
2819
+ setWebData2(null);
2820
+ }
2821
+ }, [isConnected, address, subscribedAddress, sendJsonMessage]);
2822
+ // Handle incoming WebSocket messages
2823
+ useEffect(() => {
2824
+ if (!lastMessage)
2825
+ return;
2826
+ try {
2827
+ const message = JSON.parse(lastMessage.data);
2828
+ console.log('[HyperLiquid WS] Received message:', message);
2829
+ // Handle subscription responses
2830
+ if ('success' in message || 'error' in message) {
2831
+ if (message.error) {
2832
+ console.error('[HyperLiquid WS] Subscription error:', message.error);
2833
+ setLastError(message.error);
2834
+ }
2835
+ else {
2836
+ console.log('[HyperLiquid WS] Subscription success:', message);
2837
+ setLastError(null);
2838
+ }
2839
+ return;
2840
+ }
2841
+ // Handle channel data messages
2842
+ if ('channel' in message && 'data' in message) {
2843
+ const response = message;
2844
+ console.log(`[HyperLiquid WS] Received ${response.channel} data`);
2845
+ switch (response.channel) {
2846
+ case 'webData2':
2847
+ console.log('[HyperLiquid WS] Setting webData2:', response.data);
2848
+ setWebData2(response.data);
2849
+ break;
2850
+ case 'allMids':
2851
+ console.log('[HyperLiquid WS] Setting allMids:', response.data);
2852
+ setAllMids(response.data);
2853
+ break;
2854
+ default:
2855
+ console.warn(`[HyperLiquid WS] Unknown channel: ${response.channel}`);
2856
+ }
2857
+ }
2858
+ }
2859
+ catch (error) {
2860
+ const errorMessage = `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`;
2861
+ console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', lastMessage.data);
2862
+ setLastError(errorMessage);
2863
+ }
2864
+ }, [lastMessage]);
2865
+ return {
2866
+ webData2,
2867
+ allMids,
2868
+ connectionStatus: readyState,
2869
+ isConnected,
2870
+ lastError,
2871
+ };
2872
+ };
2873
+
2874
+ const PearHyperliquidContext = createContext(undefined);
2875
+ /**
2876
+ * React Provider for PearHyperliquidClient
2877
+ */
2878
+ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/ws', children, }) => {
2879
+ const client = useMemo(() => new PearHyperliquidClient(config), [config]);
2880
+ const migrationSDK = useMemo(() => new PearMigrationSDK(client), [client]);
2881
+ // Address state
2882
+ const [address, setAddress] = useState(null);
2883
+ // WebSocket connection and data (Pear API)
2884
+ const { data, connectionStatus, isConnected, lastError } = useHyperliquidWebSocket({
2885
+ wsUrl,
2886
+ address,
2887
+ });
2888
+ // HyperLiquid native WebSocket connection
2889
+ const { webData2, allMids, connectionStatus: nativeConnectionStatus, isConnected: nativeIsConnected, lastError: nativeLastError } = useHyperliquidNativeWebSocket({
2890
+ address,
2891
+ });
2735
2892
  const contextValue = useMemo(() => ({
2736
2893
  // Existing clients
2737
2894
  client,
@@ -2739,13 +2896,20 @@ const PearHyperliquidProvider = ({ config, wsUrl = 'wss://hl-v2.pearprotocol.io/
2739
2896
  // Address management
2740
2897
  address,
2741
2898
  setAddress,
2742
- // WebSocket state
2743
- connectionStatus: readyState,
2899
+ // WebSocket state (Pear API)
2900
+ connectionStatus,
2744
2901
  isConnected,
2745
- // WebSocket data
2902
+ // WebSocket data (Pear API)
2746
2903
  data,
2747
2904
  lastError,
2748
- }), [client, migrationSDK, address, readyState, isConnected, data, lastError]);
2905
+ // HyperLiquid native WebSocket state
2906
+ nativeConnectionStatus,
2907
+ nativeIsConnected,
2908
+ nativeLastError,
2909
+ // HyperLiquid native WebSocket data
2910
+ webData2,
2911
+ allMids,
2912
+ }), [client, migrationSDK, address, connectionStatus, isConnected, data, lastError, nativeConnectionStatus, nativeIsConnected, nativeLastError, webData2, allMids]);
2749
2913
  return (jsxRuntimeExports.jsx(PearHyperliquidContext.Provider, { value: contextValue, children: children }));
2750
2914
  };
2751
2915
  /**
@@ -2785,6 +2949,483 @@ const useAddress = () => {
2785
2949
  };
2786
2950
  };
2787
2951
 
2952
+ /**
2953
+ * Position side enum for calculations
2954
+ */
2955
+ var PositionSide;
2956
+ (function (PositionSide) {
2957
+ PositionSide["LONG"] = "LONG";
2958
+ PositionSide["SHORT"] = "SHORT";
2959
+ })(PositionSide || (PositionSide = {}));
2960
+ /**
2961
+ * Position calculation utility class
2962
+ */
2963
+ class PositionCalculator {
2964
+ constructor(webData2, allMids) {
2965
+ this.webData2 = webData2;
2966
+ this.allMids = allMids;
2967
+ }
2968
+ /**
2969
+ * Get market price for a coin from allMids data
2970
+ */
2971
+ getMarketPrice(coin) {
2972
+ var _a;
2973
+ if (!((_a = this.allMids) === null || _a === void 0 ? void 0 : _a.mids))
2974
+ return 0;
2975
+ // Try exact match first
2976
+ const exactPrice = this.allMids.mids[coin];
2977
+ if (exactPrice) {
2978
+ return Number(exactPrice);
2979
+ }
2980
+ // If coin has a slash (like "BTC/USD"), try just the base currency
2981
+ const baseCurrency = coin.split('/')[0];
2982
+ const basePrice = this.allMids.mids[baseCurrency];
2983
+ if (basePrice) {
2984
+ return Number(basePrice);
2985
+ }
2986
+ console.warn(`[PositionCalculator] No market price found for coin: ${coin}`);
2987
+ return 0;
2988
+ }
2989
+ /**
2990
+ * Get user positions from webData2
2991
+ */
2992
+ getUserPositions() {
2993
+ var _a, _b;
2994
+ return ((_b = (_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState) === null || _b === void 0 ? void 0 : _b.assetPositions) || [];
2995
+ }
2996
+ /**
2997
+ * Calculate updated open positions by syncing platform positions with HyperLiquid data
2998
+ */
2999
+ calculateOpenPositions(platformPositions) {
3000
+ if (!(platformPositions === null || platformPositions === void 0 ? void 0 : platformPositions.length)) {
3001
+ return [];
3002
+ }
3003
+ const hyperliquidPositions = this.getUserPositions();
3004
+ return platformPositions.map(position => this.syncPositionWithHyperliquid(position, hyperliquidPositions));
3005
+ }
3006
+ /**
3007
+ * Sync a single position with HyperLiquid data
3008
+ */
3009
+ syncPositionWithHyperliquid(position, hyperliquidPositions) {
3010
+ // Create a map of HyperLiquid positions by coin for quick lookup
3011
+ const hlPositionsMap = new Map();
3012
+ hyperliquidPositions.forEach(assetPos => {
3013
+ var _a;
3014
+ if ((_a = assetPos.position) === null || _a === void 0 ? void 0 : _a.coin) {
3015
+ hlPositionsMap.set(assetPos.position.coin, assetPos);
3016
+ }
3017
+ });
3018
+ // Combine all assets for processing
3019
+ const allAssets = [
3020
+ ...position.longAssets.map(asset => ({ ...asset, side: PositionSide.LONG })),
3021
+ ...position.shortAssets.map(asset => ({ ...asset, side: PositionSide.SHORT }))
3022
+ ];
3023
+ // Group assets by base currency for multi-pair position handling
3024
+ const assetsByBaseCurrency = this.groupAssetsByBaseCurrency(allAssets);
3025
+ // Sync each asset group with HyperLiquid data
3026
+ const syncResults = [];
3027
+ for (const [baseCurrency, assets] of assetsByBaseCurrency.entries()) {
3028
+ const hlPosition = hlPositionsMap.get(baseCurrency);
3029
+ const groupSyncResults = this.syncAssetGroupWithHyperliquid(assets, hlPosition);
3030
+ syncResults.push(...groupSyncResults);
3031
+ }
3032
+ // Update position sync status based on asset sync results
3033
+ const syncStatus = this.determineSyncStatus(syncResults);
3034
+ // Rebuild position with synced data
3035
+ return this.buildUpdatedPosition(position, syncResults, syncStatus);
3036
+ }
3037
+ /**
3038
+ * Group assets by their base currency
3039
+ */
3040
+ groupAssetsByBaseCurrency(assets) {
3041
+ const grouped = new Map();
3042
+ for (const asset of assets) {
3043
+ const baseCurrency = asset.coin.split('/')[0] || asset.coin;
3044
+ if (!grouped.has(baseCurrency)) {
3045
+ grouped.set(baseCurrency, []);
3046
+ }
3047
+ grouped.get(baseCurrency).push(asset);
3048
+ }
3049
+ return grouped;
3050
+ }
3051
+ /**
3052
+ * Sync a group of assets (same base currency) with HyperLiquid position data
3053
+ */
3054
+ syncAssetGroupWithHyperliquid(assets, hlPosition) {
3055
+ const results = [];
3056
+ // Calculate total platform size for this base currency
3057
+ const totalPlatformSize = assets.reduce((sum, asset) => sum + asset.platformSize, 0);
3058
+ const actualTotalSize = hlPosition ? Math.abs(Number(hlPosition.position.szi || 0)) : 0;
3059
+ // Check if the total size matches (within tolerance)
3060
+ const sizeDifference = Math.abs(actualTotalSize - totalPlatformSize);
3061
+ const sizeDifferencePercentage = totalPlatformSize > 0
3062
+ ? (sizeDifference / totalPlatformSize) * 100
3063
+ : (actualTotalSize > 0 ? 100 : 0);
3064
+ const isGroupExternallyModified = sizeDifferencePercentage > 0.1; // 0.1% tolerance
3065
+ for (const asset of assets) {
3066
+ const platformSize = asset.platformSize;
3067
+ let actualSize = platformSize;
3068
+ let isExternallyModified = isGroupExternallyModified;
3069
+ let cumFunding = {
3070
+ allTime: 0,
3071
+ sinceChange: 0,
3072
+ sinceOpen: 0
3073
+ };
3074
+ let unrealizedPnl = 0;
3075
+ let liquidationPrice = 0;
3076
+ if (hlPosition) {
3077
+ // Proportionally distribute the actual size based on asset's contribution
3078
+ const sizeRatio = totalPlatformSize > 0 ? platformSize / totalPlatformSize : 0;
3079
+ actualSize = actualTotalSize * sizeRatio;
3080
+ // Proportionally distribute funding and PnL based on asset's contribution
3081
+ if (hlPosition.cumFunding) {
3082
+ cumFunding = {
3083
+ allTime: Number(hlPosition.cumFunding.allTime || 0),
3084
+ sinceChange: Number(hlPosition.cumFunding.sinceChange || 0) * sizeRatio,
3085
+ sinceOpen: Number(hlPosition.cumFunding.sinceOpen || 0) * sizeRatio
3086
+ };
3087
+ }
3088
+ unrealizedPnl = Number(hlPosition.position.unrealizedPnl || 0) * sizeRatio;
3089
+ liquidationPrice = Number(hlPosition.position.liquidationPx || 0);
3090
+ }
3091
+ else {
3092
+ // Position doesn't exist on HyperLiquid - it was closed externally
3093
+ actualSize = 0;
3094
+ isExternallyModified = true;
3095
+ }
3096
+ results.push({
3097
+ asset,
3098
+ actualSize,
3099
+ isExternallyModified,
3100
+ cumFunding,
3101
+ unrealizedPnl,
3102
+ liquidationPrice,
3103
+ side: asset.side
3104
+ });
3105
+ }
3106
+ return results;
3107
+ }
3108
+ /**
3109
+ * Determine sync status based on asset sync results
3110
+ */
3111
+ determineSyncStatus(syncResults) {
3112
+ const hasExternalModifications = syncResults.some(result => result.isExternallyModified);
3113
+ const allAssetsClosed = syncResults.every(result => result.actualSize === 0);
3114
+ const someAssetsClosed = syncResults.some(result => result.actualSize === 0) && !allAssetsClosed;
3115
+ if (allAssetsClosed) {
3116
+ return 'EXTERNALLY_CLOSED';
3117
+ }
3118
+ else if (someAssetsClosed) {
3119
+ return 'PAIR_BROKEN';
3120
+ }
3121
+ else if (hasExternalModifications) {
3122
+ return 'EXTERNALLY_MODIFIED';
3123
+ }
3124
+ return 'SYNCED';
3125
+ }
3126
+ /**
3127
+ * Build updated position with synced data
3128
+ */
3129
+ buildUpdatedPosition(originalPosition, syncResults, syncStatus) {
3130
+ const longSyncResults = syncResults.filter(result => result.side === PositionSide.LONG);
3131
+ const shortSyncResults = syncResults.filter(result => result.side === PositionSide.SHORT);
3132
+ // Calculate position metrics
3133
+ const currentTotalPositionValue = this.calculateCurrentTotalPositionValue(syncResults);
3134
+ const entryTotalPositionValue = this.calculateEntryTotalPositionValue(syncResults);
3135
+ const totalMarginUsed = entryTotalPositionValue / originalPosition.leverage;
3136
+ return {
3137
+ ...originalPosition,
3138
+ syncStatus,
3139
+ entryRatio: this.calculateEntryRatio(syncResults),
3140
+ markRatio: this.calculateMarkRatio(syncResults),
3141
+ netFunding: this.calculateNetFundingFromSyncResults(syncResults),
3142
+ positionValue: currentTotalPositionValue,
3143
+ marginUsed: totalMarginUsed,
3144
+ unrealizedPnl: this.calculateTotalUnrealizedPnlFromSyncResults(syncResults),
3145
+ lastSyncAt: new Date().toISOString(),
3146
+ longAssets: longSyncResults.map(result => this.mapSyncResultToAssetDto(result)),
3147
+ shortAssets: shortSyncResults.map(result => this.mapSyncResultToAssetDto(result)),
3148
+ updatedAt: new Date().toISOString()
3149
+ };
3150
+ }
3151
+ /**
3152
+ * Map sync result to PositionAssetDetailDto
3153
+ */
3154
+ mapSyncResultToAssetDto(syncResult) {
3155
+ const currentPrice = this.getMarketPrice(syncResult.asset.coin);
3156
+ const positionValue = syncResult.actualSize * currentPrice;
3157
+ const entryValue = syncResult.actualSize * syncResult.asset.entryPrice;
3158
+ return {
3159
+ ...syncResult.asset,
3160
+ actualSize: syncResult.actualSize,
3161
+ isExternallyModified: syncResult.isExternallyModified,
3162
+ cumFunding: syncResult.cumFunding,
3163
+ marginUsed: entryValue,
3164
+ positionValue: positionValue,
3165
+ unrealizedPnl: syncResult.unrealizedPnl,
3166
+ liquidationPrice: syncResult.liquidationPrice
3167
+ };
3168
+ }
3169
+ /**
3170
+ * Calculate entry ratio (weighted long entry value / weighted short entry value)
3171
+ */
3172
+ calculateEntryRatio(syncResults) {
3173
+ const longResults = syncResults.filter(result => result.side === PositionSide.LONG);
3174
+ const shortResults = syncResults.filter(result => result.side === PositionSide.SHORT);
3175
+ if (longResults.length === 0 || shortResults.length === 0)
3176
+ return 0;
3177
+ // Calculate total position value at entry prices
3178
+ const totalPositionValue = syncResults.reduce((sum, result) => {
3179
+ return sum + (result.actualSize * result.asset.entryPrice);
3180
+ }, 0);
3181
+ if (totalPositionValue === 0)
3182
+ return 0;
3183
+ // Calculate weighted long portfolio entry value
3184
+ const weightedLongValue = longResults.reduce((sum, result) => {
3185
+ const entryPrice = result.asset.entryPrice;
3186
+ const assetValue = result.actualSize * entryPrice;
3187
+ const weight = assetValue / totalPositionValue;
3188
+ return sum + (entryPrice * weight);
3189
+ }, 0);
3190
+ // Calculate weighted short portfolio entry value
3191
+ const weightedShortValue = shortResults.reduce((sum, result) => {
3192
+ const entryPrice = result.asset.entryPrice;
3193
+ const assetValue = result.actualSize * entryPrice;
3194
+ const weight = assetValue / totalPositionValue;
3195
+ return sum + (entryPrice * weight);
3196
+ }, 0);
3197
+ return weightedShortValue > 0 ? weightedLongValue / weightedShortValue : 0;
3198
+ }
3199
+ /**
3200
+ * Calculate mark ratio (weighted long mark value / weighted short mark value)
3201
+ */
3202
+ calculateMarkRatio(syncResults) {
3203
+ const longResults = syncResults.filter(result => result.side === PositionSide.LONG);
3204
+ const shortResults = syncResults.filter(result => result.side === PositionSide.SHORT);
3205
+ if (longResults.length === 0 || shortResults.length === 0)
3206
+ return 0;
3207
+ // Calculate total position value at current market prices
3208
+ const totalPositionValue = syncResults.reduce((sum, result) => {
3209
+ const currentPrice = this.getMarketPrice(result.asset.coin);
3210
+ return sum + (result.actualSize * currentPrice);
3211
+ }, 0);
3212
+ if (totalPositionValue === 0)
3213
+ return 0;
3214
+ // Calculate weighted long portfolio value
3215
+ const weightedLongValue = longResults.reduce((sum, result) => {
3216
+ const currentPrice = this.getMarketPrice(result.asset.coin);
3217
+ const assetValue = result.actualSize * currentPrice;
3218
+ const weight = assetValue / totalPositionValue;
3219
+ return sum + (currentPrice * weight);
3220
+ }, 0);
3221
+ // Calculate weighted short portfolio value
3222
+ const weightedShortValue = shortResults.reduce((sum, result) => {
3223
+ const currentPrice = this.getMarketPrice(result.asset.coin);
3224
+ const assetValue = result.actualSize * currentPrice;
3225
+ const weight = assetValue / totalPositionValue;
3226
+ return sum + (currentPrice * weight);
3227
+ }, 0);
3228
+ return weightedShortValue > 0 ? weightedLongValue / weightedShortValue : 0;
3229
+ }
3230
+ /**
3231
+ * Calculate net funding from sync results
3232
+ */
3233
+ calculateNetFundingFromSyncResults(syncResults) {
3234
+ return syncResults.reduce((sum, result) => sum + result.cumFunding.sinceOpen, 0);
3235
+ }
3236
+ /**
3237
+ * Calculate total unrealized PnL from sync results
3238
+ */
3239
+ calculateTotalUnrealizedPnlFromSyncResults(syncResults) {
3240
+ return syncResults.reduce((sum, result) => sum + result.unrealizedPnl, 0);
3241
+ }
3242
+ /**
3243
+ * Calculate current total position value using market prices
3244
+ */
3245
+ calculateCurrentTotalPositionValue(syncResults) {
3246
+ return syncResults.reduce((sum, result) => {
3247
+ const currentPrice = this.getMarketPrice(result.asset.coin);
3248
+ return sum + (result.actualSize * currentPrice);
3249
+ }, 0);
3250
+ }
3251
+ /**
3252
+ * Calculate entry total position value using entry prices
3253
+ */
3254
+ calculateEntryTotalPositionValue(syncResults) {
3255
+ return syncResults.reduce((sum, result) => {
3256
+ return sum + (result.actualSize * result.asset.entryPrice);
3257
+ }, 0);
3258
+ }
3259
+ }
3260
+
3261
+ /**
3262
+ * Hook that calculates open positions by syncing platform positions with HyperLiquid real-time data
3263
+ */
3264
+ const useCalculatedOpenPositions = (platformPositions, webData2, allMids) => {
3265
+ const calculatedPositions = useMemo(() => {
3266
+ var _a, _b;
3267
+ // Return null if we don't have platform positions yet
3268
+ if (!platformPositions) {
3269
+ console.log('[useCalculatedOpenPositions] No platform positions available');
3270
+ return null;
3271
+ }
3272
+ // If we don't have real-time data yet, return platform positions as-is
3273
+ if (!webData2 || !allMids) {
3274
+ console.log('[useCalculatedOpenPositions] Missing real-time data, returning platform positions');
3275
+ return platformPositions;
3276
+ }
3277
+ console.log('[useCalculatedOpenPositions] Calculating positions with real-time data', {
3278
+ platformPositionsCount: platformPositions.length,
3279
+ hasWebData2: !!webData2,
3280
+ hasAllMids: !!allMids,
3281
+ hyperliquidPositionsCount: ((_b = (_a = webData2.clearinghouseState) === null || _a === void 0 ? void 0 : _a.assetPositions) === null || _b === void 0 ? void 0 : _b.length) || 0,
3282
+ availableMids: Object.keys(allMids.mids || {}).length
3283
+ });
3284
+ // Create calculator and compute positions
3285
+ const calculator = new PositionCalculator(webData2, allMids);
3286
+ const calculated = calculator.calculateOpenPositions(platformPositions);
3287
+ console.log('[useCalculatedOpenPositions] Calculation completed', {
3288
+ inputCount: platformPositions.length,
3289
+ outputCount: calculated.length
3290
+ });
3291
+ return calculated;
3292
+ }, [platformPositions, webData2, allMids]);
3293
+ return calculatedPositions;
3294
+ };
3295
+
3296
+ /**
3297
+ * Account summary calculation utility class
3298
+ */
3299
+ class AccountSummaryCalculator {
3300
+ constructor(webData2) {
3301
+ this.webData2 = webData2;
3302
+ }
3303
+ /**
3304
+ * Calculate account summary from webData2 and platform orders
3305
+ */
3306
+ calculateAccountSummary(platformAccountSummary, platformOpenOrders, agentWalletAddress, agentWalletStatus) {
3307
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
3308
+ // If we don't have webData2, return platform data as-is
3309
+ if (!((_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState)) {
3310
+ console.log('[AccountSummaryCalculator] No webData2 clearinghouseState available, returning platform data');
3311
+ return platformAccountSummary;
3312
+ }
3313
+ console.log('[AccountSummaryCalculator] Calculating account summary with real-time data', {
3314
+ hasPlatformSummary: !!platformAccountSummary,
3315
+ hasOpenOrders: !!platformOpenOrders,
3316
+ openOrdersCount: (platformOpenOrders === null || platformOpenOrders === void 0 ? void 0 : platformOpenOrders.length) || 0,
3317
+ hasAgentWallet: !!agentWalletAddress
3318
+ });
3319
+ const clearinghouseState = this.webData2.clearinghouseState;
3320
+ // Calculate total limit order value from platform orders
3321
+ const totalLimitOrderValue = this.calculateTotalLimitOrderValue(platformOpenOrders || []);
3322
+ console.log('[AccountSummaryCalculator] Total limit order value:', totalLimitOrderValue);
3323
+ // Use real-time data from webData2 clearinghouseState
3324
+ const withdrawableAmount = parseFloat(clearinghouseState.withdrawable || '0');
3325
+ const adjustedWithdrawable = Math.max(0, withdrawableAmount - totalLimitOrderValue);
3326
+ const accountSummary = {
3327
+ balanceSummary: {
3328
+ crossMaintenanceMarginUsed: clearinghouseState.crossMaintenanceMarginUsed || '0',
3329
+ crossMarginSummary: {
3330
+ accountValue: ((_b = clearinghouseState.crossMarginSummary) === null || _b === void 0 ? void 0 : _b.accountValue) || '0',
3331
+ totalMarginUsed: ((_c = clearinghouseState.crossMarginSummary) === null || _c === void 0 ? void 0 : _c.totalMarginUsed) || '0',
3332
+ totalNtlPos: ((_d = clearinghouseState.crossMarginSummary) === null || _d === void 0 ? void 0 : _d.totalNtlPos) || '0',
3333
+ totalRawUsd: ((_e = clearinghouseState.crossMarginSummary) === null || _e === void 0 ? void 0 : _e.totalRawUsd) || '0'
3334
+ },
3335
+ marginSummary: {
3336
+ accountValue: ((_f = clearinghouseState.marginSummary) === null || _f === void 0 ? void 0 : _f.accountValue) || '0',
3337
+ totalMarginUsed: ((_g = clearinghouseState.marginSummary) === null || _g === void 0 ? void 0 : _g.totalMarginUsed) || '0',
3338
+ totalNtlPos: ((_h = clearinghouseState.marginSummary) === null || _h === void 0 ? void 0 : _h.totalNtlPos) || '0',
3339
+ totalRawUsd: ((_j = clearinghouseState.marginSummary) === null || _j === void 0 ? void 0 : _j.totalRawUsd) || '0'
3340
+ },
3341
+ time: clearinghouseState.time || Date.now(),
3342
+ withdrawable: adjustedWithdrawable.toString()
3343
+ },
3344
+ agentWallet: {
3345
+ address: agentWalletAddress || ((_k = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWallet) === null || _k === void 0 ? void 0 : _k.address) || '',
3346
+ status: agentWalletStatus || ((_l = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWallet) === null || _l === void 0 ? void 0 : _l.status) || 'UNKNOWN'
3347
+ }
3348
+ };
3349
+ console.log('[AccountSummaryCalculator] Calculated account summary:', {
3350
+ accountValue: accountSummary.balanceSummary.crossMarginSummary.accountValue,
3351
+ withdrawable: accountSummary.balanceSummary.withdrawable,
3352
+ totalMarginUsed: accountSummary.balanceSummary.crossMarginSummary.totalMarginUsed,
3353
+ agentWalletAddress: accountSummary.agentWallet.address
3354
+ });
3355
+ return accountSummary;
3356
+ }
3357
+ /**
3358
+ * Calculate total USD value of open limit orders
3359
+ */
3360
+ calculateTotalLimitOrderValue(openOrders) {
3361
+ if (!(openOrders === null || openOrders === void 0 ? void 0 : openOrders.length)) {
3362
+ return 0;
3363
+ }
3364
+ const totalValue = openOrders
3365
+ .filter(order => order.status === 'OPEN' || order.status === 'PROCESSING')
3366
+ .reduce((sum, order) => sum + order.usdValue, 0);
3367
+ console.log('[AccountSummaryCalculator] Calculated limit order value:', {
3368
+ totalOrders: openOrders.length,
3369
+ openOrders: openOrders.filter(order => order.status === 'OPEN' || order.status === 'PROCESSING').length,
3370
+ totalValue
3371
+ });
3372
+ return totalValue;
3373
+ }
3374
+ /**
3375
+ * Get real-time clearinghouse state from webData2
3376
+ */
3377
+ getClearinghouseState() {
3378
+ var _a;
3379
+ return ((_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState) || null;
3380
+ }
3381
+ /**
3382
+ * Check if real-time data is available
3383
+ */
3384
+ hasRealTimeData() {
3385
+ var _a;
3386
+ return !!((_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState);
3387
+ }
3388
+ }
3389
+
3390
+ /**
3391
+ * Hook that calculates account summary by syncing platform data with HyperLiquid real-time data
3392
+ */
3393
+ const useCalculatedAccountSummary = (platformAccountSummary, platformOpenOrders, webData2, agentWalletAddress, agentWalletStatus) => {
3394
+ const calculatedAccountSummary = useMemo(() => {
3395
+ var _a, _b, _c;
3396
+ // Return null if we don't have platform account summary yet
3397
+ if (!platformAccountSummary) {
3398
+ console.log('[useCalculatedAccountSummary] No platform account summary available');
3399
+ return null;
3400
+ }
3401
+ // If we don't have real-time data yet, return platform summary as-is
3402
+ if (!(webData2 === null || webData2 === void 0 ? void 0 : webData2.clearinghouseState)) {
3403
+ console.log('[useCalculatedAccountSummary] Missing webData2 clearinghouseState, returning platform summary');
3404
+ return platformAccountSummary;
3405
+ }
3406
+ console.log('[useCalculatedAccountSummary] Calculating account summary with real-time data', {
3407
+ hasPlatformSummary: !!platformAccountSummary,
3408
+ hasWebData2: !!webData2,
3409
+ hasClearinghouseState: !!webData2.clearinghouseState,
3410
+ hasOpenOrders: !!platformOpenOrders,
3411
+ openOrdersCount: (platformOpenOrders === null || platformOpenOrders === void 0 ? void 0 : platformOpenOrders.length) || 0,
3412
+ agentWalletAddress,
3413
+ agentWalletStatus
3414
+ });
3415
+ // Create calculator and compute account summary
3416
+ const calculator = new AccountSummaryCalculator(webData2);
3417
+ const calculated = calculator.calculateAccountSummary(platformAccountSummary, platformOpenOrders, agentWalletAddress, agentWalletStatus);
3418
+ console.log('[useCalculatedAccountSummary] Calculation completed', {
3419
+ hadPlatformSummary: !!platformAccountSummary,
3420
+ calculatedSummary: !!calculated,
3421
+ withdrawable: (_a = calculated === null || calculated === void 0 ? void 0 : calculated.balanceSummary) === null || _a === void 0 ? void 0 : _a.withdrawable,
3422
+ accountValue: (_c = (_b = calculated === null || calculated === void 0 ? void 0 : calculated.balanceSummary) === null || _b === void 0 ? void 0 : _b.crossMarginSummary) === null || _c === void 0 ? void 0 : _c.accountValue
3423
+ });
3424
+ return calculated;
3425
+ }, [platformAccountSummary, platformOpenOrders, webData2, agentWalletAddress, agentWalletStatus]);
3426
+ return calculatedAccountSummary;
3427
+ };
3428
+
2788
3429
  /**
2789
3430
  * Hook to access trade histories
2790
3431
  */
@@ -2796,14 +3437,16 @@ const useTradeHistories = () => {
2796
3437
  return context.data.tradeHistories;
2797
3438
  };
2798
3439
  /**
2799
- * Hook to access open positions
3440
+ * Hook to access open positions with real-time calculations
2800
3441
  */
2801
3442
  const useOpenPositions = () => {
2802
3443
  const context = useContext(PearHyperliquidContext);
2803
3444
  if (!context) {
2804
3445
  throw new Error('useOpenPositions must be used within a PearHyperliquidProvider');
2805
3446
  }
2806
- return context.data.openPositions;
3447
+ // Use calculated positions that sync platform data with HyperLiquid real-time data
3448
+ const calculatedPositions = useCalculatedOpenPositions(context.data.openPositions, context.webData2, context.allMids);
3449
+ return calculatedPositions;
2807
3450
  };
2808
3451
  /**
2809
3452
  * Hook to access open orders
@@ -2816,15 +3459,18 @@ const useOpenOrders = () => {
2816
3459
  return context.data.openOrders;
2817
3460
  };
2818
3461
  /**
2819
- * Hook to access account summary
3462
+ * Hook to access account summary with real-time calculations
2820
3463
  */
2821
3464
  const useAccountSummary = () => {
3465
+ var _a, _b, _c, _d;
2822
3466
  const context = useContext(PearHyperliquidContext);
2823
3467
  if (!context) {
2824
3468
  throw new Error('useAccountSummary must be used within a PearHyperliquidProvider');
2825
3469
  }
2826
- return context.data.accountSummary;
3470
+ // Use calculated account summary that syncs platform data with HyperLiquid real-time data
3471
+ const calculatedAccountSummary = useCalculatedAccountSummary(context.data.accountSummary, context.data.openOrders, context.webData2, (_b = (_a = context.data.accountSummary) === null || _a === void 0 ? void 0 : _a.agentWallet) === null || _b === void 0 ? void 0 : _b.address, (_d = (_c = context.data.accountSummary) === null || _c === void 0 ? void 0 : _c.agentWallet) === null || _d === void 0 ? void 0 : _d.status);
3472
+ return calculatedAccountSummary;
2827
3473
  };
2828
3474
 
2829
- export { PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, PearHyperliquidClient as default, useAccountSummary, useAddress, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, useTradeHistories };
3475
+ export { AccountSummaryCalculator, PearHyperliquidClient, PearHyperliquidProvider, PearMigrationSDK, PositionCalculator, PositionSide, PearHyperliquidClient as default, useAccountSummary, useAddress, useCalculatedAccountSummary, useCalculatedOpenPositions, useHyperliquidNativeWebSocket, useHyperliquidWebSocket, useMigrationSDK, useOpenOrders, useOpenPositions, usePearHyperliquidClient, useTradeHistories };
2830
3476
  //# sourceMappingURL=index.esm.js.map