Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions eslint-suppressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1563,9 +1563,6 @@
}
},
"packages/perps-controller/src/PerpsController.ts": {
"@typescript-eslint/no-unused-vars": {
"count": 1
},
"no-restricted-syntax": {
"count": 3
}
Expand Down
12 changes: 12 additions & 0 deletions packages/perps-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `MarketCategory` enum, `MARKET_CATEGORIES` ordered array (7 data-model category pills), and `getMarketCategories` messenger action ([#8892](https://github.com/MetaMask/core/pull/8892))
- Expand `HIP3_ASSET_MARKET_TYPES` with new stock, ETF, pre-IPO, forex, and commodity markets ([#8892](https://github.com/MetaMask/core/pull/8892))
- Add `categories`, `sortBy`, `direction`, `limit`, and `excludeSymbols` optional params to `GetMarketDataWithPricesParams` and `getMarketDataWithPrices()` for post-processing filtering, sorting, and pagination of market data ([#8892](https://github.com/MetaMask/core/pull/8892))
- Export `SortField`, `SortDirection`, and `GetMarketDataWithPricesParams` types from the package root ([#8892](https://github.com/MetaMask/core/pull/8892))

### Changed

- **BREAKING:** Replace `'equity'` with granular `MarketType` values: `'stock'`, `'pre-ipo'`, `'index'`, and `'etf'` ([#8892](https://github.com/MetaMask/core/pull/8892))
- Update any code matching `marketType === 'equity'` to use the specific sub-type.

## [6.3.0]

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,18 @@ export type PerpsControllerGetMarketsAction = {
};

/**
* Get market data with prices (includes price, volume, 24h change)
* Get market data with prices (includes price, volume, 24h change).
* Optionally filter by category, sort, and limit the results.
*
* For standalone mode, bypasses getActiveProvider() to allow market data queries
* without full perps initialization (e.g., for background preloading on app start)
*
* @param params - The operation parameters.
* @param params.standalone - Whether to use standalone mode.
* @param params.categories - Filter to markets matching any of these categories.
* @param params.sortBy - Sort results by this field.
* @param params.direction - Sort direction (default: desc).
* @param params.limit - Maximum number of results to return.
* @returns A promise that resolves to the market data.
*/
export type PerpsControllerGetMarketDataWithPricesAction = {
Expand Down Expand Up @@ -574,6 +579,18 @@ export type PerpsControllerGetCurrentNetworkAction = {
handler: PerpsController['getCurrentNetwork'];
};

/**
* Get the ordered list of all market categories for HIP-3 markets.
* Returns a stable, explicitly ordered array so the UI can render
* category filter tabs without deriving order from config insertion.
*
* @returns Ordered array of {@link MarketTypeFilter} values. Does not include the 'all' or 'new' sentinels — those are separate UI controls.
*/
export type PerpsControllerGetMarketCategoriesAction = {
type: `PerpsController:getMarketCategories`;
handler: PerpsController['getMarketCategories'];
};

/**
* Get the current WebSocket connection state from the active provider.
* Used by the UI to monitor connection health and show notifications.
Expand Down Expand Up @@ -1050,6 +1067,7 @@ export type PerpsControllerMethodActions =
| PerpsControllerToggleTestnetAction
| PerpsControllerSwitchProviderAction
| PerpsControllerGetCurrentNetworkAction
| PerpsControllerGetMarketCategoriesAction
| PerpsControllerGetWebSocketConnectionStateAction
| PerpsControllerSubscribeToConnectionStateAction
| PerpsControllerReconnectAction
Expand Down
43 changes: 35 additions & 8 deletions packages/perps-controller/src/PerpsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
PERPS_CONSTANTS,
MARKET_SORTING_CONFIG,
PROVIDER_CONFIG,
PERPS_DISK_CACHE_MARKETS,
PERPS_DISK_CACHE_USER_DATA,
buildProviderCacheKey,
MAX_SLIPPAGE_BOUNDS,
Expand All @@ -47,6 +46,7 @@ import {
PerpsTraceNames,
PerpsTraceOperations,
isVersionGatedFeatureFlag,
MARKET_CATEGORIES,
// Platform dependencies interface for core migration (bundles all platform-specific deps)
} from './types';
import type {
Expand All @@ -68,6 +68,7 @@ import type {
GetAccountStateParams,
GetAvailableDexsParams,
GetFundingParams,
GetMarketDataWithPricesParams,
GetMarketsParams,
GetOrderFillsParams,
GetOrdersParams,
Expand Down Expand Up @@ -110,8 +111,10 @@ import type {
PerpsRemoteFeatureFlagState,
PerpsTransactionParams,
PerpsAddTransactionOptions,
MarketTypeFilter,
MYXCredentials,
} from './types';
import type { SortDirection } from './types';
import type {
PerpsControllerAllowedActions,
PerpsControllerAllowedEvents,
Expand All @@ -128,7 +131,6 @@ import {
persistMarketEntriesToDisk,
persistUserEntriesToDisk,
} from './utils/perpsDiskPersistence';
import type { SortDirection } from './utils/sortMarkets';
import { wait } from './utils/wait';

/** Derived type for logger options from PerpsLogger interface */
Expand Down Expand Up @@ -723,6 +725,7 @@ const MESSENGER_EXPOSED_METHODS = [
'getCurrentNetwork',
'getFunding',
'getHistoricalPortfolio',
'getMarketCategories',
'getMarketDataWithPrices',
'getMarketFilterPreferences',
'getMarkets',
Expand Down Expand Up @@ -2933,28 +2936,41 @@ export class PerpsController extends BaseController<
}

/**
* Get market data with prices (includes price, volume, 24h change)
* Get market data with prices (includes price, volume, 24h change).
* Optionally filter by category, sort, and limit the results.
*
* For standalone mode, bypasses getActiveProvider() to allow market data queries
* without full perps initialization (e.g., for background preloading on app start)
*
* @param params - The operation parameters.
* @param params.standalone - Whether to use standalone mode.
* @param params.categories - Filter to markets matching any of these categories.
* @param params.sortBy - Sort results by this field.
* @param params.direction - Sort direction (default: desc).
* @param params.limit - Maximum number of results to return.
* @returns A promise that resolves to the market data.
*/
async getMarketDataWithPrices(params?: {
standalone?: boolean;
}): Promise<PerpsMarketData[]> {
async getMarketDataWithPrices(
params?: GetMarketDataWithPricesParams,
): Promise<PerpsMarketData[]> {
if (params?.standalone) {
// Use activeProviderInstance if available (respects provider abstraction)
// Fallback to cached standalone provider for pre-initialization discovery
const provider =
this.activeProviderInstance ?? this.#getOrCreateStandaloneProvider();
return provider.getMarketDataWithPrices();
return this.#marketDataService.getMarketDataWithPrices({
provider,
params,
context: this.#createServiceContext('getMarketDataWithPrices'),
});
}

const provider = this.getActiveProvider();
return provider.getMarketDataWithPrices();
return this.#marketDataService.getMarketDataWithPrices({
provider,
params,
context: this.#createServiceContext('getMarketDataWithPrices'),
});
}

// ============================================================================
Expand Down Expand Up @@ -3960,6 +3976,17 @@ export class PerpsController extends BaseController<
return this.state.isTestnet ? 'testnet' : 'mainnet';
}

/**
* Get the ordered list of all market categories for HIP-3 markets.
* Returns a stable, explicitly ordered array so the UI can render
* category filter tabs without deriving order from config insertion.
*
* @returns Ordered array of {@link MarketTypeFilter} values. Does not include the 'all' or 'new' sentinels — those are separate UI controls.
*/
getMarketCategories(): MarketTypeFilter[] {
return MARKET_CATEGORIES;
}

/**
* Get the current WebSocket connection state from the active provider.
* Used by the UI to monitor connection health and show notifications.
Expand Down
158 changes: 94 additions & 64 deletions packages/perps-controller/src/constants/hyperLiquidConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { CaipAssetId, CaipChainId, Hex } from '@metamask/utils';

import { MarketCategory } from '../types';
import type { MarketType } from '../types';
import type {
HyperLiquidNetwork,
HyperLiquidEndpoints,
Expand Down Expand Up @@ -292,79 +294,107 @@ export const SPOT_ASSET_ID_OFFSET = 10000;
* Maps asset symbols (e.g., "xyz:TSLA") to their market type for badge display.
*
* Market type determines the badge shown in the UI:
* - 'equity': STOCK badge (stocks like TSLA, NVDA)
* - 'commodity': COMMODITY badge (commodities like GOLD)
* - 'forex': FOREX badge (forex pairs)
* - undefined: No badge for crypto or unmapped assets
* - 'stock': Individual stocks (TSLA, NVDA, AAPL, etc.)
* - 'pre-ipo': Pre-IPO assets not yet publicly listed
* - 'index': Market indices (SP500, JP225, VIX, etc.)
* - 'etf': Exchange-traded funds (EWY, EWJ, USAR, etc.)
* - 'commodity': Commodities (GOLD, SILVER, CL, etc.)
* - 'forex': Forex pairs (EUR, JPY, DXY)
* - 'crypto': Explicitly categorized crypto assets
* - undefined: No badge for unmapped assets
*
* Format: 'dex:SYMBOL' → MarketType
* This allows flexible per-asset classification.
* Assets not listed here will have no market type (undefined).
*/
export const HIP3_ASSET_MARKET_TYPES: Record<
string,
'equity' | 'commodity' | 'forex' | 'crypto'
> = {
// xyz DEX - Equities
'xyz:TSLA': 'equity',
'xyz:NVDA': 'equity',
'xyz:XYZ100': 'equity',
'xyz:INTC': 'equity',
'xyz:MU': 'equity',
'xyz:CRCL': 'equity',
'xyz:HOOD': 'equity',
'xyz:SNDK': 'equity',
'xyz:GOOGL': 'equity',
'xyz:COIN': 'equity',
'xyz:ORCL': 'equity',
'xyz:AMZN': 'equity',
'xyz:PLTR': 'equity',
'xyz:AAPL': 'equity',
'xyz:META': 'equity',
'xyz:AMD': 'equity',
'xyz:MSFT': 'equity',
'xyz:BABA': 'equity',
'xyz:RIVN': 'equity',
'xyz:NFLX': 'equity',
'xyz:COST': 'equity',
'xyz:LLY': 'equity',
'xyz:TSM': 'equity',
'xyz:SKHX': 'equity',
'xyz:MSTR': 'equity',
'xyz:CRWV': 'equity',
'xyz:SMSN': 'equity',

'xyz:GME': 'equity',
'xyz:SOFTBANK': 'equity',
'xyz:HYUNDAI': 'equity',
'xyz:KIOXIA': 'equity',
'xyz:HIMS': 'equity',
'xyz:EWY': 'equity',
'xyz:EWJ': 'equity',
'xyz:SP500': 'equity',
'xyz:JP225': 'equity',
'xyz:KR200': 'equity',
'xyz:VIX': 'equity',
'xyz:USAR': 'equity',
export const HIP3_ASSET_MARKET_TYPES: Record<string, MarketType> = {
// xyz DEX - Stocks (US)
'xyz:TSLA': MarketCategory.Stock,
'xyz:NVDA': MarketCategory.Stock,
'xyz:INTC': MarketCategory.Stock,
'xyz:MU': MarketCategory.Stock,
'xyz:CRCL': MarketCategory.Stock,
'xyz:HOOD': MarketCategory.Stock,
'xyz:SNDK': MarketCategory.Stock,
'xyz:GOOGL': MarketCategory.Stock,
'xyz:COIN': MarketCategory.Stock,
'xyz:ORCL': MarketCategory.Stock,
'xyz:AMZN': MarketCategory.Stock,
'xyz:PLTR': MarketCategory.Stock,
'xyz:AAPL': MarketCategory.Stock,
'xyz:META': MarketCategory.Stock,
'xyz:AMD': MarketCategory.Stock,
'xyz:MSFT': MarketCategory.Stock,
'xyz:BABA': MarketCategory.Stock,
'xyz:RIVN': MarketCategory.Stock,
'xyz:NFLX': MarketCategory.Stock,
'xyz:COST': MarketCategory.Stock,
'xyz:LLY': MarketCategory.Stock,
'xyz:TSM': MarketCategory.Stock,
'xyz:MSTR': MarketCategory.Stock,
'xyz:CRWV': MarketCategory.Stock,
'xyz:GME': MarketCategory.Stock,
'xyz:HIMS': MarketCategory.Stock,
'xyz:USAR': MarketCategory.Stock,
'xyz:DKNG': MarketCategory.Stock,
'xyz:BIRD': MarketCategory.Stock,
'xyz:RKLB': MarketCategory.Stock,
'xyz:MRVL': MarketCategory.Stock,
'xyz:ZM': MarketCategory.Stock,
'xyz:EBAY': MarketCategory.Stock,
'xyz:CBRS': MarketCategory.Stock,
'xyz:PURRDAT': MarketCategory.Stock,
'xyz:ARM': MarketCategory.Stock,
'xyz:BX': MarketCategory.Stock,
'xyz:LITE': MarketCategory.Stock,

// xyz DEX - Stocks (Korea)
'xyz:SKHX': MarketCategory.Stock,
'xyz:SMSN': MarketCategory.Stock,
'xyz:HYUNDAI': MarketCategory.Stock,

// xyz DEX - Stocks (Japan)
'xyz:SOFTBANK': MarketCategory.Stock,
'xyz:KIOXIA': MarketCategory.Stock,

// xyz DEX - Pre-IPO
'xyz:SPCX': MarketCategory.PreIpo,

// xyz DEX - Indices
'xyz:SP500': MarketCategory.Index,
'xyz:XYZ100': MarketCategory.Index,
'xyz:JP225': MarketCategory.Index,
'xyz:KR200': MarketCategory.Index,
'xyz:VIX': MarketCategory.Index,

// xyz DEX - ETFs
'xyz:EWY': MarketCategory.Etf,
'xyz:EWJ': MarketCategory.Etf,
'xyz:EWT': MarketCategory.Etf,
'xyz:EWZ': MarketCategory.Etf,
'xyz:URNM': MarketCategory.Etf,
'xyz:DRAM': MarketCategory.Etf,
'xyz:XLE': MarketCategory.Etf,

// xyz DEX - Commodities
'xyz:GOLD': 'commodity',
'xyz:SILVER': 'commodity',
'xyz:CL': 'commodity',
'xyz:COPPER': 'commodity',
'xyz:ALUMINIUM': 'commodity',
'xyz:URANIUM': 'commodity',
'xyz:URNM': 'commodity',
'xyz:NATGAS': 'commodity',
'xyz:PLATINUM': 'commodity',
'xyz:PALLADIUM': 'commodity',
'xyz:BRENTOIL': 'commodity',
'xyz:GOLD': MarketCategory.Commodity,
'xyz:SILVER': MarketCategory.Commodity,
'xyz:CL': MarketCategory.Commodity,
'xyz:WTIOIL': MarketCategory.Commodity,
'xyz:COPPER': MarketCategory.Commodity,
'xyz:ALUMINIUM': MarketCategory.Commodity,
'xyz:URANIUM': MarketCategory.Commodity,
'xyz:NATGAS': MarketCategory.Commodity,
'xyz:PLATINUM': MarketCategory.Commodity,
'xyz:PALLADIUM': MarketCategory.Commodity,
'xyz:BRENTOIL': MarketCategory.Commodity,

// xyz DEX - Forex
'xyz:EUR': 'forex',
'xyz:JPY': 'forex',
'xyz:DXY': 'forex',
} as const;
'xyz:EUR': MarketCategory.Forex,
'xyz:JPY': MarketCategory.Forex,
'xyz:GBP': MarketCategory.Forex,
'xyz:DXY': MarketCategory.Forex,
};

/**
* Testnet-specific HIP-3 DEX configuration
Expand Down
Loading
Loading