---
name: architecture
domain: perps
description: Perps architecture overview: layers, hooks, components, data flow
---

# Perps Architecture

## Overview

The Perps feature enables perpetual futures trading in MetaMask Mobile. This document provides a high-level architectural overview of the codebase structure, key patterns, and references to detailed documentation.

**Locations**:

- **Controller**: `app/controllers/perps/` — business logic, providers, services, types (portable, no mobile-specific imports)
- **UI**: `app/components/UI/Perps/` — React components, hooks, views, contexts

## Quick Navigation

- **[Connection Architecture](./perps-connection-architecture.md)** - Connection lifecycle, reconnection logic, WebSocket management
- **[Screen Documentation](./perps-screens.md)** - Detailed view documentation
- **[Sentry Integration](./perps-sentry-reference.md)** - Error tracking and monitoring
- **[MetaMetrics Events](./perps-metametrics-reference.md)** - Analytics events
- **[Protocol Documentation](./hyperliquid/)** - HyperLiquid protocol specifics

## Layer Architecture

The Perps system uses a layered architecture where each layer has clear responsibilities:

```mermaid
graph TD
    UI[UI Components] -->|consume| Hooks[React Hooks]
    Hooks -->|subscribe to| Streams[Stream Manager]
    Streams -->|coordinate with| Connection[Connection Manager]
    Connection -->|orchestrates| Controller[Perps Controller]
    Controller -->|manages| Provider[Protocol Provider]
    Provider -->|communicates with| Protocol[HyperLiquid API]

    Controller -->|stores data in| Redux[Redux State]
    Hooks -->|read from| Redux

    style Streams fill:#e1f5ff
    style Connection fill:#e1f5ff
```

### Layer Responsibilities

| Layer                  | Purpose                                           | Examples                                           |
| ---------------------- | ------------------------------------------------- | -------------------------------------------------- |
| **UI Components**      | Presentational components, user interactions      | PerpsOrderView, PerpsMarketList, PerpsPositionCard |
| **React Hooks**        | Data access, business logic, state management     | usePerpsTrading, usePerpsMarkets, useLivePrices    |
| **Stream Manager**     | WebSocket subscription management, real-time data | PerpsStreamManager, component-level throttling     |
| **Connection Manager** | Connection lifecycle, reconnection orchestration  | PerpsConnectionManager (singleton)                 |
| **Perps Controller**   | Business logic, provider management, Redux state  | PerpsController (Redux controller)                 |
| **Protocol Provider**  | Exchange-specific API implementation              | HyperLiquidProvider (REST + WebSocket)             |

**See [perps-connection-architecture.md](./perps-connection-architecture.md) for detailed connection flow.**

## Directory Structure

### Controller (`app/controllers/perps/`)

