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