@pear-protocol/hyperliquid-sdk 0.0.8 → 0.0.10

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
@@ -2642,21 +2642,17 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
2642
2642
  accountSummary: null,
2643
2643
  });
2644
2644
  const [lastError, setLastError] = require$$0.useState(null);
2645
+ const [lastSubscribedAddress, setLastSubscribedAddress] = require$$0.useState(null);
2645
2646
  // WebSocket connection
2646
- const { lastMessage, readyState, sendMessage } = useWebSocket(address ? wsUrl : null, // Only connect when address is set
2647
- {
2647
+ const { readyState, sendMessage } = useWebSocket(wsUrl, {
2648
2648
  shouldReconnect: () => true,
2649
2649
  reconnectAttempts: 5,
2650
2650
  reconnectInterval: 3000,
2651
- });
2652
- const isConnected = readyState === dist.ReadyState.OPEN;
2653
- // Handle incoming WebSocket messages
2654
- require$$0.useEffect(() => {
2655
- if (lastMessage !== null) {
2651
+ onMessage: (event) => {
2656
2652
  try {
2657
- const message = JSON.parse(lastMessage.data);
2658
- // Handle subscription responses
2659
- if ('success' in message || 'error' in message) {
2653
+ const message = JSON.parse(event.data);
2654
+ // Handle subscription responses (only if they don't have channel data)
2655
+ if (('success' in message || 'error' in message) && !('channel' in message)) {
2660
2656
  if (message.error) {
2661
2657
  setLastError(message.error);
2662
2658
  }
@@ -2668,30 +2664,42 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
2668
2664
  // Handle channel data messages
2669
2665
  if ('channel' in message && 'data' in message) {
2670
2666
  const dataMessage = message;
2667
+ // Validate data exists and is not null/undefined
2668
+ if (dataMessage.data === null || dataMessage.data === undefined) {
2669
+ return;
2670
+ }
2671
2671
  switch (dataMessage.channel) {
2672
2672
  case 'trade-histories':
2673
- setData(prev => ({
2674
- ...prev,
2675
- tradeHistories: dataMessage.data
2676
- }));
2673
+ if (Array.isArray(dataMessage.data)) {
2674
+ setData(prev => ({
2675
+ ...prev,
2676
+ tradeHistories: dataMessage.data
2677
+ }));
2678
+ }
2677
2679
  break;
2678
2680
  case 'open-positions':
2679
- setData(prev => ({
2680
- ...prev,
2681
- openPositions: dataMessage.data
2682
- }));
2681
+ if (Array.isArray(dataMessage.data)) {
2682
+ setData(prev => ({
2683
+ ...prev,
2684
+ openPositions: dataMessage.data
2685
+ }));
2686
+ }
2683
2687
  break;
2684
2688
  case 'open-orders':
2685
- setData(prev => ({
2686
- ...prev,
2687
- openOrders: dataMessage.data
2688
- }));
2689
+ if (Array.isArray(dataMessage.data)) {
2690
+ setData(prev => ({
2691
+ ...prev,
2692
+ openOrders: dataMessage.data
2693
+ }));
2694
+ }
2689
2695
  break;
2690
2696
  case 'account-summary':
2691
- setData(prev => ({
2692
- ...prev,
2693
- accountSummary: dataMessage.data
2694
- }));
2697
+ if (typeof dataMessage.data === 'object' && dataMessage.data !== null) {
2698
+ setData(prev => ({
2699
+ ...prev,
2700
+ accountSummary: dataMessage.data
2701
+ }));
2702
+ }
2695
2703
  break;
2696
2704
  }
2697
2705
  }
@@ -2700,34 +2708,47 @@ const useHyperliquidWebSocket = ({ wsUrl, address }) => {
2700
2708
  setLastError(`Failed to parse message: ${error instanceof Error ? error.message : String(error)}`);
2701
2709
  }
2702
2710
  }
2703
- }, [lastMessage]);
2704
- // Handle address changes - subscribe/unsubscribe
2711
+ });
2712
+ const isConnected = readyState === dist.ReadyState.OPEN;
2713
+ // Handle subscription management
2705
2714
  require$$0.useEffect(() => {
2706
- if (isConnected && address) {
2715
+ if (isConnected && address && address !== lastSubscribedAddress) {
2716
+ // Unsubscribe from previous address if exists
2717
+ if (lastSubscribedAddress) {
2718
+ sendMessage(JSON.stringify({
2719
+ action: 'unsubscribe',
2720
+ address: lastSubscribedAddress
2721
+ }));
2722
+ }
2707
2723
  // Subscribe to new address
2708
2724
  sendMessage(JSON.stringify({
2709
2725
  action: 'subscribe',
2710
2726
  address: address
2711
2727
  }));
2712
- // Clear previous data
2713
- setData({
2714
- tradeHistories: null,
2715
- openPositions: null,
2716
- openOrders: null,
2717
- accountSummary: null,
2718
- });
2728
+ setLastSubscribedAddress(address);
2719
2729
  setLastError(null);
2720
2730
  }
2721
- else if (isConnected && !address) {
2722
- // Clear data when address is removed
2731
+ else if (isConnected && !address && lastSubscribedAddress) {
2732
+ // Send unsubscribe action when address is removed
2733
+ sendMessage(JSON.stringify({
2734
+ action: 'unsubscribe',
2735
+ address: lastSubscribedAddress
2736
+ }));
2737
+ setLastSubscribedAddress(null);
2738
+ }
2739
+ }, [isConnected, address, lastSubscribedAddress, sendMessage]);
2740
+ // Clear data when address changes
2741
+ require$$0.useEffect(() => {
2742
+ if (address !== lastSubscribedAddress) {
2723
2743
  setData({
2724
2744
  tradeHistories: null,
2725
2745
  openPositions: null,
2726
2746
  openOrders: null,
2727
2747
  accountSummary: null,
2728
2748
  });
2749
+ setLastError(null);
2729
2750
  }
2730
- }, [isConnected, address, sendMessage]);
2751
+ }, [address, lastSubscribedAddress]);
2731
2752
  return {
2732
2753
  data,
2733
2754
  connectionStatus: readyState,
@@ -2743,29 +2764,61 @@ const useHyperliquidNativeWebSocket = ({ address }) => {
2743
2764
  const [subscribedAddress, setSubscribedAddress] = require$$0.useState(null);
2744
2765
  const pingIntervalRef = require$$0.useRef(null);
2745
2766
  // WebSocket connection to HyperLiquid native API
2746
- const { lastMessage, readyState, sendJsonMessage } = useWebSocket('wss://api.hyperliquid.xyz/ws', {
2767
+ const { readyState, sendJsonMessage } = useWebSocket('wss://api.hyperliquid.xyz/ws', {
2747
2768
  shouldReconnect: () => true,
2748
2769
  reconnectAttempts: 5,
2749
2770
  reconnectInterval: 3000,
2750
- onOpen: () => console.log('[HyperLiquid WS] Connected to wss://api.hyperliquid.xyz/ws'),
2751
- onClose: () => console.log('[HyperLiquid WS] Connection closed'),
2771
+ onOpen: () => { },
2772
+ onClose: () => { },
2752
2773
  onError: (event) => console.error('[HyperLiquid WS] Connection error:', event),
2753
2774
  onReconnectStop: () => console.error('[HyperLiquid WS] Reconnection stopped after 5 attempts'),
2775
+ onMessage: (event) => {
2776
+ try {
2777
+ const message = JSON.parse(event.data);
2778
+ // Handle subscription responses
2779
+ if ('success' in message || 'error' in message) {
2780
+ if (message.error) {
2781
+ console.error('[HyperLiquid WS] Subscription error:', message.error);
2782
+ setLastError(message.error);
2783
+ }
2784
+ else {
2785
+ setLastError(null);
2786
+ }
2787
+ return;
2788
+ }
2789
+ // Handle channel data messages
2790
+ if ('channel' in message && 'data' in message) {
2791
+ const response = message;
2792
+ switch (response.channel) {
2793
+ case 'webData2':
2794
+ setWebData2(response.data);
2795
+ break;
2796
+ case 'allMids':
2797
+ setAllMids(response.data);
2798
+ break;
2799
+ default:
2800
+ console.warn(`[HyperLiquid WS] Unknown channel: ${response.channel}`);
2801
+ }
2802
+ }
2803
+ }
2804
+ catch (error) {
2805
+ const errorMessage = `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`;
2806
+ console.error('[HyperLiquid WS] Parse error:', errorMessage, 'Raw message:', event.data);
2807
+ setLastError(errorMessage);
2808
+ }
2809
+ }
2754
2810
  });
2755
2811
  const isConnected = readyState === dist.ReadyState.OPEN;
2756
2812
  // Setup ping mechanism
2757
2813
  require$$0.useEffect(() => {
2758
2814
  if (isConnected) {
2759
- console.log('[HyperLiquid WS] Setting up ping mechanism (30s interval)');
2760
2815
  // Send ping every 30 seconds
2761
2816
  pingIntervalRef.current = setInterval(() => {
2762
- console.log('[HyperLiquid WS] Sending ping');
2763
2817
  sendJsonMessage({ method: 'ping' });
2764
2818
  }, 30000);
2765
2819
  }
2766
2820
  else {
2767
2821
  if (pingIntervalRef.current) {
2768
- console.log('[HyperLiquid WS] Clearing ping interval');
2769
2822
  clearInterval(pingIntervalRef.current);
2770
2823
  pingIntervalRef.current = null;
2771
2824
  }
@@ -2787,7 +2840,6 @@ const useHyperliquidNativeWebSocket = ({ address }) => {
2787
2840
  return;
2788
2841
  // Unsubscribe from previous address if exists
2789
2842
  if (subscribedAddress) {
2790
- console.log(`[HyperLiquid WS] Unsubscribing from webData2 for previous address: ${subscribedAddress}`);
2791
2843
  const unsubscribeMessage = {
2792
2844
  method: 'unsubscribe',
2793
2845
  subscription: {
@@ -2798,7 +2850,6 @@ const useHyperliquidNativeWebSocket = ({ address }) => {
2798
2850
  sendJsonMessage(unsubscribeMessage);
2799
2851
  }
2800
2852
  // Subscribe to webData2 with new address
2801
- console.log(`[HyperLiquid WS] Subscribing to webData2 for address: ${userAddress}`);
2802
2853
  const subscribeWebData2 = {
2803
2854
  method: 'subscribe',
2804
2855
  subscription: {
@@ -2807,7 +2858,6 @@ const useHyperliquidNativeWebSocket = ({ address }) => {
2807
2858
  },
2808
2859
  };
2809
2860
  // Subscribe to allMids
2810
- console.log('[HyperLiquid WS] Subscribing to allMids');
2811
2861
  const subscribeAllMids = {
2812
2862
  method: 'subscribe',
2813
2863
  subscription: {
@@ -2819,53 +2869,9 @@ const useHyperliquidNativeWebSocket = ({ address }) => {
2819
2869
  setSubscribedAddress(userAddress);
2820
2870
  // Clear previous data when address changes
2821
2871
  if (subscribedAddress && subscribedAddress !== userAddress) {
2822
- console.log('[HyperLiquid WS] Address changed, clearing previous webData2');
2823
2872
  setWebData2(null);
2824
2873
  }
2825
2874
  }, [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
2875
  return {
2870
2876
  webData2,
2871
2877
  allMids,
@@ -2953,84 +2959,76 @@ const useAddress = () => {
2953
2959
  };
2954
2960
  };
2955
2961
 
2956
- /**
2957
- * Position side enum for calculations
2958
- */
2959
- exports.PositionSide = void 0;
2962
+ var PositionSide;
2960
2963
  (function (PositionSide) {
2961
2964
  PositionSide["LONG"] = "LONG";
2962
2965
  PositionSide["SHORT"] = "SHORT";
2963
- })(exports.PositionSide || (exports.PositionSide = {}));
2964
- /**
2965
- * Aggregate position calculation utility class that handles cross-position asset syncing
2966
- */
2967
- class AggregatePositionCalculator {
2966
+ })(PositionSide || (PositionSide = {}));
2967
+ class PositionProcessor {
2968
2968
  constructor(webData2, allMids) {
2969
2969
  this.webData2 = webData2;
2970
2970
  this.allMids = allMids;
2971
2971
  }
2972
- /**
2973
- * Get market price for a coin from allMids data
2974
- */
2972
+ execute(rawPositions) {
2973
+ if (!rawPositions || rawPositions.length === 0) {
2974
+ return [];
2975
+ }
2976
+ const userHyperliquidPositions = this.getUserPositions();
2977
+ const platformTotalsByAsset = this.calculatePlatformTotalsByAsset(rawPositions);
2978
+ const hlPositionsMap = new Map();
2979
+ (userHyperliquidPositions || []).forEach(assetPos => {
2980
+ var _a;
2981
+ if ((_a = assetPos.position) === null || _a === void 0 ? void 0 : _a.coin) {
2982
+ hlPositionsMap.set(assetPos.position.coin, assetPos);
2983
+ }
2984
+ });
2985
+ const openPositionDtos = [];
2986
+ for (const position of rawPositions) {
2987
+ const syncedPositionDto = this.syncPositionWithAggregateData(position, hlPositionsMap, platformTotalsByAsset);
2988
+ openPositionDtos.push(syncedPositionDto);
2989
+ }
2990
+ return openPositionDtos;
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
+ }
2975
2996
  getMarketPrice(coin) {
2976
2997
  var _a;
2977
2998
  if (!((_a = this.allMids) === null || _a === void 0 ? void 0 : _a.mids))
2978
2999
  return 0;
2979
- // Try exact match first
2980
3000
  const exactPrice = this.allMids.mids[coin];
2981
3001
  if (exactPrice) {
2982
3002
  return Number(exactPrice);
2983
3003
  }
2984
- // If coin has a slash (like "BTC/USD"), try just the base currency
2985
- const baseCurrency = coin.split('/')[0];
3004
+ const baseCurrency = this.extractBaseCurrency(coin);
2986
3005
  const basePrice = this.allMids.mids[baseCurrency];
2987
3006
  if (basePrice) {
2988
3007
  return Number(basePrice);
2989
3008
  }
2990
- console.warn(`[AggregatePositionCalculator] No market price found for coin: ${coin}`);
2991
3009
  return 0;
2992
3010
  }
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
- * Uses aggregate totals across all positions for accurate cross-position sync
3003
- */
3004
- calculateOpenPositions(platformPositions) {
3005
- if (!(platformPositions === null || platformPositions === void 0 ? void 0 : platformPositions.length)) {
3006
- return [];
3007
- }
3008
- const hyperliquidPositions = this.getUserPositions();
3009
- // Build a map of total platform sizes per asset across ALL positions
3010
- const platformTotalsByAsset = this.calculatePlatformTotalsByAsset(platformPositions);
3011
- // Create a map of HyperLiquid positions by coin
3012
- const hlPositionsMap = new Map();
3013
- hyperliquidPositions.forEach(assetPos => {
3014
- var _a;
3015
- if ((_a = assetPos.position) === null || _a === void 0 ? void 0 : _a.coin) {
3016
- hlPositionsMap.set(assetPos.position.coin, assetPos);
3017
- }
3018
- });
3019
- // Process each position with awareness of the aggregated totals
3020
- return platformPositions.map(position => this.syncPositionWithAggregateData(position, hlPositionsMap, platformTotalsByAsset));
3021
- }
3022
- /**
3023
- * Calculate total platform sizes per asset across all positions
3024
- */
3025
3011
  calculatePlatformTotalsByAsset(positions) {
3026
3012
  const totalsMap = new Map();
3027
3013
  for (const position of positions) {
3028
- // Combine all assets from both sides
3029
- const allAssets = [
3030
- ...position.longAssets.map(asset => ({ ...asset, side: exports.PositionSide.LONG })),
3031
- ...position.shortAssets.map(asset => ({ ...asset, side: exports.PositionSide.SHORT }))
3032
- ];
3033
- for (const asset of allAssets) {
3014
+ for (const asset of position.longAssets || []) {
3015
+ const baseCurrency = this.extractBaseCurrency(asset.coin);
3016
+ if (!totalsMap.has(baseCurrency)) {
3017
+ totalsMap.set(baseCurrency, {
3018
+ totalSize: 0,
3019
+ positions: []
3020
+ });
3021
+ }
3022
+ const totals = totalsMap.get(baseCurrency);
3023
+ const assetSize = Number(asset.size || 0);
3024
+ totals.totalSize += assetSize;
3025
+ totals.positions.push({
3026
+ positionId: position.positionId,
3027
+ asset: asset,
3028
+ size: assetSize
3029
+ });
3030
+ }
3031
+ for (const asset of position.shortAssets || []) {
3034
3032
  const baseCurrency = this.extractBaseCurrency(asset.coin);
3035
3033
  if (!totalsMap.has(baseCurrency)) {
3036
3034
  totalsMap.set(baseCurrency, {
@@ -3039,7 +3037,7 @@ class AggregatePositionCalculator {
3039
3037
  });
3040
3038
  }
3041
3039
  const totals = totalsMap.get(baseCurrency);
3042
- const assetSize = asset.platformSize;
3040
+ const assetSize = Number(asset.size || 0);
3043
3041
  totals.totalSize += assetSize;
3044
3042
  totals.positions.push({
3045
3043
  positionId: position.positionId,
@@ -3050,47 +3048,44 @@ class AggregatePositionCalculator {
3050
3048
  }
3051
3049
  return totalsMap;
3052
3050
  }
3053
- /**
3054
- * Extract base currency from asset name (handles "LINK/USD" -> "LINK")
3055
- */
3056
3051
  extractBaseCurrency(assetName) {
3057
3052
  return assetName.split('/')[0] || assetName;
3058
3053
  }
3059
- /**
3060
- * Sync a single position with HyperLiquid data using aggregate totals
3061
- */
3062
3054
  syncPositionWithAggregateData(position, hlPositionsMap, platformTotalsByAsset) {
3063
3055
  const syncResults = [];
3064
3056
  let hasExternalModification = false;
3065
3057
  let allAssetsClosed = true;
3066
- // Separate tracking for long and short sides
3067
3058
  let longAssetStatuses = { total: 0, closed: 0 };
3068
3059
  let shortAssetStatuses = { total: 0, closed: 0 };
3069
- // Process all assets
3070
- const allAssets = [
3071
- ...position.longAssets.map(asset => ({ ...asset, side: exports.PositionSide.LONG })),
3072
- ...position.shortAssets.map(asset => ({ ...asset, side: exports.PositionSide.SHORT }))
3073
- ];
3074
- for (const asset of allAssets) {
3060
+ // Process long assets
3061
+ for (const asset of position.longAssets || []) {
3075
3062
  const baseCurrency = this.extractBaseCurrency(asset.coin);
3076
3063
  const hlPosition = hlPositionsMap.get(baseCurrency);
3077
3064
  const platformTotals = platformTotalsByAsset.get(baseCurrency);
3078
- const syncResult = this.syncAssetWithAggregateData(asset, hlPosition, (platformTotals === null || platformTotals === void 0 ? void 0 : platformTotals.totalSize) || 0);
3065
+ const syncResult = this.syncAssetWithAggregateData({ ...asset, side: PositionSide.LONG }, hlPosition, (platformTotals === null || platformTotals === void 0 ? void 0 : platformTotals.totalSize) || 0);
3079
3066
  syncResults.push(syncResult);
3080
- // Track status by side
3081
- if (asset.side === exports.PositionSide.LONG) {
3082
- longAssetStatuses.total++;
3083
- if (syncResult.actualSize === 0) {
3084
- longAssetStatuses.closed++;
3085
- }
3067
+ longAssetStatuses.total++;
3068
+ if (syncResult.actualSize === 0) {
3069
+ longAssetStatuses.closed++;
3086
3070
  }
3087
- else if (asset.side === exports.PositionSide.SHORT) {
3088
- shortAssetStatuses.total++;
3089
- if (syncResult.actualSize === 0) {
3090
- shortAssetStatuses.closed++;
3091
- }
3071
+ if (syncResult.isExternallyModified) {
3072
+ hasExternalModification = true;
3073
+ }
3074
+ if (syncResult.actualSize !== 0) {
3075
+ allAssetsClosed = false;
3076
+ }
3077
+ }
3078
+ // Process short assets
3079
+ for (const asset of position.shortAssets || []) {
3080
+ const baseCurrency = this.extractBaseCurrency(asset.coin);
3081
+ const hlPosition = hlPositionsMap.get(baseCurrency);
3082
+ const platformTotals = platformTotalsByAsset.get(baseCurrency);
3083
+ const syncResult = this.syncAssetWithAggregateData({ ...asset, side: PositionSide.SHORT }, hlPosition, (platformTotals === null || platformTotals === void 0 ? void 0 : platformTotals.totalSize) || 0);
3084
+ syncResults.push(syncResult);
3085
+ shortAssetStatuses.total++;
3086
+ if (syncResult.actualSize === 0) {
3087
+ shortAssetStatuses.closed++;
3092
3088
  }
3093
- // Update flags
3094
3089
  if (syncResult.isExternallyModified) {
3095
3090
  hasExternalModification = true;
3096
3091
  }
@@ -3098,17 +3093,27 @@ class AggregatePositionCalculator {
3098
3093
  allAssetsClosed = false;
3099
3094
  }
3100
3095
  }
3101
- // Determine sync status
3102
3096
  const syncStatus = this.determineSyncStatus(hasExternalModification, allAssetsClosed, longAssetStatuses, shortAssetStatuses);
3103
- return this.buildUpdatedPosition(position, syncResults, syncStatus);
3097
+ return this.mapPositionToDtoWithSyncData(position, syncResults, syncStatus);
3098
+ }
3099
+ determineSyncStatus(hasExternalModification, allAssetsClosed, longAssetStatuses, shortAssetStatuses) {
3100
+ if (allAssetsClosed) {
3101
+ return 'EXTERNALLY_CLOSED';
3102
+ }
3103
+ const allLongsClosed = longAssetStatuses.total > 0 &&
3104
+ longAssetStatuses.closed === longAssetStatuses.total;
3105
+ const allShortsClosed = shortAssetStatuses.total > 0 &&
3106
+ shortAssetStatuses.closed === shortAssetStatuses.total;
3107
+ if ((allLongsClosed && !allShortsClosed) || (!allLongsClosed && allShortsClosed)) {
3108
+ return 'PAIR_BROKEN';
3109
+ }
3110
+ if (hasExternalModification) {
3111
+ return 'EXTERNALLY_MODIFIED';
3112
+ }
3113
+ return 'SYNCED';
3104
3114
  }
3105
- /**
3106
- * Sync individual asset with aggregate data awareness
3107
- */
3108
3115
  syncAssetWithAggregateData(asset, hlPosition, platformTotal) {
3109
- var _a, _b, _c;
3110
- const platformSize = asset.platformSize;
3111
- // No position on HyperLiquid - asset was closed
3116
+ const platformSize = Number(asset.size || 0);
3112
3117
  if (!hlPosition || !hlPosition.position || !hlPosition.position.szi) {
3113
3118
  return {
3114
3119
  asset,
@@ -3116,27 +3121,23 @@ class AggregatePositionCalculator {
3116
3121
  isExternallyModified: true,
3117
3122
  cumFunding: { allTime: 0, sinceChange: 0, sinceOpen: 0 },
3118
3123
  unrealizedPnl: 0,
3119
- liquidationPrice: 0,
3120
- side: asset.side
3124
+ liquidationPrice: 0
3121
3125
  };
3122
3126
  }
3123
3127
  const hlTotalSize = Math.abs(Number(hlPosition.position.szi || 0));
3124
- // Check if the TOTAL platform size matches HyperLiquid total
3125
3128
  const totalDifference = Math.abs(hlTotalSize - platformTotal);
3126
- const tolerance = platformTotal * 0.001; // 0.1% tolerance
3129
+ const tolerance = platformTotal * 0.001;
3127
3130
  const isExternallyModified = totalDifference > tolerance;
3128
- // Calculate this position's proportional share of the HyperLiquid position
3129
3131
  const proportion = platformTotal > 0 ? platformSize / platformTotal : 0;
3130
3132
  const actualSize = hlTotalSize * proportion;
3131
- // Distribute funding proportionally
3133
+ // Get cumFunding from hlPosition.position.cumFunding
3134
+ const rawCumFunding = hlPosition.position.cumFunding;
3132
3135
  const cumFunding = {
3133
- allTime: Number(((_a = hlPosition.cumFunding) === null || _a === void 0 ? void 0 : _a.allTime) || 0),
3134
- sinceChange: Number(((_b = hlPosition.cumFunding) === null || _b === void 0 ? void 0 : _b.sinceChange) || 0) * proportion,
3135
- sinceOpen: Number(((_c = hlPosition.cumFunding) === null || _c === void 0 ? void 0 : _c.sinceOpen) || 0) * proportion
3136
+ allTime: Number((rawCumFunding === null || rawCumFunding === void 0 ? void 0 : rawCumFunding.allTime) || 0),
3137
+ sinceChange: Number((rawCumFunding === null || rawCumFunding === void 0 ? void 0 : rawCumFunding.sinceChange) || 0) * proportion,
3138
+ sinceOpen: Number((rawCumFunding === null || rawCumFunding === void 0 ? void 0 : rawCumFunding.sinceOpen) || 0) * proportion
3136
3139
  };
3137
- // Distribute PnL proportionally
3138
3140
  const unrealizedPnl = Number(hlPosition.position.unrealizedPnl || 0) * proportion;
3139
- // Liquidation price is the same for all positions of the same asset
3140
3141
  const liquidationPrice = Number(hlPosition.position.liquidationPx || 0);
3141
3142
  return {
3142
3143
  asset,
@@ -3144,46 +3145,27 @@ class AggregatePositionCalculator {
3144
3145
  isExternallyModified,
3145
3146
  cumFunding,
3146
3147
  unrealizedPnl,
3147
- liquidationPrice,
3148
- side: asset.side
3148
+ liquidationPrice
3149
3149
  };
3150
3150
  }
3151
- /**
3152
- * Determine sync status with sophisticated side-aware logic
3153
- */
3154
- determineSyncStatus(hasExternalModification, allAssetsClosed, longAssetStatuses, shortAssetStatuses) {
3155
- // All assets closed externally
3156
- if (allAssetsClosed) {
3157
- return 'EXTERNALLY_CLOSED';
3158
- }
3159
- // Check if pair is broken (one entire side closed)
3160
- const allLongsClosed = longAssetStatuses.total > 0 &&
3161
- longAssetStatuses.closed === longAssetStatuses.total;
3162
- const allShortsClosed = shortAssetStatuses.total > 0 &&
3163
- shortAssetStatuses.closed === shortAssetStatuses.total;
3164
- if ((allLongsClosed && !allShortsClosed) || (!allLongsClosed && allShortsClosed)) {
3165
- return 'PAIR_BROKEN';
3166
- }
3167
- // External modification detected
3168
- if (hasExternalModification) {
3169
- return 'EXTERNALLY_MODIFIED';
3170
- }
3171
- // Everything synced properly
3172
- return 'SYNCED';
3173
- }
3174
- /**
3175
- * Build updated position with synced data
3176
- */
3177
- buildUpdatedPosition(originalPosition, syncResults, syncStatus) {
3178
- const longSyncResults = syncResults.filter(result => result.side === exports.PositionSide.LONG);
3179
- const shortSyncResults = syncResults.filter(result => result.side === exports.PositionSide.SHORT);
3180
- // Calculate position metrics
3151
+ mapPositionToDtoWithSyncData(position, syncResults, syncStatus) {
3152
+ var _a, _b;
3153
+ const longAssets = ((_a = position.longAssets) === null || _a === void 0 ? void 0 : _a.filter(asset => asset)) || [];
3154
+ const shortAssets = ((_b = position.shortAssets) === null || _b === void 0 ? void 0 : _b.filter(asset => asset)) || [];
3155
+ const syncResultsMap = new Map();
3156
+ syncResults.forEach(result => {
3157
+ syncResultsMap.set(`${result.asset.coin}-${result.asset.side}`, result);
3158
+ });
3181
3159
  const currentTotalPositionValue = this.calculateCurrentTotalPositionValue(syncResults);
3182
3160
  const entryTotalPositionValue = this.calculateEntryTotalPositionValue(syncResults);
3183
- const totalMarginUsed = entryTotalPositionValue / originalPosition.leverage;
3161
+ const totalMarginUsed = entryTotalPositionValue / position.leverage;
3184
3162
  return {
3185
- ...originalPosition,
3186
- syncStatus,
3163
+ syncStatus: syncStatus,
3164
+ positionId: position.positionId,
3165
+ address: position.address,
3166
+ leverage: position.leverage,
3167
+ stopLoss: position.stopLoss,
3168
+ takeProfit: position.takeProfit,
3187
3169
  entryRatio: this.calculateEntryRatio(syncResults),
3188
3170
  markRatio: this.calculateMarkRatio(syncResults),
3189
3171
  netFunding: this.calculateNetFundingFromSyncResults(syncResults),
@@ -3191,90 +3173,73 @@ class AggregatePositionCalculator {
3191
3173
  marginUsed: totalMarginUsed,
3192
3174
  unrealizedPnl: this.calculateTotalUnrealizedPnlFromSyncResults(syncResults),
3193
3175
  lastSyncAt: new Date().toISOString(),
3194
- longAssets: longSyncResults.map(result => this.mapSyncResultToAssetDto(result)),
3195
- shortAssets: shortSyncResults.map(result => this.mapSyncResultToAssetDto(result)),
3196
- updatedAt: new Date().toISOString()
3176
+ longAssets: longAssets.map(asset => this.mapAssetToDetailDto(asset, syncResultsMap.get(`${asset.coin}-LONG`))),
3177
+ shortAssets: shortAssets.map(asset => this.mapAssetToDetailDto(asset, syncResultsMap.get(`${asset.coin}-SHORT`))),
3178
+ createdAt: position.createdAt,
3179
+ updatedAt: position.updatedAt
3197
3180
  };
3198
3181
  }
3199
- /**
3200
- * Map sync result to PositionAssetDetailDto
3201
- */
3202
- mapSyncResultToAssetDto(syncResult) {
3203
- const currentPrice = this.getMarketPrice(syncResult.asset.coin);
3204
- const positionValue = syncResult.actualSize * currentPrice;
3205
- const entryValue = syncResult.actualSize * syncResult.asset.entryPrice;
3182
+ mapAssetToDetailDto(asset, syncData) {
3183
+ const currentPrice = this.getMarketPrice(asset.coin);
3184
+ const actualSize = (syncData === null || syncData === void 0 ? void 0 : syncData.actualSize) || Number(asset.size || 0);
3185
+ const positionValue = actualSize * currentPrice;
3186
+ const entryValue = Number(asset.size || 0) * Number(asset.entryPrice || 0);
3206
3187
  return {
3207
- ...syncResult.asset,
3208
- actualSize: syncResult.actualSize,
3209
- isExternallyModified: syncResult.isExternallyModified,
3210
- cumFunding: syncResult.cumFunding,
3188
+ coin: asset.coin,
3189
+ entryPrice: Number(asset.entryPrice || 0),
3190
+ platformSize: Number(asset.size || 0),
3191
+ actualSize: actualSize,
3192
+ isExternallyModified: (syncData === null || syncData === void 0 ? void 0 : syncData.isExternallyModified) || false,
3193
+ cumFunding: (syncData === null || syncData === void 0 ? void 0 : syncData.cumFunding) || {
3194
+ allTime: 0,
3195
+ sinceChange: 0,
3196
+ sinceOpen: 0
3197
+ },
3211
3198
  marginUsed: entryValue,
3212
3199
  positionValue: positionValue,
3213
- unrealizedPnl: syncResult.unrealizedPnl,
3214
- liquidationPrice: syncResult.liquidationPrice
3200
+ unrealizedPnl: (syncData === null || syncData === void 0 ? void 0 : syncData.unrealizedPnl) || 0,
3201
+ liquidationPrice: (syncData === null || syncData === void 0 ? void 0 : syncData.liquidationPrice) || 0
3215
3202
  };
3216
3203
  }
3217
- /**
3218
- * Calculate entry ratio using actual sizes from sync results
3219
- */
3220
3204
  calculateEntryRatio(syncResults) {
3221
- const longResults = syncResults.filter(result => result.side === exports.PositionSide.LONG);
3222
- const shortResults = syncResults.filter(result => result.side === exports.PositionSide.SHORT);
3205
+ var _a, _b;
3206
+ const longResults = syncResults.filter(result => result.asset.side === PositionSide.LONG);
3207
+ const shortResults = syncResults.filter(result => result.asset.side === PositionSide.SHORT);
3223
3208
  if (longResults.length === 0 || shortResults.length === 0)
3224
3209
  return 0;
3225
- const longValue = longResults.reduce((sum, result) => {
3226
- return sum + (result.actualSize * result.asset.entryPrice);
3227
- }, 0);
3228
- const shortValue = shortResults.reduce((sum, result) => {
3229
- return sum + (result.actualSize * result.asset.entryPrice);
3230
- }, 0);
3231
- return shortValue > 0 ? longValue / shortValue : 0;
3210
+ const longEntryPrice = ((_a = longResults[0]) === null || _a === void 0 ? void 0 : _a.asset.entryPrice) ? Number(longResults[0].asset.entryPrice) : 0;
3211
+ const shortEntryPrice = ((_b = shortResults[0]) === null || _b === void 0 ? void 0 : _b.asset.entryPrice) ? Number(shortResults[0].asset.entryPrice) : 0;
3212
+ return shortEntryPrice > 0 ? longEntryPrice / shortEntryPrice : 0;
3232
3213
  }
3233
- /**
3234
- * Calculate mark ratio using actual sizes and current prices
3235
- */
3236
3214
  calculateMarkRatio(syncResults) {
3237
- const longResults = syncResults.filter(result => result.side === exports.PositionSide.LONG);
3238
- const shortResults = syncResults.filter(result => result.side === exports.PositionSide.SHORT);
3215
+ var _a, _b;
3216
+ const longResults = syncResults.filter(result => result.asset.side === PositionSide.LONG);
3217
+ const shortResults = syncResults.filter(result => result.asset.side === PositionSide.SHORT);
3239
3218
  if (longResults.length === 0 || shortResults.length === 0)
3240
3219
  return 0;
3241
- const longValue = longResults.reduce((sum, result) => {
3242
- const currentPrice = this.getMarketPrice(result.asset.coin);
3243
- return sum + (result.actualSize * currentPrice);
3244
- }, 0);
3245
- const shortValue = shortResults.reduce((sum, result) => {
3246
- const currentPrice = this.getMarketPrice(result.asset.coin);
3247
- return sum + (result.actualSize * currentPrice);
3248
- }, 0);
3249
- return shortValue > 0 ? longValue / shortValue : 0;
3220
+ const longMarkPrice = ((_a = longResults[0]) === null || _a === void 0 ? void 0 : _a.asset.coin) ? this.getMarketPrice(longResults[0].asset.coin) : 0;
3221
+ const shortMarkPrice = ((_b = shortResults[0]) === null || _b === void 0 ? void 0 : _b.asset.coin) ? this.getMarketPrice(shortResults[0].asset.coin) : 0;
3222
+ return shortMarkPrice > 0 ? longMarkPrice / shortMarkPrice : 0;
3250
3223
  }
3251
- /**
3252
- * Calculate net funding from sync results
3253
- */
3254
3224
  calculateNetFundingFromSyncResults(syncResults) {
3255
- return syncResults.reduce((sum, result) => sum + result.cumFunding.sinceOpen, 0);
3225
+ const netFunding = syncResults.reduce((sum, result) => {
3226
+ const funding = result.cumFunding.sinceOpen;
3227
+ return sum + funding;
3228
+ }, 0);
3229
+ return netFunding;
3256
3230
  }
3257
- /**
3258
- * Calculate total unrealized PnL from sync results
3259
- */
3260
3231
  calculateTotalUnrealizedPnlFromSyncResults(syncResults) {
3261
3232
  return syncResults.reduce((sum, result) => sum + result.unrealizedPnl, 0);
3262
3233
  }
3263
- /**
3264
- * Calculate current total position value using market prices
3265
- */
3266
3234
  calculateCurrentTotalPositionValue(syncResults) {
3267
3235
  return syncResults.reduce((sum, result) => {
3268
3236
  const currentPrice = this.getMarketPrice(result.asset.coin);
3269
3237
  return sum + (result.actualSize * currentPrice);
3270
3238
  }, 0);
3271
3239
  }
3272
- /**
3273
- * Calculate entry total position value using entry prices
3274
- */
3275
3240
  calculateEntryTotalPositionValue(syncResults) {
3276
3241
  return syncResults.reduce((sum, result) => {
3277
- return sum + (result.actualSize * result.asset.entryPrice);
3242
+ return sum + (Number(result.asset.size || 0) * Number(result.asset.entryPrice || 0));
3278
3243
  }, 0);
3279
3244
  }
3280
3245
  }
@@ -3284,32 +3249,18 @@ class AggregatePositionCalculator {
3284
3249
  */
3285
3250
  const useCalculatedOpenPositions = (platformPositions, webData2, allMids) => {
3286
3251
  const calculatedPositions = require$$0.useMemo(() => {
3287
- var _a, _b;
3288
3252
  // Return null if we don't have platform positions yet
3289
3253
  if (!platformPositions) {
3290
- console.log('[useCalculatedOpenPositions] No platform positions available');
3291
3254
  return null;
3292
3255
  }
3293
- // If we don't have real-time data yet, return platform positions as-is
3256
+ // If we don't have real-time data yet, we can't calculate properly, return null
3294
3257
  if (!webData2 || !allMids) {
3295
- console.log('[useCalculatedOpenPositions] Missing real-time data, returning platform positions');
3296
- return platformPositions;
3297
- }
3298
- console.log('[useCalculatedOpenPositions] Calculating positions with real-time data', {
3299
- platformPositionsCount: platformPositions.length,
3300
- hasWebData2: !!webData2,
3301
- hasAllMids: !!allMids,
3302
- hyperliquidPositionsCount: ((_b = (_a = webData2.clearinghouseState) === null || _a === void 0 ? void 0 : _a.assetPositions) === null || _b === void 0 ? void 0 : _b.length) || 0,
3303
- availableMids: Object.keys(allMids.mids || {}).length
3304
- });
3305
- // Create calculator and compute positions
3306
- const calculator = new AggregatePositionCalculator(webData2, allMids);
3307
- const calculated = calculator.calculateOpenPositions(platformPositions);
3308
- console.log('[useCalculatedOpenPositions] Calculation completed', {
3309
- inputCount: platformPositions.length,
3310
- outputCount: calculated.length
3311
- });
3312
- return calculated;
3258
+ return null;
3259
+ }
3260
+ // Create processor and compute positions
3261
+ const processor = new PositionProcessor(webData2, allMids);
3262
+ const processed = processor.execute(platformPositions);
3263
+ return processed;
3313
3264
  }, [platformPositions, webData2, allMids]);
3314
3265
  return calculatedPositions;
3315
3266
  };
@@ -3328,19 +3279,11 @@ class AccountSummaryCalculator {
3328
3279
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
3329
3280
  // If we don't have webData2, return platform data as-is
3330
3281
  if (!((_a = this.webData2) === null || _a === void 0 ? void 0 : _a.clearinghouseState)) {
3331
- console.log('[AccountSummaryCalculator] No webData2 clearinghouseState available, returning platform data');
3332
3282
  return platformAccountSummary;
3333
3283
  }
3334
- console.log('[AccountSummaryCalculator] Calculating account summary with real-time data', {
3335
- hasPlatformSummary: !!platformAccountSummary,
3336
- hasOpenOrders: !!platformOpenOrders,
3337
- openOrdersCount: (platformOpenOrders === null || platformOpenOrders === void 0 ? void 0 : platformOpenOrders.length) || 0,
3338
- hasAgentWallet: !!agentWalletAddress
3339
- });
3340
3284
  const clearinghouseState = this.webData2.clearinghouseState;
3341
3285
  // Calculate total limit order value from platform orders
3342
3286
  const totalLimitOrderValue = this.calculateTotalLimitOrderValue(platformOpenOrders || []);
3343
- console.log('[AccountSummaryCalculator] Total limit order value:', totalLimitOrderValue);
3344
3287
  // Use real-time data from webData2 clearinghouseState
3345
3288
  const withdrawableAmount = parseFloat(clearinghouseState.withdrawable || '0');
3346
3289
  const adjustedWithdrawable = Math.max(0, withdrawableAmount - totalLimitOrderValue);
@@ -3367,12 +3310,6 @@ class AccountSummaryCalculator {
3367
3310
  status: agentWalletStatus || ((_l = platformAccountSummary === null || platformAccountSummary === void 0 ? void 0 : platformAccountSummary.agentWallet) === null || _l === void 0 ? void 0 : _l.status) || 'UNKNOWN'
3368
3311
  }
3369
3312
  };
3370
- console.log('[AccountSummaryCalculator] Calculated account summary:', {
3371
- accountValue: accountSummary.balanceSummary.crossMarginSummary.accountValue,
3372
- withdrawable: accountSummary.balanceSummary.withdrawable,
3373
- totalMarginUsed: accountSummary.balanceSummary.crossMarginSummary.totalMarginUsed,
3374
- agentWalletAddress: accountSummary.agentWallet.address
3375
- });
3376
3313
  return accountSummary;
3377
3314
  }
3378
3315
  /**
@@ -3385,11 +3322,6 @@ class AccountSummaryCalculator {
3385
3322
  const totalValue = openOrders
3386
3323
  .filter(order => order.status === 'OPEN' || order.status === 'PROCESSING')
3387
3324
  .reduce((sum, order) => sum + order.usdValue, 0);
3388
- console.log('[AccountSummaryCalculator] Calculated limit order value:', {
3389
- totalOrders: openOrders.length,
3390
- openOrders: openOrders.filter(order => order.status === 'OPEN' || order.status === 'PROCESSING').length,
3391
- totalValue
3392
- });
3393
3325
  return totalValue;
3394
3326
  }
3395
3327
  /**
@@ -3413,52 +3345,41 @@ class AccountSummaryCalculator {
3413
3345
  */
3414
3346
  const useCalculatedAccountSummary = (platformAccountSummary, platformOpenOrders, webData2, agentWalletAddress, agentWalletStatus) => {
3415
3347
  const calculatedAccountSummary = require$$0.useMemo(() => {
3416
- var _a, _b, _c;
3417
3348
  // Return null if we don't have platform account summary yet
3418
3349
  if (!platformAccountSummary) {
3419
- console.log('[useCalculatedAccountSummary] No platform account summary available');
3420
3350
  return null;
3421
3351
  }
3422
3352
  // If we don't have real-time data yet, return platform summary as-is
3423
3353
  if (!(webData2 === null || webData2 === void 0 ? void 0 : webData2.clearinghouseState)) {
3424
- console.log('[useCalculatedAccountSummary] Missing webData2 clearinghouseState, returning platform summary');
3425
3354
  return platformAccountSummary;
3426
3355
  }
3427
- console.log('[useCalculatedAccountSummary] Calculating account summary with real-time data', {
3428
- hasPlatformSummary: !!platformAccountSummary,
3429
- hasWebData2: !!webData2,
3430
- hasClearinghouseState: !!webData2.clearinghouseState,
3431
- hasOpenOrders: !!platformOpenOrders,
3432
- openOrdersCount: (platformOpenOrders === null || platformOpenOrders === void 0 ? void 0 : platformOpenOrders.length) || 0,
3433
- agentWalletAddress,
3434
- agentWalletStatus
3435
- });
3436
3356
  // Create calculator and compute account summary
3437
3357
  const calculator = new AccountSummaryCalculator(webData2);
3438
3358
  const calculated = calculator.calculateAccountSummary(platformAccountSummary, platformOpenOrders, agentWalletAddress, agentWalletStatus);
3439
- console.log('[useCalculatedAccountSummary] Calculation completed', {
3440
- hadPlatformSummary: !!platformAccountSummary,
3441
- calculatedSummary: !!calculated,
3442
- withdrawable: (_a = calculated === null || calculated === void 0 ? void 0 : calculated.balanceSummary) === null || _a === void 0 ? void 0 : _a.withdrawable,
3443
- 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
3444
- });
3445
3359
  return calculated;
3446
3360
  }, [platformAccountSummary, platformOpenOrders, webData2, agentWalletAddress, agentWalletStatus]);
3447
3361
  return calculatedAccountSummary;
3448
3362
  };
3449
3363
 
3450
3364
  /**
3451
- * Hook to access trade histories
3365
+ * Hook to access trade histories with loading state
3452
3366
  */
3453
3367
  const useTradeHistories = () => {
3454
3368
  const context = require$$0.useContext(PearHyperliquidContext);
3455
3369
  if (!context) {
3456
3370
  throw new Error('useTradeHistories must be used within a PearHyperliquidProvider');
3457
3371
  }
3458
- return context.data.tradeHistories;
3372
+ const isLoading = require$$0.useMemo(() => {
3373
+ // Loading is true initially and becomes false once we get the first data
3374
+ return context.data.tradeHistories === null && context.isConnected;
3375
+ }, [context.data.tradeHistories, context.isConnected]);
3376
+ return {
3377
+ data: context.data.tradeHistories,
3378
+ isLoading
3379
+ };
3459
3380
  };
3460
3381
  /**
3461
- * Hook to access open positions with real-time calculations
3382
+ * Hook to access open positions with real-time calculations and loading state
3462
3383
  */
3463
3384
  const useOpenPositions = () => {
3464
3385
  const context = require$$0.useContext(PearHyperliquidContext);
@@ -3467,20 +3388,38 @@ const useOpenPositions = () => {
3467
3388
  }
3468
3389
  // Use calculated positions that sync platform data with HyperLiquid real-time data
3469
3390
  const calculatedPositions = useCalculatedOpenPositions(context.data.openPositions, context.webData2, context.allMids);
3470
- return calculatedPositions;
3391
+ const isLoading = require$$0.useMemo(() => {
3392
+ // Loading is true initially and becomes false only when:
3393
+ // 1. WebSocket has open-positions data
3394
+ // 2. webData2 and allMids are ready (required for calculations)
3395
+ // 3. Connection is established
3396
+ return (context.isConnected &&
3397
+ (context.data.openPositions === null || !context.webData2 || !context.allMids));
3398
+ }, [context.data.openPositions, context.webData2, context.allMids, context.isConnected]);
3399
+ return {
3400
+ data: calculatedPositions,
3401
+ isLoading
3402
+ };
3471
3403
  };
3472
3404
  /**
3473
- * Hook to access open orders
3405
+ * Hook to access open orders with loading state
3474
3406
  */
3475
3407
  const useOpenOrders = () => {
3476
3408
  const context = require$$0.useContext(PearHyperliquidContext);
3477
3409
  if (!context) {
3478
3410
  throw new Error('useOpenOrders must be used within a PearHyperliquidProvider');
3479
3411
  }
3480
- return context.data.openOrders;
3412
+ const isLoading = require$$0.useMemo(() => {
3413
+ // Loading is true initially and becomes false once we get the first data
3414
+ return context.data.openOrders === null && context.isConnected;
3415
+ }, [context.data.openOrders, context.isConnected]);
3416
+ return {
3417
+ data: context.data.openOrders,
3418
+ isLoading
3419
+ };
3481
3420
  };
3482
3421
  /**
3483
- * Hook to access account summary with real-time calculations
3422
+ * Hook to access account summary with real-time calculations and loading state
3484
3423
  */
3485
3424
  const useAccountSummary = () => {
3486
3425
  var _a, _b, _c, _d;
@@ -3490,11 +3429,17 @@ const useAccountSummary = () => {
3490
3429
  }
3491
3430
  // Use calculated account summary that syncs platform data with HyperLiquid real-time data
3492
3431
  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);
3493
- return calculatedAccountSummary;
3432
+ const isLoading = require$$0.useMemo(() => {
3433
+ // Loading is true initially and becomes false once we get the first data
3434
+ return context.data.accountSummary === null && context.isConnected;
3435
+ }, [context.data.accountSummary, context.isConnected]);
3436
+ return {
3437
+ data: calculatedAccountSummary,
3438
+ isLoading
3439
+ };
3494
3440
  };
3495
3441
 
3496
3442
  exports.AccountSummaryCalculator = AccountSummaryCalculator;
3497
- exports.AggregatePositionCalculator = AggregatePositionCalculator;
3498
3443
  exports.PearHyperliquidClient = PearHyperliquidClient;
3499
3444
  exports.PearHyperliquidProvider = PearHyperliquidProvider;
3500
3445
  exports.PearMigrationSDK = PearMigrationSDK;