The controller is isolated from mobile-specific code and published as `@metamask/perps-controller`.
See [ADR-042](https://github.com/MetaMask/core/blob/main/docs/adr/ADR-042-perps-controller-location.md) for the architectural decision.

```
app/controllers/perps/
├── PerpsController.ts      - Main controller (state, lifecycle, provider mgmt)
├── index.ts                - Package entry point
├── perpsErrorCodes.ts      - Error code definitions
├── selectors.ts            - Redux state selectors
├── providers/              - Protocol-specific implementations
│   ├── HyperLiquidProvider.ts
│   ├── MYXProvider.ts
│   └── AggregatedPerpsProvider.ts
├── services/               - Business logic services
│   ├── AccountService.ts
│   ├── TradingService.ts
│   ├── MarketDataService.ts
│   ├── EligibilityService.ts
│   ├── DepositService.ts
│   ├── DataLakeService.ts
│   ├── RewardsIntegrationService.ts
│   ├── FeatureFlagConfigurationService.ts
│   ├── HyperLiquidClientService.ts
│   ├── HyperLiquidSubscriptionService.ts
│   ├── HyperLiquidWalletService.ts
│   ├── MYXClientService.ts
│   ├── TradingReadinessCache.ts
│   └── ServiceContext.ts
├── routing/                - Provider routing logic
├── aggregation/            - Multi-provider aggregation
├── types/                  - TypeScript type definitions
├── constants/              - Configuration values
└── utils/                  - Pure utility functions
```

### UI (`app/components/UI/Perps/`)

```
app/components/UI/Perps/
├── components/       - Reusable UI components
├── Views/           - Main screen-level components
├── hooks/           - React hooks for data access and logic
│   └── stream/      - WebSocket subscription hooks (real-time data)
├── providers/       - React context providers
├── selectors/       - Redux selectors by domain
├── contexts/        - React contexts
├── styles/          - Shared style utilities
├── Debug/           - Developer tools
├── animations/      - Rive animation files
└── __mocks__/       - Test mocks and fixtures
```

### Components

Reusable UI components organized by feature:

- **Display Components**: LivePriceDisplay, PerpsAmountDisplay, PerpsBadge, PerpsProgressBar, PerpsLoader
- **Form Components**: PerpsSlider, PerpsOrderTypeBottomSheet, PerpsLeverageBottomSheet, PerpsLimitPriceBottomSheet
- **Card Components**: PerpsCard, PerpsPositionCard, PerpsOpenOrderCard, PerpsMarketStatisticsCard
- **List Components**: PerpsMarketList, PerpsRecentActivityList, PerpsWatchlistMarkets
- **Modal Components**: PerpsCancelAllOrdersModal, PerpsCloseAllPositionsModal, PerpsGTMModal
- **Header Components**: PerpsHomeHeader, PerpsMarketHeader, PerpsOrderHeader, PerpsTabControlBar
- **Navigation**: PerpsNavigationCard, PerpsMarketTabs
- **Tooltips**: PerpsBottomSheetTooltip (with content registry), PerpsNotificationTooltip
- **Charts**: TradingViewChart, PerpsCandlestickChartIntervalSelector, FundingCountdown
- **Developer Tools**: PerpsDeveloperOptionsSection

### Views

Main screen-level components representing full pages:

- **PerpsTabView** - Main tab container with navigation
- **PerpsHomeView** - Landing/dashboard screen
- **PerpsMarketListView** - Market browser with search/filters
- **PerpsMarketDetailsView** - Individual market with chart
- **PerpsOrderView** - Order entry form
- **PerpsPositionsView** - Active positions list
- **PerpsClosePositionView** - Single position close flow
- **PerpsCloseAllPositionsView** - Close all positions flow
- **PerpsCancelAllOrdersView** - Cancel all orders flow
- **PerpsTPSLView** - Take profit/stop loss management
- **PerpsTransactionsView** - Transaction history
- **PerpsWithdrawView** - Withdrawal flow
- **PerpsHeroCardView** - Hero/banner cards
- **PerpsEmptyState** - Empty state screens
- **PerpsRedirect** - Routing/redirect logic
- **HIP3DebugView** - Developer debug interface

**See [perps-screens.md](./perps-screens.md) for detailed view documentation.**

### Hooks

React hooks organized by category:

#### Controller Access

- `usePerpsTrading` - Trading operations (place/cancel/close)
- `usePerpsDeposit` - Deposit flow
- `usePerpsDepositQuote` - Deposit quotes
- `usePerpsMarkets` - Market data
- `usePerpsNetwork` - Network configuration
- `usePerpsWithdrawQuote` - Withdrawal quotes

#### State Management

- `usePerpsAccount` - Redux account state
- `usePerpsConnection` - Connection provider context
- `usePerpsPositions` - Position list
- `usePerpsNetworkConfig` - Network state
- `usePerpsOpenOrders` - Open orders list

#### Live Data (Stream Architecture)

- `useLivePrices` - Real-time prices with component-level throttling
- `usePerpsLiveAccount` - Account state updates
- `usePerpsLiveFills` - Order fill notifications
- `usePerpsLiveOrders` - Order updates
- `usePerpsLivePositions` - Position updates
- `usePerpsTopOfBook` - Top-of-book data
- `usePerpsPositionData` - Position data aggregation

#### Calculations

- `usePerpsLiquidationPrice` - Liquidation price calculation
- `usePerpsOrderFees` - Fee calculation
- `useMinimumOrderAmount` - Minimum order calculation
- `usePerpsMarketData` - Market-specific data
- `usePerpsMarketStats` - Market statistics
- `usePerpsFunding` - Funding rate data

#### Validation

- `usePerpsOrderValidation` - Order validation (protocol + UI rules)
- `usePerpsClosePositionValidation` - Close validation
- `useWithdrawValidation` - Withdrawal validation

#### Form Management

- `usePerpsOrderForm` - Order form state
- `usePerpsOrderExecution` - Order execution flow
- `usePerpsClosePosition` - Close position flow
- `usePerpsTPSLForm` - TP/SL form management
- `usePerpsTPSLUpdate` - TP/SL updates

#### UI Utilities

- `useColorPulseAnimation` - Price change animations
- `useBalanceComparison` - Balance comparison
- `useHasExistingPosition` - Position existence check
- `useStableArray` - Array reference stability
- `usePerpsNavigation` - Navigation utilities
- `usePerpsToasts` - Toast notifications

#### Assets/Tokens

- `usePerpsAssetsMetadata` - Asset metadata
- `usePerpsPaymentTokens` - Payment tokens
- `useWithdrawTokens` - Withdrawal tokens

#### Monitoring & Tracking

- `usePerpsEventTracking` - Analytics events
- `usePerpsDataMonitor` - Data monitoring
- `usePerpsMeasurement` - Performance measurement
- `usePerpsDepositStatus` - Deposit status tracking
- `usePerpsWithdrawStatus` - Withdrawal status tracking

### Controller (`app/controllers/perps/`)

Business logic and Redux state management. Isolated from mobile-specific code — uses `PerpsPlatformDependencies` for dependency injection of platform-specific services (logging, metrics, feature flags, etc.).

- **PerpsController** (`app/controllers/perps/PerpsController.ts`) - Main controller managing providers, orders, positions, market data
- **HyperLiquidProvider** (`app/controllers/perps/providers/HyperLiquidProvider.ts`) - HyperLiquid protocol implementation
- **MYXProvider** (`app/controllers/perps/providers/MYXProvider.ts`) - MYX protocol implementation
- **AggregatedPerpsProvider** (`app/controllers/perps/providers/AggregatedPerpsProvider.ts`) - Multi-protocol aggregation via `ProviderRouter`
- **Selectors** (`app/controllers/perps/selectors.ts`) - Redux state selectors
- **Error Codes** (`app/controllers/perps/perpsErrorCodes.ts`) - Error code definitions

### Services (`app/controllers/perps/services/`)

Business logic services instantiated with platform dependencies:

- **AccountService** - Account state, balances, withdrawals
- **TradingService** - Order placement, cancellation, position management
- **MarketDataService** - Market info, candles, funding rates
- **EligibilityService** - User eligibility and geo-blocking
- **DepositService** - Deposit flow with transaction confirmation
- **DataLakeService** - Historical data queries
- **RewardsIntegrationService** - Rewards program integration
- **FeatureFlagConfigurationService** - Remote feature flag configuration (HIP-3, geo-blocking)
- **HyperLiquidClientService** - HTTP client for HyperLiquid REST API
- **HyperLiquidSubscriptionService** - WebSocket subscription management
- **HyperLiquidWalletService** - Wallet operations and signing
- **MYXClientService** - HTTP client for MYX protocol
- **TradingReadinessCache** - Cached trading readiness state
- **PerpsConnectionManager** (`app/components/UI/Perps/services/`) - Connection lifecycle orchestration (mobile-specific singleton, stays in UI layer)

### Providers

React context providers:

- **PerpsAlwaysOnProvider** - Top-level always-on lifecycle manager (mounted at Wallet root); single caller of connect/disconnect on the PerpsConnectionManager singleton
- **PerpsConnectionProvider** - Connection state and methods for UI; all instances use `manageLifecycle={false}` — lifecycle is delegated to PerpsAlwaysOnProvider
- **PerpsStreamManager** - WebSocket stream management with caching
- **PerpsOrderContext** - Order form context

### Utils

Pure utility functions organized by domain:

- **Calculations**: orderCalculations, positionCalculations, pnlCalculations
- **Formatting**: formatUtils, amountConversion, textUtils
- **Validation**: hyperLiquidValidation, tpslValidation
- **Transforms**: marketDataTransform, transactionTransforms, arbitrumWithdrawalTransforms
- **Market Utils**: marketUtils, marketHours, sortMarkets
- **Error Handling**: perpsErrorHandler, translatePerpsError
- **Protocol**: hyperLiquidAdapter, hyperLiquidOrderBookProcessor
- **Blockchain**: idUtils, tokenIconUtils

## Key Patterns

### Validation Flow

Protocol validation (provider) → UI validation (hook) → Display errors (component)

```typescript
// Provider validates protocol rules
provider.validateOrder(order) // throws if invalid

// Hook adds UI-specific rules
usePerpsOrderValidation(orderParams) // returns { isValid, errors }

// Component displays errors
{errors.amount && <ErrorMessage>{errors.amount}</ErrorMessage>}
```

### Data Flow

Controller → Redux Store → Hooks → Components

```typescript
// Controller fetches and stores
await controller.getAccountState() // updates Redux

// Hook reads from Redux
const account = usePerpsAccount() // subscribes to Redux

// Component renders
<Text>{account.balance}</Text>
```

### Real-time Updates

WebSocket → Stream Manager → Hooks → Components

```typescript
// Stream Manager maintains single WebSocket connection
streamManager.subscribeToPrices(['BTC', 'ETH'])

// Hook throttles updates at component level
const prices = useLivePrices({
  symbols: ['BTC', 'ETH'],
  throttleMs: 2000, // 2s updates
})

// Component renders with throttled data
<Text>{prices.BTC?.price}</Text>
```

**See [perps-connection-architecture.md](./perps-connection-architecture.md) for WebSocket architecture details.**

### Background Preloading

Market data and user data are preloaded in the background before the user opens Perps, enabling instant rendering of all sections on the home screen.

#### Preload Pipeline

| Step              | Method                                               | What It Does                                                 |
| ----------------- | ---------------------------------------------------- | ------------------------------------------------------------ |
| 1. Trigger        | `startMarketDataPreload()` (`PerpsAlwaysOnProvider`) | Starts immediate fetch + 5-min periodic refresh              |
| 2. Market data    | `performMarketDataPreload()`                         | Fetches market data via standalone REST → `cachedMarketData` |
| 3. User data      | `performUserDataPreload()`                           | Fetches positions, orders, account state → cached fields     |
| 4. Cache guard    | `PRELOAD_GUARD_MS` (30s)                             | Debounce to prevent rapid re-fetches                         |
| 5. Account change | State-change handler                                 | Clears user data cache, re-preloads                          |

#### Cache-Seeded Hook Initialization

Hooks use lazy `useState` initializers to read cached data from the controller, so the first render already has data instead of showing an empty skeleton.

| Utility                      | Purpose                                              |
| ---------------------------- | ---------------------------------------------------- |
| `hasPreloadedData(field)`    | Returns `true` if controller cache field is non-null |
| `getPreloadedData<T>(field)` | Returns cached value or `null`                       |

Cache freshness is managed by the controller's 5-minute preload cycle, not by the hooks — there is no client-side TTL.

#### What the User Sees

| Timing       | Content                                                                              |
| ------------ | ------------------------------------------------------------------------------------ |
| **Instant**  | Market lists, positions, orders, and account balance populated from cached REST data |
| **~1-2s**    | Live WebSocket data replaces cache with real-time updates                            |
| **On error** | `PerpsConnectionErrorView` renders (unchanged behavior)                              |

**See [perps-connection-architecture.md](./perps-connection-architecture.md) for detailed preloading architecture.**

### Form Management

Component input → Hook state → Validation → Controller action

```typescript
// Component captures input
<Input onChangeText={setAmount} />

// Hook manages form state
const { amount, setAmount, errors } = usePerpsOrderForm()

// Hook validates
const validation = usePerpsOrderValidation({ amount, ... })

// Hook executes when valid
if (validation.isValid) {
  await controller.placeOrder(params)
}
```

### Standalone Mode (Lightweight Queries)

For discovery use cases that need perps data without full initialization:

```typescript
// Check if perps market exists for an asset (usePerpsMarketForAsset hook)
const markets = await perpsController.getMarkets({
  symbols: ['ETH'],
  standalone: true,
});

// Query positions for any address without WebSocket, wallet setup, etc.
const positions = await perpsController.getPositions({
  standalone: true,
  userAddress: '0x...',
});

// Check if user has perps funds (for discovery banners)
const accountState = await perpsController.getAccountState({
  standalone: true,
  userAddress: '0x...',
});
```

**Supported methods:** `getMarkets`, `getPositions`, `getAccountState`

**When to use:**

- Spot token detail pages checking for perps market availability (see `usePerpsMarketForAsset`)
- Token detail pages showing perps positions
- Discovery banners checking if user has perps funds
- Portfolio analytics without entering perps context

**How it works:**

1. Bypasses `getActiveProvider()` check (works even when controller is not initialized)
2. Creates standalone HTTP client via `createStandaloneInfoClient` (see `utils/standaloneInfoClient.ts`)
3. No WebSocket, wallet, or account setup required
4. HIP-3 multi-DEX aggregation supported (positions and account state)

**Limitations:**

- No TP/SL data on positions (would require additional API calls)
- No spot balance aggregation on account state
- No real-time updates (HTTP only, no WebSocket)

### Cache Invalidation

Standalone queries use client-side caching for performance (e.g., 30s TTL for positions).
The `PerpsCacheInvalidator` service provides loosely-coupled cache invalidation when
data changes in the perps environment:

**Hook side (consumers):**

```typescript
import { PerpsCacheInvalidator } from '../services/PerpsCacheInvalidator';

// Subscribe to invalidation events
useEffect(() => {
  const unsubPositions = PerpsCacheInvalidator.subscribe('positions', () => {
    clearMyCache();
    refetch();
  });
  const unsubAccount = PerpsCacheInvalidator.subscribe('accountState', () => {
    clearMyCache();
    refetch();
  });
  return () => {
    unsubPositions();
    unsubAccount();
  };
}, []);
```

**Service side (producers):**

```typescript
// After successful position change (TradingService)
PerpsCacheInvalidator.invalidate('positions');
PerpsCacheInvalidator.invalidate('accountState');

// After successful withdrawal (AccountService)
PerpsCacheInvalidator.invalidate('accountState');
```

**Cache types:**

- `positions` - Position data caches (invalidated on order placement, position close)
- `accountState` - Account balance/state caches (invalidated on trades, withdrawals)
- `markets` - Market data caches (rarely changes)

This pattern allows token detail pages to show accurate position status even after
the user closes positions in the perps environment, without polling or WebSocket overhead.

## Stream Architecture

**Single WebSocket connections shared across all components with component-level debouncing.**

### Benefits

- **90% fewer WebSocket connections** - One subscription per data type (not per component)
- **No subscription interference** - Each component controls its own update rate
- **Component-level control** - Different throttle rates for different views
- **Instant first render** - Pre-warmed connections provide cached data immediately
- **Zero parent re-renders** - Updates go directly to subscribers

### How It Works

1. **PerpsConnectionManager** pre-warms critical subscriptions on connection
2. **PerpsStreamManager** maintains single WebSocket subscriptions with reference counting
3. **Stream Hooks** provide component-level throttling:

```typescript
// Order view: stable prices (10s throttle)
const prices = useLivePrices({ symbols: ['BTC'], throttleMs: 10000 });

// Market list: responsive updates (2s throttle)
const prices = useLivePrices({ symbols: allSymbols, throttleMs: 2000 });

// Charts: near real-time (100ms throttle)
const prices = useLivePrices({ symbols: ['BTC'], throttleMs: 100 });
```

4. **Shared cache** ensures instant data availability for all subscribers

**See [perps-connection-architecture.md](./perps-connection-architecture.md) for detailed stream architecture.**

## Quick Reference

| Need           | Use Hook                                     | Use Component             |
| -------------- | -------------------------------------------- | ------------------------- |
| Place order    | `usePerpsTrading` + `usePerpsOrderExecution` | PerpsOrderView            |
| Validate order | `usePerpsOrderValidation`                    | -                         |
| Get prices     | `useLivePrices`                              | LivePriceDisplay          |
| Manage form    | `usePerpsOrderForm`                          | -                         |
| Calculate fees | `usePerpsOrderFees`                          | PerpsFeesDisplay          |
| Check position | `useHasExistingPosition`                     | -                         |
| Close position | `usePerpsClosePosition` + validation         | PerpsClosePositionView    |
| Get account    | `usePerpsAccount`                            | -                         |
| Deposit funds  | `usePerpsDeposit`                            | PerpsMarketBalanceActions |
| Withdraw funds | `usePerpsWithdrawQuote` + validation         | PerpsWithdrawView         |
| Show market    | -                                            | PerpsMarketDetailsView    |
| List markets   | `usePerpsMarkets`                            | PerpsMarketListView       |

## Error Handling

Perps uses a multi-layered error handling approach:

1. **Provider Layer** - Protocol-specific errors, logs to Sentry
2. **Controller Layer** - Business logic errors, updates Redux, logs to Sentry
3. **Manager Layer** - Connection errors, sets local state, logs to DevLogger
4. **Hook Layer** - Exposes errors to UI
5. **Component Layer** - Displays errors to user

**See [perps-sentry-reference.md](./perps-sentry-reference.md) for error tracking details.**

## Analytics

All user interactions are tracked via MetaMetrics events:

- Trading actions (orders, closes, cancels)
- Market interactions (views, searches, filters)
- Connection events (connect, disconnect, errors)
- Deposit/withdrawal flows

**See [perps-metametrics-reference.md](./perps-metametrics-reference.md) for complete event catalog.**

## Development Guidelines

### Adding a New Hook

1. Determine category (Controller Access, State Management, Live Data, etc.)
2. Follow naming convention: `usePerps[Feature][Action]`
3. Keep single responsibility
4. Add comprehensive tests
5. Document in this file

### Adding a New Component

1. Create in appropriate subdirectory under `components/`
2. Include `.styles.ts` file for styles
3. Add tests in `__tests__/` subdirectory
4. Export from component directory's `index.ts`
5. Use existing shared components where possible

### Adding a New View

1. Create in `Views/` directory
2. Follow naming: `Perps[Feature]View`
3. Use hooks for data access (not direct controller calls)
4. Add to navigation in `routes/index.tsx`
5. Document in [perps-screens.md](./perps-screens.md)

### Before Committing

```bash
# Format code
yarn prettier --write 'app/components/UI/Perps/**/*.{ts,tsx}'

# Check for errors
yarn eslint app/components/UI/Perps/**/*.{ts,tsx}

# Run tests
yarn jest app/components/UI/Perps/ --no-coverage
```

## Testing

- **Test Coverage**: ~95% across hooks, components, and utilities
- **Test Location**: Co-located `__tests__/` directories or `.test.ts` files
- **Mock System**: Centralized mocks in `__mocks__/` directory

Key testing utilities:

- `perpsHooksMocks.ts` - Mock hooks
- `perpsComponentMocks.ts` - Mock components
- `providerMocks.ts` - Mock providers
- `streamHooksMocks.ts` - Mock stream hooks

## Code Quality

The codebase maintains high quality standards:

- **Test Coverage**: ~95% across hooks, components, and utilities
- **Architecture**: Tight cohesion with 59% of files used only internally
- **Patterns**: Consistent use of hooks, components, and utilities
- **Documentation**: Comprehensive inline and external documentation

## Protocol Integration

Multi-protocol architecture with provider abstraction:

### HyperLiquid (primary)

- **REST API** - Account queries, order placement, market data
- **WebSocket** - Real-time prices, order fills, position updates
- **Wallet Integration** - Ethereum signing for orders

### MYX (feature-flagged)

- MYX protocol support via `MYXProvider` and `MYXClientService`
- Enabled via `perpsMyxProviderEnabled` remote feature flag with version gating
- When enabled alongside HyperLiquid, uses `AggregatedPerpsProvider` with `ProviderRouter`

### Multi-Protocol Architecture

- **`ProviderRouter`** (`routing/`) - Routes operations to the correct provider based on market
- **`AggregatedPerpsProvider`** - Wraps multiple providers behind the `PerpsProvider` interface
- **`SubscriptionMultiplexer`** - Merges WebSocket subscriptions from multiple providers

**See [hyperliquid/](./hyperliquid/) directory for HyperLiquid-specific documentation.**

## Migration Notes

### HIP-3 Upgrade (Nov 2024)

Major protocol upgrade with webData3 migration:

- Single WebSocket connection for positions + orders
- Improved performance and reliability
- See HIP3DebugView for debugging tools

### Stream Architecture (Oct 2024)

Migrated from per-component subscriptions to shared streams:

- Old: `usePerpsPrices` (deprecated)
- New: `useLivePrices` with component-level throttling
- 90% reduction in WebSocket connections

### Always-On Connection Architecture (Mar 2026)

Migrated from per-section `PerpsConnectionProvider` lifecycle management to a single top-level `PerpsAlwaysOnProvider`:

- **Old**: Multiple `PerpsConnectionProvider` instances in Homepage, PerpsTabView, ActivityView, TrendingView, ExploreSearchScreen, and UrlAutocomplete each called `connect()`/`disconnect()`. Reference-count edge cases caused intermittent bugs (positions not showing, 24h values missing) after long app backgrounding.
- **New**: Single `PerpsAlwaysOnProvider` at `Wallet/index.tsx` owns the entire lifecycle. All `PerpsConnectionProvider` instances use `manageLifecycle={false}` — they provide React context only.
- **Result**: `connectionRefCount` in `PerpsConnectionManager` stays exactly 1; no more reference-count races. Skeleton correctly shows on reconnect via `isConnecting` flag ORed into loading states in `usePerpsHomeData`.

## Additional Resources

- **[Perps Screens](./perps-screens.md)** - Detailed view documentation
- **[Connection Architecture](./perps-connection-architecture.md)** - Connection management deep dive
- **[Sentry Integration](./perps-sentry-reference.md)** - Error tracking
- **[MetaMetrics Events](./perps-metametrics-reference.md)** - Analytics events
- **[HyperLiquid Docs](./hyperliquid/)** - Protocol documentation

## Questions?

For architecture questions or contributions, refer to the specific documentation linked above or consult the team.
