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