From f4a676d1a492c1618899a525965672c3edcfe1a8 Mon Sep 17 00:00:00 2001 From: Michal Szorad Date: Fri, 12 Jun 2026 10:26:58 +0200 Subject: [PATCH 1/5] feat(perps-controller): add hardcoded market collections registry Add a canonical registry of 183 perps markets with ticker, max leverage, and collection tags (e.g. L1, DeFi, Memecoin). Expose accessor methods on PerpsController and pure utility functions for lookup and filtering. --- .../PerpsController-method-action-types.ts | 47 ++++ .../perps-controller/src/PerpsController.ts | 55 ++++ .../perps-controller/src/constants/index.ts | 1 + .../src/constants/marketCollections.ts | 260 ++++++++++++++++++ packages/perps-controller/src/index.ts | 14 + packages/perps-controller/src/types/index.ts | 51 ++++ .../src/constants/marketCollections.test.ts | 158 +++++++++++ 7 files changed, 586 insertions(+) create mode 100644 packages/perps-controller/src/constants/marketCollections.ts create mode 100644 packages/perps-controller/tests/src/constants/marketCollections.test.ts diff --git a/packages/perps-controller/src/PerpsController-method-action-types.ts b/packages/perps-controller/src/PerpsController-method-action-types.ts index 1351266616..76196a1593 100644 --- a/packages/perps-controller/src/PerpsController-method-action-types.ts +++ b/packages/perps-controller/src/PerpsController-method-action-types.ts @@ -591,6 +591,49 @@ export type PerpsControllerGetMarketCategoriesAction = { handler: PerpsController['getMarketCategories']; }; +/** + * Get the ordered list of all market collection tags. + * Used by the UI to render collection filter pills. + * + * @returns Ordered array of {@link PerpsMarketCollectionTag} values. + */ +export type PerpsControllerGetMarketCollectionsAction = { + type: `PerpsController:getMarketCollections`; + handler: PerpsController['getMarketCollections']; +}; + +/** + * Get the full list of hardcoded perps market definitions. + * + * @returns Array of all {@link PerpsMarketDefinition} entries. + */ +export type PerpsControllerGetMarketDefinitionsAction = { + type: `PerpsController:getMarketDefinitions`; + handler: PerpsController['getMarketDefinitions']; +}; + +/** + * Look up a single market definition by its ticker symbol. + * + * @param ticker - The ticker to look up (e.g. 'BTC', 'ETH'). + * @returns The matching definition, or `undefined` if not found. + */ +export type PerpsControllerGetMarketDefinitionByTickerAction = { + type: `PerpsController:getMarketDefinitionByTicker`; + handler: PerpsController['getMarketDefinitionByTicker']; +}; + +/** + * Return all market definitions that belong to a given collection tag. + * + * @param collection - The collection tag to filter by. + * @returns Array of matching market definitions (may be empty). + */ +export type PerpsControllerGetMarketDefinitionsByCollectionAction = { + type: `PerpsController:getMarketDefinitionsByCollection`; + handler: PerpsController['getMarketDefinitionsByCollection']; +}; + /** * Get the current WebSocket connection state from the active provider. * Used by the UI to monitor connection health and show notifications. @@ -1068,6 +1111,10 @@ export type PerpsControllerMethodActions = | PerpsControllerSwitchProviderAction | PerpsControllerGetCurrentNetworkAction | PerpsControllerGetMarketCategoriesAction + | PerpsControllerGetMarketCollectionsAction + | PerpsControllerGetMarketDefinitionsAction + | PerpsControllerGetMarketDefinitionByTickerAction + | PerpsControllerGetMarketDefinitionsByCollectionAction | PerpsControllerGetWebSocketConnectionStateAction | PerpsControllerSubscribeToConnectionStateAction | PerpsControllerReconnectAction diff --git a/packages/perps-controller/src/PerpsController.ts b/packages/perps-controller/src/PerpsController.ts index 8e57403634..9cc8fef534 100644 --- a/packages/perps-controller/src/PerpsController.ts +++ b/packages/perps-controller/src/PerpsController.ts @@ -18,6 +18,12 @@ import { import { USDC_SYMBOL } from './constants/hyperLiquidConfig'; import { PerpsMeasurementName } from './constants/performanceMetrics'; import type { SortOptionId } from './constants/perpsConfig'; +import { + PERPS_MARKET_COLLECTION_TAGS, + PERPS_MARKET_DEFINITIONS, + getMarketDefinitionByTicker as getMarketDefinitionByTickerUtil, + getMarketDefinitionsByCollection as getMarketDefinitionsByCollectionUtil, +} from './constants/marketCollections'; import { PERPS_CONSTANTS, MARKET_SORTING_CONFIG, @@ -107,6 +113,8 @@ import type { PerpsLogger, PerpsActiveProviderMode, PerpsProviderType, + PerpsMarketCollectionTag, + PerpsMarketDefinition, PerpsSelectedPaymentToken, PerpsRemoteFeatureFlagState, PerpsTransactionParams, @@ -726,7 +734,11 @@ const MESSENGER_EXPOSED_METHODS = [ 'getFunding', 'getHistoricalPortfolio', 'getMarketCategories', + 'getMarketCollections', 'getMarketDataWithPrices', + 'getMarketDefinitionByTicker', + 'getMarketDefinitions', + 'getMarketDefinitionsByCollection', 'getMarketFilterPreferences', 'getMarkets', 'getMaxLeverage', @@ -3987,6 +3999,49 @@ export class PerpsController extends BaseController< return MARKET_CATEGORIES; } + /** + * Get the ordered list of all market collection tags. + * Used by the UI to render collection filter pills. + * + * @returns Ordered array of {@link PerpsMarketCollectionTag} values. + */ + getMarketCollections(): PerpsMarketCollectionTag[] { + return [...PERPS_MARKET_COLLECTION_TAGS]; + } + + /** + * Get the full list of hardcoded perps market definitions. + * + * @returns Array of all {@link PerpsMarketDefinition} entries. + */ + getMarketDefinitions(): PerpsMarketDefinition[] { + return [...PERPS_MARKET_DEFINITIONS]; + } + + /** + * Look up a single market definition by its ticker symbol. + * + * @param ticker - The ticker to look up (e.g. 'BTC', 'ETH'). + * @returns The matching definition, or `undefined` if not found. + */ + getMarketDefinitionByTicker( + ticker: string, + ): PerpsMarketDefinition | undefined { + return getMarketDefinitionByTickerUtil(ticker); + } + + /** + * Return all market definitions that belong to a given collection tag. + * + * @param collection - The collection tag to filter by. + * @returns Array of matching market definitions (may be empty). + */ + getMarketDefinitionsByCollection( + collection: PerpsMarketCollectionTag, + ): PerpsMarketDefinition[] { + return getMarketDefinitionsByCollectionUtil(collection); + } + /** * Get the current WebSocket connection state from the active provider. * Used by the UI to monitor connection health and show notifications. diff --git a/packages/perps-controller/src/constants/index.ts b/packages/perps-controller/src/constants/index.ts index aedcaaec56..7568880f3f 100644 --- a/packages/perps-controller/src/constants/index.ts +++ b/packages/perps-controller/src/constants/index.ts @@ -9,3 +9,4 @@ export * from './perpsConfig'; export * from './transactionsHistoryConfig'; export * from './performanceMetrics'; export * from './myxConfig'; +export * from './marketCollections'; diff --git a/packages/perps-controller/src/constants/marketCollections.ts b/packages/perps-controller/src/constants/marketCollections.ts new file mode 100644 index 0000000000..de9d2a5c3c --- /dev/null +++ b/packages/perps-controller/src/constants/marketCollections.ts @@ -0,0 +1,260 @@ +import type { + PerpsMarketCollectionTag, + PerpsMarketDefinition, +} from '../types'; + +/** + * Ordered list of all market collection tags for UI filter pills. + * The order here determines display order in the consumer UI. + */ +export const PERPS_MARKET_COLLECTION_TAGS: readonly PerpsMarketCollectionTag[] = + [ + 'L1', + 'L2 / Scaling', + 'Bitcoin Ecosystem', + 'Solana Ecosystem', + 'Cosmos Ecosystem', + 'TON Ecosystem', + 'Hyperliquid Ecosystem', + 'Move Ecosystem', + 'Smart Contract Platform', + 'DeFi', + 'Exchange Token', + 'Memecoin', + 'Gaming / NFT', + 'AI / DePIN', + 'Infrastructure', + 'Oracle', + 'Interoperability', + 'Payments', + 'LSD / Liquid Staking', + 'RWA / Stablecoin', + 'ZK / Modular', + 'Privacy', + 'Storage / Data', + 'Store of Value', + 'Metaverse', + 'IoT / Infrastructure', + 'Political', + ] as const; + +/** + * Canonical registry of all supported perps markets. + * Each entry defines the ticker, maximum leverage, and thematic collections. + */ +export const PERPS_MARKET_DEFINITIONS: readonly PerpsMarketDefinition[] = [ + { ticker: 'BTC', maxLeverage: 40, collections: ['L1', 'Bitcoin Ecosystem', 'Store of Value'] }, + { ticker: 'ETH', maxLeverage: 25, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'ATOM', maxLeverage: 5, collections: ['L1', 'Cosmos Ecosystem', 'Interoperability'] }, + { ticker: 'DYDX', maxLeverage: 5, collections: ['DeFi', 'Cosmos Ecosystem', 'Exchange Token'] }, + { ticker: 'SOL', maxLeverage: 20, collections: ['L1', 'Solana Ecosystem'] }, + { ticker: 'AVAX', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'BNB', maxLeverage: 10, collections: ['L1', 'Exchange Token', 'Smart Contract Platform'] }, + { ticker: 'APE', maxLeverage: 5, collections: ['Gaming / NFT'] }, + { ticker: 'OP', maxLeverage: 5, collections: ['L2 / Scaling'] }, + { ticker: 'LTC', maxLeverage: 10, collections: ['L1', 'Bitcoin Ecosystem', 'Payments'] }, + { ticker: 'ARB', maxLeverage: 10, collections: ['L2 / Scaling'] }, + { ticker: 'DOGE', maxLeverage: 10, collections: ['L1', 'Memecoin', 'Payments'] }, + { ticker: 'INJ', maxLeverage: 5, collections: ['L1', 'Cosmos Ecosystem', 'DeFi'] }, + { ticker: 'SUI', maxLeverage: 10, collections: ['L1', 'Move Ecosystem'] }, + { ticker: 'kPEPE', maxLeverage: 10, collections: ['Memecoin'] }, + { ticker: 'CRV', maxLeverage: 10, collections: ['DeFi'] }, + { ticker: 'LDO', maxLeverage: 5, collections: ['DeFi', 'LSD / Liquid Staking'] }, + { ticker: 'LINK', maxLeverage: 10, collections: ['Infrastructure', 'Oracle'] }, + { ticker: 'STX', maxLeverage: 5, collections: ['L2 / Scaling', 'Bitcoin Ecosystem'] }, + { ticker: 'CFX', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'GMX', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, + { ticker: 'SNX', maxLeverage: 3, collections: ['DeFi'] }, + { ticker: 'XRP', maxLeverage: 20, collections: ['L1', 'Payments'] }, + { ticker: 'BCH', maxLeverage: 10, collections: ['L1', 'Bitcoin Ecosystem', 'Payments'] }, + { ticker: 'APT', maxLeverage: 10, collections: ['L1', 'Move Ecosystem'] }, + { ticker: 'AAVE', maxLeverage: 10, collections: ['DeFi'] }, + { ticker: 'COMP', maxLeverage: 5, collections: ['DeFi'] }, + { ticker: 'WLD', maxLeverage: 10, collections: ['AI / DePIN'] }, + { ticker: 'YGG', maxLeverage: 3, collections: ['Gaming / NFT'] }, + { ticker: 'TRX', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'kSHIB', maxLeverage: 10, collections: ['Memecoin'] }, + { ticker: 'UNI', maxLeverage: 10, collections: ['DeFi', 'Exchange Token'] }, + { ticker: 'SEI', maxLeverage: 5, collections: ['L1', 'Cosmos Ecosystem', 'DeFi'] }, + { ticker: 'RUNE', maxLeverage: 5, collections: ['Bitcoin Ecosystem', 'DeFi'] }, + { ticker: 'ZRO', maxLeverage: 5, collections: ['Infrastructure', 'Interoperability'] }, + { ticker: 'DOT', maxLeverage: 10, collections: ['L1', 'Interoperability'] }, + { ticker: 'BANANA', maxLeverage: 3, collections: ['Memecoin', 'DeFi'] }, + { ticker: 'TRB', maxLeverage: 3, collections: ['Infrastructure', 'Oracle'] }, + { ticker: 'FTT', maxLeverage: 3, collections: ['Exchange Token'] }, + { ticker: 'ARK', maxLeverage: 3, collections: ['L1'] }, + { ticker: 'BIGTIME', maxLeverage: 3, collections: ['Gaming / NFT'] }, + { ticker: 'KAS', maxLeverage: 3, collections: ['L1', 'Bitcoin Ecosystem'] }, + { ticker: 'BLUR', maxLeverage: 3, collections: ['Gaming / NFT', 'DeFi'] }, + { ticker: 'TIA', maxLeverage: 5, collections: ['L1', 'ZK / Modular', 'Cosmos Ecosystem'] }, + { ticker: 'BSV', maxLeverage: 3, collections: ['L1', 'Bitcoin Ecosystem'] }, + { ticker: 'ADA', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'TON', maxLeverage: 10, collections: ['L1', 'TON Ecosystem'] }, + { ticker: 'MINA', maxLeverage: 3, collections: ['L1', 'ZK / Modular'] }, + { ticker: 'POLYX', maxLeverage: 3, collections: ['RWA / Stablecoin', 'Infrastructure'] }, + { ticker: 'GAS', maxLeverage: 3, collections: ['Infrastructure'] }, + { ticker: 'PENDLE', maxLeverage: 5, collections: ['DeFi', 'LSD / Liquid Staking'] }, + { ticker: 'FET', maxLeverage: 5, collections: ['AI / DePIN', 'Infrastructure'] }, + { ticker: 'NEAR', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'MEME', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'ORDI', maxLeverage: 3, collections: ['Bitcoin Ecosystem'] }, + { ticker: 'NEO', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'ZEN', maxLeverage: 5, collections: ['L1', 'Privacy'] }, + { ticker: 'FIL', maxLeverage: 5, collections: ['L1', 'Storage / Data'] }, + { ticker: 'PYTH', maxLeverage: 5, collections: ['Infrastructure', 'Oracle', 'Solana Ecosystem'] }, + { ticker: 'SUSHI', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, + { ticker: 'IMX', maxLeverage: 5, collections: ['Gaming / NFT', 'L2 / Scaling'] }, + { ticker: 'kBONK', maxLeverage: 10, collections: ['Memecoin', 'Solana Ecosystem'] }, + { ticker: 'GMT', maxLeverage: 3, collections: ['Gaming / NFT'] }, + { ticker: 'SUPER', maxLeverage: 3, collections: ['Gaming / NFT'] }, + { ticker: 'JUP', maxLeverage: 10, collections: ['DeFi', 'Solana Ecosystem', 'Exchange Token'] }, + { ticker: 'kLUNC', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'RSR', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, + { ticker: 'GALA', maxLeverage: 3, collections: ['Gaming / NFT'] }, + { ticker: 'JTO', maxLeverage: 5, collections: ['DeFi', 'Solana Ecosystem', 'LSD / Liquid Staking'] }, + { ticker: 'ACE', maxLeverage: 3, collections: ['Gaming / NFT'] }, + { ticker: 'WIF', maxLeverage: 5, collections: ['Memecoin', 'Solana Ecosystem'] }, + { ticker: 'CAKE', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, + { ticker: 'PEOPLE', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'ENS', maxLeverage: 5, collections: ['Infrastructure'] }, + { ticker: 'ETC', maxLeverage: 5, collections: ['L1', 'Bitcoin Ecosystem'] }, + { ticker: 'XAI', maxLeverage: 3, collections: ['Gaming / NFT', 'L2 / Scaling'] }, + { ticker: 'MANTA', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular'] }, + { ticker: 'UMA', maxLeverage: 3, collections: ['Infrastructure', 'Oracle', 'DeFi'] }, + { ticker: 'ONDO', maxLeverage: 10, collections: ['RWA / Stablecoin', 'DeFi'] }, + { ticker: 'ALT', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular'] }, + { ticker: 'ZETA', maxLeverage: 3, collections: ['L1', 'Interoperability'] }, + { ticker: 'DYM', maxLeverage: 3, collections: ['L1', 'ZK / Modular'] }, + { ticker: 'W', maxLeverage: 5, collections: ['L1', 'Interoperability'] }, + { ticker: 'STRK', maxLeverage: 5, collections: ['L2 / Scaling', 'ZK / Modular'] }, + { ticker: 'TAO', maxLeverage: 5, collections: ['L1', 'AI / DePIN'] }, + { ticker: 'AR', maxLeverage: 5, collections: ['L1', 'Storage / Data'] }, + { ticker: 'kFLOKI', maxLeverage: 5, collections: ['Memecoin'] }, + { ticker: 'BOME', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, + { ticker: 'ETHFI', maxLeverage: 5, collections: ['DeFi', 'LSD / Liquid Staking'] }, + { ticker: 'ENA', maxLeverage: 10, collections: ['DeFi', 'RWA / Stablecoin'] }, + { ticker: 'MNT', maxLeverage: 5, collections: ['L2 / Scaling', 'Exchange Token'] }, + { ticker: 'TNSR', maxLeverage: 3, collections: ['Gaming / NFT', 'Solana Ecosystem'] }, + { ticker: 'SAGA', maxLeverage: 3, collections: ['L1', 'Gaming / NFT'] }, + { ticker: 'MERL', maxLeverage: 3, collections: ['L2 / Scaling', 'Bitcoin Ecosystem'] }, + { ticker: 'HBAR', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'POPCAT', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, + { ticker: 'EIGEN', maxLeverage: 5, collections: ['Infrastructure', 'LSD / Liquid Staking'] }, + { ticker: 'REZ', maxLeverage: 3, collections: ['DeFi', 'LSD / Liquid Staking'] }, + { ticker: 'NOT', maxLeverage: 3, collections: ['Memecoin', 'TON Ecosystem'] }, + { ticker: 'TURBO', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, + { ticker: 'BRETT', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'IO', maxLeverage: 3, collections: ['AI / DePIN'] }, + { ticker: 'ZK', maxLeverage: 5, collections: ['L2 / Scaling', 'ZK / Modular'] }, + { ticker: 'BLAST', maxLeverage: 3, collections: ['L2 / Scaling', 'DeFi'] }, + { ticker: 'RENDER', maxLeverage: 5, collections: ['AI / DePIN'] }, + { ticker: 'POL', maxLeverage: 5, collections: ['L2 / Scaling'] }, + { ticker: 'CELO', maxLeverage: 3, collections: ['L1', 'Payments'] }, + { ticker: 'HMSTR', maxLeverage: 3, collections: ['Memecoin', 'TON Ecosystem'] }, + { ticker: 'kNEIRO', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'GOAT', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, + { ticker: 'MOODENG', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'GRASS', maxLeverage: 3, collections: ['AI / DePIN'] }, + { ticker: 'PURR', maxLeverage: 3, collections: ['Memecoin', 'Hyperliquid Ecosystem'] }, + { ticker: 'PNUT', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, + { ticker: 'XLM', maxLeverage: 5, collections: ['L1', 'Payments'] }, + { ticker: 'CHILLGUY', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, + { ticker: 'SAND', maxLeverage: 5, collections: ['Gaming / NFT', 'Metaverse'] }, + { ticker: 'IOTA', maxLeverage: 3, collections: ['L1', 'IoT / Infrastructure'] }, + { ticker: 'ALGO', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'HYPE', maxLeverage: 10, collections: ['L1', 'Exchange Token', 'Hyperliquid Ecosystem'] }, + { ticker: 'ME', maxLeverage: 3, collections: ['Gaming / NFT', 'Solana Ecosystem'] }, + { ticker: 'MOVE', maxLeverage: 3, collections: ['L1', 'Move Ecosystem'] }, + { ticker: 'VIRTUAL', maxLeverage: 5, collections: ['AI / DePIN'] }, + { ticker: 'PENGU', maxLeverage: 5, collections: ['Memecoin', 'Gaming / NFT', 'Solana Ecosystem'] }, + { ticker: 'USUAL', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, + { ticker: 'FARTCOIN', maxLeverage: 10, collections: ['Memecoin'] }, + { ticker: 'AIXBT', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, + { ticker: 'BIO', maxLeverage: 3, collections: ['AI / DePIN'] }, + { ticker: 'GRIFFAIN', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, + { ticker: 'SPX', maxLeverage: 5, collections: ['AI / DePIN', 'Memecoin'] }, + { ticker: 'S', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'MORPHO', maxLeverage: 5, collections: ['DeFi'] }, + { ticker: 'TRUMP', maxLeverage: 10, collections: ['Memecoin', 'Political'] }, + { ticker: 'MELANIA', maxLeverage: 3, collections: ['Memecoin', 'Political'] }, + { ticker: 'ANIME', maxLeverage: 3, collections: ['Gaming / NFT', 'Memecoin'] }, + { ticker: 'VINE', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'VVV', maxLeverage: 3, collections: ['DeFi'] }, + { ticker: 'BERA', maxLeverage: 5, collections: ['L1', 'DeFi'] }, + { ticker: 'TST', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'LAYER', maxLeverage: 3, collections: ['LSD / Liquid Staking', 'Solana Ecosystem'] }, + { ticker: 'IP', maxLeverage: 3, collections: ['Infrastructure'] }, + { ticker: 'KAITO', maxLeverage: 5, collections: ['AI / DePIN', 'Infrastructure'] }, + { ticker: 'NIL', maxLeverage: 3, collections: ['L1', 'ZK / Modular'] }, + { ticker: 'PAXG', maxLeverage: 10, collections: ['RWA / Stablecoin'] }, + { ticker: 'BABY', maxLeverage: 3, collections: ['Memecoin'] }, + { ticker: 'WCT', maxLeverage: 3, collections: ['Infrastructure'] }, + { ticker: 'HYPER', maxLeverage: 3, collections: ['AI / DePIN'] }, + { ticker: 'ZORA', maxLeverage: 3, collections: ['Gaming / NFT', 'L2 / Scaling'] }, + { ticker: 'INIT', maxLeverage: 3, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'DOOD', maxLeverage: 3, collections: ['Gaming / NFT', 'Memecoin'] }, + { ticker: 'NXPC', maxLeverage: 3, collections: [] }, + { ticker: 'SOPH', maxLeverage: 3, collections: ['L2 / Scaling', 'AI / DePIN'] }, + { ticker: 'RESOLV', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, + { ticker: 'SYRUP', maxLeverage: 3, collections: ['DeFi'] }, + { ticker: 'PUMP', maxLeverage: 10, collections: ['Memecoin', 'Solana Ecosystem'] }, + { ticker: 'PROVE', maxLeverage: 3, collections: ['ZK / Modular', 'Infrastructure'] }, + { ticker: 'XPL', maxLeverage: 10, collections: [] }, + { ticker: 'WLFI', maxLeverage: 5, collections: ['DeFi'] }, + { ticker: 'LINEA', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular'] }, + { ticker: 'SKY', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, + { ticker: 'ASTER', maxLeverage: 5, collections: ['DeFi', 'Exchange Token'] }, + { ticker: 'AVNT', maxLeverage: 5, collections: [] }, + { ticker: 'STBL', maxLeverage: 3, collections: ['RWA / Stablecoin'] }, + { ticker: '0G', maxLeverage: 3, collections: ['AI / DePIN', 'Storage / Data'] }, + { ticker: 'HEMI', maxLeverage: 3, collections: ['L2 / Scaling', 'Bitcoin Ecosystem'] }, + { ticker: 'APEX', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, + { ticker: '2Z', maxLeverage: 3, collections: [] }, + { ticker: 'ZEC', maxLeverage: 10, collections: ['L1', 'Privacy'] }, + { ticker: 'MON', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, + { ticker: 'MET', maxLeverage: 3, collections: ['L2 / Scaling'] }, + { ticker: 'MEGA', maxLeverage: 3, collections: ['L2 / Scaling'] }, + { ticker: 'CC', maxLeverage: 3, collections: [] }, + { ticker: 'ICP', maxLeverage: 5, collections: ['L1', 'Infrastructure'] }, + { ticker: 'AERO', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, + { ticker: 'STABLE', maxLeverage: 3, collections: ['RWA / Stablecoin'] }, + { ticker: 'FOGO', maxLeverage: 3, collections: [] }, + { ticker: 'LIT', maxLeverage: 5, collections: ['Infrastructure', 'Privacy'] }, + { ticker: 'XMR', maxLeverage: 5, collections: ['L1', 'Privacy'] }, + { ticker: 'AXS', maxLeverage: 5, collections: ['Gaming / NFT'] }, + { ticker: 'DASH', maxLeverage: 5, collections: ['L1', 'Privacy', 'Payments'] }, + { ticker: 'SKR', maxLeverage: 3, collections: [] }, + { ticker: 'AZTEC', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular', 'Privacy'] }, + { ticker: 'CHIP', maxLeverage: 3, collections: [] }, +] as const; + +const marketsByTicker = new Map( + PERPS_MARKET_DEFINITIONS.map((m) => [m.ticker, m]), +); + +/** + * Look up a single market definition by its ticker symbol. + * O(1) via pre-built Map. + * + * @param ticker - The ticker to look up (e.g. 'BTC', 'ETH'). + * @returns The matching definition, or `undefined` if not found. + */ +export function getMarketDefinitionByTicker( + ticker: string, +): PerpsMarketDefinition | undefined { + return marketsByTicker.get(ticker); +} + +/** + * Return all market definitions that belong to a given collection tag. + * + * @param collection - The collection tag to filter by. + * @returns Array of matching market definitions (may be empty). + */ +export function getMarketDefinitionsByCollection( + collection: PerpsMarketCollectionTag, +): PerpsMarketDefinition[] { + return PERPS_MARKET_DEFINITIONS.filter((m) => + m.collections.includes(collection), + ); +} diff --git a/packages/perps-controller/src/index.ts b/packages/perps-controller/src/index.ts index c82cc7d4e1..d51d65af4d 100644 --- a/packages/perps-controller/src/index.ts +++ b/packages/perps-controller/src/index.ts @@ -73,6 +73,10 @@ export type { PerpsControllerGetMarketDataWithPricesAction, PerpsControllerGetMarketFilterPreferencesAction, PerpsControllerGetMarketCategoriesAction, + PerpsControllerGetMarketCollectionsAction, + PerpsControllerGetMarketDefinitionByTickerAction, + PerpsControllerGetMarketDefinitionsAction, + PerpsControllerGetMarketDefinitionsByCollectionAction, PerpsControllerGetMarketsAction, PerpsControllerGetMaxLeverageAction, PerpsControllerGetOpenOrdersAction, @@ -139,6 +143,10 @@ export { MARKET_CATEGORIES, MarketCategory, } from './types'; +export type { + PerpsMarketCollectionTag, + PerpsMarketDefinition, +} from './types'; export type { RawLedgerUpdate, UserHistoryItem, @@ -413,6 +421,12 @@ export { MYX_MINIMUM_ORDER_SIZE_USD, MYX_EXECUTION_FEE_TOKEN, } from './constants'; +export { + PERPS_MARKET_COLLECTION_TAGS, + PERPS_MARKET_DEFINITIONS, + getMarketDefinitionByTicker, + getMarketDefinitionsByCollection, +} from './constants'; export { PERPS_CONSTANTS, WITHDRAWAL_CONSTANTS, diff --git a/packages/perps-controller/src/types/index.ts b/packages/perps-controller/src/types/index.ts index 24f8cbbdd4..dffbca0705 100644 --- a/packages/perps-controller/src/types/index.ts +++ b/packages/perps-controller/src/types/index.ts @@ -1787,6 +1787,57 @@ export function isVersionGatedFeatureFlag( ); } +// ============================================================================ +// Market Collections +// ============================================================================ + +/** + * Tag identifying a thematic collection/grouping that a perps market belongs to. + * A single market may belong to zero or more collections. + */ +export type PerpsMarketCollectionTag = + | 'L1' + | 'L2 / Scaling' + | 'Bitcoin Ecosystem' + | 'Solana Ecosystem' + | 'Cosmos Ecosystem' + | 'TON Ecosystem' + | 'Hyperliquid Ecosystem' + | 'Move Ecosystem' + | 'Smart Contract Platform' + | 'DeFi' + | 'Exchange Token' + | 'Memecoin' + | 'Gaming / NFT' + | 'AI / DePIN' + | 'Infrastructure' + | 'Oracle' + | 'Interoperability' + | 'Payments' + | 'LSD / Liquid Staking' + | 'RWA / Stablecoin' + | 'ZK / Modular' + | 'Privacy' + | 'Storage / Data' + | 'Store of Value' + | 'Metaverse' + | 'IoT / Infrastructure' + | 'Political'; + +/** + * Static definition of a supported perps market. + * These entries are hardcoded and represent the canonical set of markets + * available for perpetual trading. + */ +export type PerpsMarketDefinition = { + /** Asset ticker symbol (e.g. 'BTC', 'ETH', 'kPEPE'). */ + ticker: string; + /** Maximum leverage multiplier (e.g. 40 for 40x). */ + maxLeverage: number; + /** Thematic collections this market belongs to. May be empty. */ + collections: PerpsMarketCollectionTag[]; +}; + // ============================================================================ // Sub-module type re-exports // These types live in separate files within types/ and need to be accessible diff --git a/packages/perps-controller/tests/src/constants/marketCollections.test.ts b/packages/perps-controller/tests/src/constants/marketCollections.test.ts new file mode 100644 index 0000000000..7941719d50 --- /dev/null +++ b/packages/perps-controller/tests/src/constants/marketCollections.test.ts @@ -0,0 +1,158 @@ +import { + PERPS_MARKET_COLLECTION_TAGS, + PERPS_MARKET_DEFINITIONS, + getMarketDefinitionByTicker, + getMarketDefinitionsByCollection, +} from '../../../src/constants/marketCollections'; +import type { PerpsMarketCollectionTag } from '../../../src/types'; + +describe('PERPS_MARKET_DEFINITIONS', () => { + it('contains 183 market entries', () => { + expect(PERPS_MARKET_DEFINITIONS).toHaveLength(183); + }); + + it('has unique tickers', () => { + const tickers = PERPS_MARKET_DEFINITIONS.map((m) => m.ticker); + expect(new Set(tickers).size).toBe(tickers.length); + }); + + it('has valid maxLeverage for every entry', () => { + for (const market of PERPS_MARKET_DEFINITIONS) { + expect(market.maxLeverage).toBeGreaterThanOrEqual(1); + expect(Number.isInteger(market.maxLeverage)).toBe(true); + } + }); + + it('has a non-empty ticker for every entry', () => { + for (const market of PERPS_MARKET_DEFINITIONS) { + expect(market.ticker.length).toBeGreaterThan(0); + } + }); + + it('only uses collection tags that exist in PERPS_MARKET_COLLECTION_TAGS', () => { + const validTags = new Set(PERPS_MARKET_COLLECTION_TAGS); + for (const market of PERPS_MARKET_DEFINITIONS) { + for (const tag of market.collections) { + expect(validTags.has(tag)).toBe(true); + } + } + }); + + it('includes known markets with correct data', () => { + const btc = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'BTC'); + expect(btc).toStrictEqual({ + ticker: 'BTC', + maxLeverage: 40, + collections: ['L1', 'Bitcoin Ecosystem', 'Store of Value'], + }); + + const eth = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'ETH'); + expect(eth).toStrictEqual({ + ticker: 'ETH', + maxLeverage: 25, + collections: ['L1', 'Smart Contract Platform'], + }); + }); + + it('allows markets with empty collections', () => { + const nxpc = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'NXPC'); + expect(nxpc).toBeDefined(); + expect(nxpc?.collections).toStrictEqual([]); + }); +}); + +describe('PERPS_MARKET_COLLECTION_TAGS', () => { + it('contains 27 collection tags', () => { + expect(PERPS_MARKET_COLLECTION_TAGS).toHaveLength(27); + }); + + it('has unique tags', () => { + expect(new Set(PERPS_MARKET_COLLECTION_TAGS).size).toBe( + PERPS_MARKET_COLLECTION_TAGS.length, + ); + }); + + it('covers every tag used by any market definition', () => { + const usedTags = new Set(); + for (const market of PERPS_MARKET_DEFINITIONS) { + for (const tag of market.collections) { + usedTags.add(tag); + } + } + const declaredTags = new Set(PERPS_MARKET_COLLECTION_TAGS); + for (const tag of usedTags) { + expect(declaredTags.has(tag)).toBe(true); + } + }); +}); + +describe('getMarketDefinitionByTicker', () => { + it('returns the correct entry for BTC', () => { + const btc = getMarketDefinitionByTicker('BTC'); + expect(btc).toBeDefined(); + expect(btc?.ticker).toBe('BTC'); + expect(btc?.maxLeverage).toBe(40); + expect(btc?.collections).toContain('Bitcoin Ecosystem'); + }); + + it('returns undefined for a non-existent ticker', () => { + expect(getMarketDefinitionByTicker('NONEXISTENT')).toBeUndefined(); + }); + + it('is case-sensitive', () => { + expect(getMarketDefinitionByTicker('btc')).toBeUndefined(); + expect(getMarketDefinitionByTicker('Btc')).toBeUndefined(); + }); + + it('returns the correct entry for a ticker with special prefix', () => { + const kPepe = getMarketDefinitionByTicker('kPEPE'); + expect(kPepe).toBeDefined(); + expect(kPepe?.maxLeverage).toBe(10); + expect(kPepe?.collections).toStrictEqual(['Memecoin']); + }); +}); + +describe('getMarketDefinitionsByCollection', () => { + it('returns all Memecoin markets', () => { + const memecoins = getMarketDefinitionsByCollection('Memecoin'); + expect(memecoins.length).toBeGreaterThan(0); + for (const market of memecoins) { + expect(market.collections).toContain('Memecoin'); + } + }); + + it('returns all DeFi markets', () => { + const defi = getMarketDefinitionsByCollection('DeFi'); + expect(defi.length).toBeGreaterThan(0); + for (const market of defi) { + expect(market.collections).toContain('DeFi'); + } + }); + + it('returns BTC for Bitcoin Ecosystem', () => { + const btcEco = getMarketDefinitionsByCollection('Bitcoin Ecosystem'); + const tickers = btcEco.map((m) => m.ticker); + expect(tickers).toContain('BTC'); + expect(tickers).toContain('LTC'); + }); + + it('returns an empty array for a tag with no markets', () => { + const allTags = new Set( + PERPS_MARKET_DEFINITIONS.flatMap((m) => m.collections), + ); + // "Store of Value" should only have BTC, but let's test an actual edge case: + // verify each returned market actually has the tag + const storeOfValue = getMarketDefinitionsByCollection('Store of Value'); + expect(storeOfValue.length).toBeGreaterThanOrEqual(1); + for (const market of storeOfValue) { + expect(market.collections).toContain('Store of Value'); + } + // Verify all declared tags have at least one result OR are valid + for (const tag of PERPS_MARKET_COLLECTION_TAGS) { + const results = getMarketDefinitionsByCollection(tag); + if (allTags.has(tag)) { + expect(results.length).toBeGreaterThan(0); + } + } + }); +}); From 78a16f187d1a7722d00e69ed2a8e6e7721f579bb Mon Sep 17 00:00:00 2001 From: Michal Szorad Date: Fri, 12 Jun 2026 10:35:08 +0200 Subject: [PATCH 2/5] refactor(perps-controller): use enum for collection tags, remove maxLeverage and empty markets - Convert PerpsMarketCollectionTag from string literal union to string enum - Remove maxLeverage from PerpsMarketDefinition (already available via provider) - Remove 8 markets with no collection tags (NXPC, XPL, AVNT, 2Z, CC, FOGO, SKR, CHIP) --- .../src/constants/marketCollections.ts | 428 +++++++++--------- packages/perps-controller/src/index.ts | 6 +- packages/perps-controller/src/types/index.ts | 59 ++- .../src/constants/marketCollections.test.ts | 73 +-- 4 files changed, 288 insertions(+), 278 deletions(-) diff --git a/packages/perps-controller/src/constants/marketCollections.ts b/packages/perps-controller/src/constants/marketCollections.ts index de9d2a5c3c..3c03177d67 100644 --- a/packages/perps-controller/src/constants/marketCollections.ts +++ b/packages/perps-controller/src/constants/marketCollections.ts @@ -1,231 +1,235 @@ -import type { +import { PerpsMarketCollectionTag, +} from '../types'; +import type { PerpsMarketDefinition, } from '../types'; +const T = PerpsMarketCollectionTag; + /** * Ordered list of all market collection tags for UI filter pills. * The order here determines display order in the consumer UI. */ export const PERPS_MARKET_COLLECTION_TAGS: readonly PerpsMarketCollectionTag[] = [ - 'L1', - 'L2 / Scaling', - 'Bitcoin Ecosystem', - 'Solana Ecosystem', - 'Cosmos Ecosystem', - 'TON Ecosystem', - 'Hyperliquid Ecosystem', - 'Move Ecosystem', - 'Smart Contract Platform', - 'DeFi', - 'Exchange Token', - 'Memecoin', - 'Gaming / NFT', - 'AI / DePIN', - 'Infrastructure', - 'Oracle', - 'Interoperability', - 'Payments', - 'LSD / Liquid Staking', - 'RWA / Stablecoin', - 'ZK / Modular', - 'Privacy', - 'Storage / Data', - 'Store of Value', - 'Metaverse', - 'IoT / Infrastructure', - 'Political', + T.L1, + T.L2Scaling, + T.BitcoinEcosystem, + T.SolanaEcosystem, + T.CosmosEcosystem, + T.TonEcosystem, + T.HyperliquidEcosystem, + T.MoveEcosystem, + T.SmartContractPlatform, + T.DeFi, + T.ExchangeToken, + T.Memecoin, + T.GamingNft, + T.AiDepin, + T.Infrastructure, + T.Oracle, + T.Interoperability, + T.Payments, + T.LiquidStaking, + T.RwaStablecoin, + T.ZkModular, + T.Privacy, + T.StorageData, + T.StoreOfValue, + T.Metaverse, + T.IotInfrastructure, + T.Political, ] as const; /** * Canonical registry of all supported perps markets. - * Each entry defines the ticker, maximum leverage, and thematic collections. + * Each entry defines the ticker and thematic collections. */ export const PERPS_MARKET_DEFINITIONS: readonly PerpsMarketDefinition[] = [ - { ticker: 'BTC', maxLeverage: 40, collections: ['L1', 'Bitcoin Ecosystem', 'Store of Value'] }, - { ticker: 'ETH', maxLeverage: 25, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'ATOM', maxLeverage: 5, collections: ['L1', 'Cosmos Ecosystem', 'Interoperability'] }, - { ticker: 'DYDX', maxLeverage: 5, collections: ['DeFi', 'Cosmos Ecosystem', 'Exchange Token'] }, - { ticker: 'SOL', maxLeverage: 20, collections: ['L1', 'Solana Ecosystem'] }, - { ticker: 'AVAX', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'BNB', maxLeverage: 10, collections: ['L1', 'Exchange Token', 'Smart Contract Platform'] }, - { ticker: 'APE', maxLeverage: 5, collections: ['Gaming / NFT'] }, - { ticker: 'OP', maxLeverage: 5, collections: ['L2 / Scaling'] }, - { ticker: 'LTC', maxLeverage: 10, collections: ['L1', 'Bitcoin Ecosystem', 'Payments'] }, - { ticker: 'ARB', maxLeverage: 10, collections: ['L2 / Scaling'] }, - { ticker: 'DOGE', maxLeverage: 10, collections: ['L1', 'Memecoin', 'Payments'] }, - { ticker: 'INJ', maxLeverage: 5, collections: ['L1', 'Cosmos Ecosystem', 'DeFi'] }, - { ticker: 'SUI', maxLeverage: 10, collections: ['L1', 'Move Ecosystem'] }, - { ticker: 'kPEPE', maxLeverage: 10, collections: ['Memecoin'] }, - { ticker: 'CRV', maxLeverage: 10, collections: ['DeFi'] }, - { ticker: 'LDO', maxLeverage: 5, collections: ['DeFi', 'LSD / Liquid Staking'] }, - { ticker: 'LINK', maxLeverage: 10, collections: ['Infrastructure', 'Oracle'] }, - { ticker: 'STX', maxLeverage: 5, collections: ['L2 / Scaling', 'Bitcoin Ecosystem'] }, - { ticker: 'CFX', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'GMX', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, - { ticker: 'SNX', maxLeverage: 3, collections: ['DeFi'] }, - { ticker: 'XRP', maxLeverage: 20, collections: ['L1', 'Payments'] }, - { ticker: 'BCH', maxLeverage: 10, collections: ['L1', 'Bitcoin Ecosystem', 'Payments'] }, - { ticker: 'APT', maxLeverage: 10, collections: ['L1', 'Move Ecosystem'] }, - { ticker: 'AAVE', maxLeverage: 10, collections: ['DeFi'] }, - { ticker: 'COMP', maxLeverage: 5, collections: ['DeFi'] }, - { ticker: 'WLD', maxLeverage: 10, collections: ['AI / DePIN'] }, - { ticker: 'YGG', maxLeverage: 3, collections: ['Gaming / NFT'] }, - { ticker: 'TRX', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'kSHIB', maxLeverage: 10, collections: ['Memecoin'] }, - { ticker: 'UNI', maxLeverage: 10, collections: ['DeFi', 'Exchange Token'] }, - { ticker: 'SEI', maxLeverage: 5, collections: ['L1', 'Cosmos Ecosystem', 'DeFi'] }, - { ticker: 'RUNE', maxLeverage: 5, collections: ['Bitcoin Ecosystem', 'DeFi'] }, - { ticker: 'ZRO', maxLeverage: 5, collections: ['Infrastructure', 'Interoperability'] }, - { ticker: 'DOT', maxLeverage: 10, collections: ['L1', 'Interoperability'] }, - { ticker: 'BANANA', maxLeverage: 3, collections: ['Memecoin', 'DeFi'] }, - { ticker: 'TRB', maxLeverage: 3, collections: ['Infrastructure', 'Oracle'] }, - { ticker: 'FTT', maxLeverage: 3, collections: ['Exchange Token'] }, - { ticker: 'ARK', maxLeverage: 3, collections: ['L1'] }, - { ticker: 'BIGTIME', maxLeverage: 3, collections: ['Gaming / NFT'] }, - { ticker: 'KAS', maxLeverage: 3, collections: ['L1', 'Bitcoin Ecosystem'] }, - { ticker: 'BLUR', maxLeverage: 3, collections: ['Gaming / NFT', 'DeFi'] }, - { ticker: 'TIA', maxLeverage: 5, collections: ['L1', 'ZK / Modular', 'Cosmos Ecosystem'] }, - { ticker: 'BSV', maxLeverage: 3, collections: ['L1', 'Bitcoin Ecosystem'] }, - { ticker: 'ADA', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'TON', maxLeverage: 10, collections: ['L1', 'TON Ecosystem'] }, - { ticker: 'MINA', maxLeverage: 3, collections: ['L1', 'ZK / Modular'] }, - { ticker: 'POLYX', maxLeverage: 3, collections: ['RWA / Stablecoin', 'Infrastructure'] }, - { ticker: 'GAS', maxLeverage: 3, collections: ['Infrastructure'] }, - { ticker: 'PENDLE', maxLeverage: 5, collections: ['DeFi', 'LSD / Liquid Staking'] }, - { ticker: 'FET', maxLeverage: 5, collections: ['AI / DePIN', 'Infrastructure'] }, - { ticker: 'NEAR', maxLeverage: 10, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'MEME', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'ORDI', maxLeverage: 3, collections: ['Bitcoin Ecosystem'] }, - { ticker: 'NEO', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'ZEN', maxLeverage: 5, collections: ['L1', 'Privacy'] }, - { ticker: 'FIL', maxLeverage: 5, collections: ['L1', 'Storage / Data'] }, - { ticker: 'PYTH', maxLeverage: 5, collections: ['Infrastructure', 'Oracle', 'Solana Ecosystem'] }, - { ticker: 'SUSHI', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, - { ticker: 'IMX', maxLeverage: 5, collections: ['Gaming / NFT', 'L2 / Scaling'] }, - { ticker: 'kBONK', maxLeverage: 10, collections: ['Memecoin', 'Solana Ecosystem'] }, - { ticker: 'GMT', maxLeverage: 3, collections: ['Gaming / NFT'] }, - { ticker: 'SUPER', maxLeverage: 3, collections: ['Gaming / NFT'] }, - { ticker: 'JUP', maxLeverage: 10, collections: ['DeFi', 'Solana Ecosystem', 'Exchange Token'] }, - { ticker: 'kLUNC', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'RSR', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, - { ticker: 'GALA', maxLeverage: 3, collections: ['Gaming / NFT'] }, - { ticker: 'JTO', maxLeverage: 5, collections: ['DeFi', 'Solana Ecosystem', 'LSD / Liquid Staking'] }, - { ticker: 'ACE', maxLeverage: 3, collections: ['Gaming / NFT'] }, - { ticker: 'WIF', maxLeverage: 5, collections: ['Memecoin', 'Solana Ecosystem'] }, - { ticker: 'CAKE', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, - { ticker: 'PEOPLE', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'ENS', maxLeverage: 5, collections: ['Infrastructure'] }, - { ticker: 'ETC', maxLeverage: 5, collections: ['L1', 'Bitcoin Ecosystem'] }, - { ticker: 'XAI', maxLeverage: 3, collections: ['Gaming / NFT', 'L2 / Scaling'] }, - { ticker: 'MANTA', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular'] }, - { ticker: 'UMA', maxLeverage: 3, collections: ['Infrastructure', 'Oracle', 'DeFi'] }, - { ticker: 'ONDO', maxLeverage: 10, collections: ['RWA / Stablecoin', 'DeFi'] }, - { ticker: 'ALT', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular'] }, - { ticker: 'ZETA', maxLeverage: 3, collections: ['L1', 'Interoperability'] }, - { ticker: 'DYM', maxLeverage: 3, collections: ['L1', 'ZK / Modular'] }, - { ticker: 'W', maxLeverage: 5, collections: ['L1', 'Interoperability'] }, - { ticker: 'STRK', maxLeverage: 5, collections: ['L2 / Scaling', 'ZK / Modular'] }, - { ticker: 'TAO', maxLeverage: 5, collections: ['L1', 'AI / DePIN'] }, - { ticker: 'AR', maxLeverage: 5, collections: ['L1', 'Storage / Data'] }, - { ticker: 'kFLOKI', maxLeverage: 5, collections: ['Memecoin'] }, - { ticker: 'BOME', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, - { ticker: 'ETHFI', maxLeverage: 5, collections: ['DeFi', 'LSD / Liquid Staking'] }, - { ticker: 'ENA', maxLeverage: 10, collections: ['DeFi', 'RWA / Stablecoin'] }, - { ticker: 'MNT', maxLeverage: 5, collections: ['L2 / Scaling', 'Exchange Token'] }, - { ticker: 'TNSR', maxLeverage: 3, collections: ['Gaming / NFT', 'Solana Ecosystem'] }, - { ticker: 'SAGA', maxLeverage: 3, collections: ['L1', 'Gaming / NFT'] }, - { ticker: 'MERL', maxLeverage: 3, collections: ['L2 / Scaling', 'Bitcoin Ecosystem'] }, - { ticker: 'HBAR', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'POPCAT', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, - { ticker: 'EIGEN', maxLeverage: 5, collections: ['Infrastructure', 'LSD / Liquid Staking'] }, - { ticker: 'REZ', maxLeverage: 3, collections: ['DeFi', 'LSD / Liquid Staking'] }, - { ticker: 'NOT', maxLeverage: 3, collections: ['Memecoin', 'TON Ecosystem'] }, - { ticker: 'TURBO', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, - { ticker: 'BRETT', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'IO', maxLeverage: 3, collections: ['AI / DePIN'] }, - { ticker: 'ZK', maxLeverage: 5, collections: ['L2 / Scaling', 'ZK / Modular'] }, - { ticker: 'BLAST', maxLeverage: 3, collections: ['L2 / Scaling', 'DeFi'] }, - { ticker: 'RENDER', maxLeverage: 5, collections: ['AI / DePIN'] }, - { ticker: 'POL', maxLeverage: 5, collections: ['L2 / Scaling'] }, - { ticker: 'CELO', maxLeverage: 3, collections: ['L1', 'Payments'] }, - { ticker: 'HMSTR', maxLeverage: 3, collections: ['Memecoin', 'TON Ecosystem'] }, - { ticker: 'kNEIRO', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'GOAT', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, - { ticker: 'MOODENG', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'GRASS', maxLeverage: 3, collections: ['AI / DePIN'] }, - { ticker: 'PURR', maxLeverage: 3, collections: ['Memecoin', 'Hyperliquid Ecosystem'] }, - { ticker: 'PNUT', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, - { ticker: 'XLM', maxLeverage: 5, collections: ['L1', 'Payments'] }, - { ticker: 'CHILLGUY', maxLeverage: 3, collections: ['Memecoin', 'Solana Ecosystem'] }, - { ticker: 'SAND', maxLeverage: 5, collections: ['Gaming / NFT', 'Metaverse'] }, - { ticker: 'IOTA', maxLeverage: 3, collections: ['L1', 'IoT / Infrastructure'] }, - { ticker: 'ALGO', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'HYPE', maxLeverage: 10, collections: ['L1', 'Exchange Token', 'Hyperliquid Ecosystem'] }, - { ticker: 'ME', maxLeverage: 3, collections: ['Gaming / NFT', 'Solana Ecosystem'] }, - { ticker: 'MOVE', maxLeverage: 3, collections: ['L1', 'Move Ecosystem'] }, - { ticker: 'VIRTUAL', maxLeverage: 5, collections: ['AI / DePIN'] }, - { ticker: 'PENGU', maxLeverage: 5, collections: ['Memecoin', 'Gaming / NFT', 'Solana Ecosystem'] }, - { ticker: 'USUAL', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, - { ticker: 'FARTCOIN', maxLeverage: 10, collections: ['Memecoin'] }, - { ticker: 'AIXBT', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, - { ticker: 'BIO', maxLeverage: 3, collections: ['AI / DePIN'] }, - { ticker: 'GRIFFAIN', maxLeverage: 3, collections: ['AI / DePIN', 'Memecoin'] }, - { ticker: 'SPX', maxLeverage: 5, collections: ['AI / DePIN', 'Memecoin'] }, - { ticker: 'S', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'MORPHO', maxLeverage: 5, collections: ['DeFi'] }, - { ticker: 'TRUMP', maxLeverage: 10, collections: ['Memecoin', 'Political'] }, - { ticker: 'MELANIA', maxLeverage: 3, collections: ['Memecoin', 'Political'] }, - { ticker: 'ANIME', maxLeverage: 3, collections: ['Gaming / NFT', 'Memecoin'] }, - { ticker: 'VINE', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'VVV', maxLeverage: 3, collections: ['DeFi'] }, - { ticker: 'BERA', maxLeverage: 5, collections: ['L1', 'DeFi'] }, - { ticker: 'TST', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'LAYER', maxLeverage: 3, collections: ['LSD / Liquid Staking', 'Solana Ecosystem'] }, - { ticker: 'IP', maxLeverage: 3, collections: ['Infrastructure'] }, - { ticker: 'KAITO', maxLeverage: 5, collections: ['AI / DePIN', 'Infrastructure'] }, - { ticker: 'NIL', maxLeverage: 3, collections: ['L1', 'ZK / Modular'] }, - { ticker: 'PAXG', maxLeverage: 10, collections: ['RWA / Stablecoin'] }, - { ticker: 'BABY', maxLeverage: 3, collections: ['Memecoin'] }, - { ticker: 'WCT', maxLeverage: 3, collections: ['Infrastructure'] }, - { ticker: 'HYPER', maxLeverage: 3, collections: ['AI / DePIN'] }, - { ticker: 'ZORA', maxLeverage: 3, collections: ['Gaming / NFT', 'L2 / Scaling'] }, - { ticker: 'INIT', maxLeverage: 3, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'DOOD', maxLeverage: 3, collections: ['Gaming / NFT', 'Memecoin'] }, - { ticker: 'NXPC', maxLeverage: 3, collections: [] }, - { ticker: 'SOPH', maxLeverage: 3, collections: ['L2 / Scaling', 'AI / DePIN'] }, - { ticker: 'RESOLV', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, - { ticker: 'SYRUP', maxLeverage: 3, collections: ['DeFi'] }, - { ticker: 'PUMP', maxLeverage: 10, collections: ['Memecoin', 'Solana Ecosystem'] }, - { ticker: 'PROVE', maxLeverage: 3, collections: ['ZK / Modular', 'Infrastructure'] }, - { ticker: 'XPL', maxLeverage: 10, collections: [] }, - { ticker: 'WLFI', maxLeverage: 5, collections: ['DeFi'] }, - { ticker: 'LINEA', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular'] }, - { ticker: 'SKY', maxLeverage: 3, collections: ['DeFi', 'RWA / Stablecoin'] }, - { ticker: 'ASTER', maxLeverage: 5, collections: ['DeFi', 'Exchange Token'] }, - { ticker: 'AVNT', maxLeverage: 5, collections: [] }, - { ticker: 'STBL', maxLeverage: 3, collections: ['RWA / Stablecoin'] }, - { ticker: '0G', maxLeverage: 3, collections: ['AI / DePIN', 'Storage / Data'] }, - { ticker: 'HEMI', maxLeverage: 3, collections: ['L2 / Scaling', 'Bitcoin Ecosystem'] }, - { ticker: 'APEX', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, - { ticker: '2Z', maxLeverage: 3, collections: [] }, - { ticker: 'ZEC', maxLeverage: 10, collections: ['L1', 'Privacy'] }, - { ticker: 'MON', maxLeverage: 5, collections: ['L1', 'Smart Contract Platform'] }, - { ticker: 'MET', maxLeverage: 3, collections: ['L2 / Scaling'] }, - { ticker: 'MEGA', maxLeverage: 3, collections: ['L2 / Scaling'] }, - { ticker: 'CC', maxLeverage: 3, collections: [] }, - { ticker: 'ICP', maxLeverage: 5, collections: ['L1', 'Infrastructure'] }, - { ticker: 'AERO', maxLeverage: 3, collections: ['DeFi', 'Exchange Token'] }, - { ticker: 'STABLE', maxLeverage: 3, collections: ['RWA / Stablecoin'] }, - { ticker: 'FOGO', maxLeverage: 3, collections: [] }, - { ticker: 'LIT', maxLeverage: 5, collections: ['Infrastructure', 'Privacy'] }, - { ticker: 'XMR', maxLeverage: 5, collections: ['L1', 'Privacy'] }, - { ticker: 'AXS', maxLeverage: 5, collections: ['Gaming / NFT'] }, - { ticker: 'DASH', maxLeverage: 5, collections: ['L1', 'Privacy', 'Payments'] }, - { ticker: 'SKR', maxLeverage: 3, collections: [] }, - { ticker: 'AZTEC', maxLeverage: 3, collections: ['L2 / Scaling', 'ZK / Modular', 'Privacy'] }, - { ticker: 'CHIP', maxLeverage: 3, collections: [] }, + { ticker: 'BTC', collections: [T.L1, T.BitcoinEcosystem, T.StoreOfValue] }, + { ticker: 'ETH', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'ATOM', collections: [T.L1, T.CosmosEcosystem, T.Interoperability] }, + { ticker: 'DYDX', collections: [T.DeFi, T.CosmosEcosystem, T.ExchangeToken] }, + { ticker: 'SOL', collections: [T.L1, T.SolanaEcosystem] }, + { ticker: 'AVAX', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'BNB', collections: [T.L1, T.ExchangeToken, T.SmartContractPlatform] }, + { ticker: 'APE', collections: [T.GamingNft] }, + { ticker: 'OP', collections: [T.L2Scaling] }, + { ticker: 'LTC', collections: [T.L1, T.BitcoinEcosystem, T.Payments] }, + { ticker: 'ARB', collections: [T.L2Scaling] }, + { ticker: 'DOGE', collections: [T.L1, T.Memecoin, T.Payments] }, + { ticker: 'INJ', collections: [T.L1, T.CosmosEcosystem, T.DeFi] }, + { ticker: 'SUI', collections: [T.L1, T.MoveEcosystem] }, + { ticker: 'kPEPE', collections: [T.Memecoin] }, + { ticker: 'CRV', collections: [T.DeFi] }, + { ticker: 'LDO', collections: [T.DeFi, T.LiquidStaking] }, + { ticker: 'LINK', collections: [T.Infrastructure, T.Oracle] }, + { ticker: 'STX', collections: [T.L2Scaling, T.BitcoinEcosystem] }, + { ticker: 'CFX', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'GMX', collections: [T.DeFi, T.ExchangeToken] }, + { ticker: 'SNX', collections: [T.DeFi] }, + { ticker: 'XRP', collections: [T.L1, T.Payments] }, + { ticker: 'BCH', collections: [T.L1, T.BitcoinEcosystem, T.Payments] }, + { ticker: 'APT', collections: [T.L1, T.MoveEcosystem] }, + { ticker: 'AAVE', collections: [T.DeFi] }, + { ticker: 'COMP', collections: [T.DeFi] }, + { ticker: 'WLD', collections: [T.AiDepin] }, + { ticker: 'YGG', collections: [T.GamingNft] }, + { ticker: 'TRX', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'kSHIB', collections: [T.Memecoin] }, + { ticker: 'UNI', collections: [T.DeFi, T.ExchangeToken] }, + { ticker: 'SEI', collections: [T.L1, T.CosmosEcosystem, T.DeFi] }, + { ticker: 'RUNE', collections: [T.BitcoinEcosystem, T.DeFi] }, + { ticker: 'ZRO', collections: [T.Infrastructure, T.Interoperability] }, + { ticker: 'DOT', collections: [T.L1, T.Interoperability] }, + { ticker: 'BANANA', collections: [T.Memecoin, T.DeFi] }, + { ticker: 'TRB', collections: [T.Infrastructure, T.Oracle] }, + { ticker: 'FTT', collections: [T.ExchangeToken] }, + { ticker: 'ARK', collections: [T.L1] }, + { ticker: 'BIGTIME', collections: [T.GamingNft] }, + { ticker: 'KAS', collections: [T.L1, T.BitcoinEcosystem] }, + { ticker: 'BLUR', collections: [T.GamingNft, T.DeFi] }, + { ticker: 'TIA', collections: [T.L1, T.ZkModular, T.CosmosEcosystem] }, + { ticker: 'BSV', collections: [T.L1, T.BitcoinEcosystem] }, + { ticker: 'ADA', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'TON', collections: [T.L1, T.TonEcosystem] }, + { ticker: 'MINA', collections: [T.L1, T.ZkModular] }, + { ticker: 'POLYX', collections: [T.RwaStablecoin, T.Infrastructure] }, + { ticker: 'GAS', collections: [T.Infrastructure] }, + { ticker: 'PENDLE', collections: [T.DeFi, T.LiquidStaking] }, + { ticker: 'FET', collections: [T.AiDepin, T.Infrastructure] }, + { ticker: 'NEAR', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'MEME', collections: [T.Memecoin] }, + { ticker: 'ORDI', collections: [T.BitcoinEcosystem] }, + { ticker: 'NEO', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'ZEN', collections: [T.L1, T.Privacy] }, + { ticker: 'FIL', collections: [T.L1, T.StorageData] }, + { ticker: 'PYTH', collections: [T.Infrastructure, T.Oracle, T.SolanaEcosystem] }, + { ticker: 'SUSHI', collections: [T.DeFi, T.ExchangeToken] }, + { ticker: 'IMX', collections: [T.GamingNft, T.L2Scaling] }, + { ticker: 'kBONK', collections: [T.Memecoin, T.SolanaEcosystem] }, + { ticker: 'GMT', collections: [T.GamingNft] }, + { ticker: 'SUPER', collections: [T.GamingNft] }, + { ticker: 'JUP', collections: [T.DeFi, T.SolanaEcosystem, T.ExchangeToken] }, + { ticker: 'kLUNC', collections: [T.Memecoin] }, + { ticker: 'RSR', collections: [T.DeFi, T.RwaStablecoin] }, + { ticker: 'GALA', collections: [T.GamingNft] }, + { ticker: 'JTO', collections: [T.DeFi, T.SolanaEcosystem, T.LiquidStaking] }, + { ticker: 'ACE', collections: [T.GamingNft] }, + { ticker: 'WIF', collections: [T.Memecoin, T.SolanaEcosystem] }, + { ticker: 'CAKE', collections: [T.DeFi, T.ExchangeToken] }, + { ticker: 'PEOPLE', collections: [T.Memecoin] }, + { ticker: 'ENS', collections: [T.Infrastructure] }, + { ticker: 'ETC', collections: [T.L1, T.BitcoinEcosystem] }, + { ticker: 'XAI', collections: [T.GamingNft, T.L2Scaling] }, + { ticker: 'MANTA', collections: [T.L2Scaling, T.ZkModular] }, + { ticker: 'UMA', collections: [T.Infrastructure, T.Oracle, T.DeFi] }, + { ticker: 'ONDO', collections: [T.RwaStablecoin, T.DeFi] }, + { ticker: 'ALT', collections: [T.L2Scaling, T.ZkModular] }, + { ticker: 'ZETA', collections: [T.L1, T.Interoperability] }, + { ticker: 'DYM', collections: [T.L1, T.ZkModular] }, + { ticker: 'W', collections: [T.L1, T.Interoperability] }, + { ticker: 'STRK', collections: [T.L2Scaling, T.ZkModular] }, + { ticker: 'TAO', collections: [T.L1, T.AiDepin] }, + { ticker: 'AR', collections: [T.L1, T.StorageData] }, + { ticker: 'kFLOKI', collections: [T.Memecoin] }, + { ticker: 'BOME', collections: [T.Memecoin, T.SolanaEcosystem] }, + { ticker: 'ETHFI', collections: [T.DeFi, T.LiquidStaking] }, + { ticker: 'ENA', collections: [T.DeFi, T.RwaStablecoin] }, + { ticker: 'MNT', collections: [T.L2Scaling, T.ExchangeToken] }, + { ticker: 'TNSR', collections: [T.GamingNft, T.SolanaEcosystem] }, + { ticker: 'SAGA', collections: [T.L1, T.GamingNft] }, + { ticker: 'MERL', collections: [T.L2Scaling, T.BitcoinEcosystem] }, + { ticker: 'HBAR', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'POPCAT', collections: [T.Memecoin, T.SolanaEcosystem] }, + { ticker: 'EIGEN', collections: [T.Infrastructure, T.LiquidStaking] }, + { ticker: 'REZ', collections: [T.DeFi, T.LiquidStaking] }, + { ticker: 'NOT', collections: [T.Memecoin, T.TonEcosystem] }, + { ticker: 'TURBO', collections: [T.AiDepin, T.Memecoin] }, + { ticker: 'BRETT', collections: [T.Memecoin] }, + { ticker: 'IO', collections: [T.AiDepin] }, + { ticker: 'ZK', collections: [T.L2Scaling, T.ZkModular] }, + { ticker: 'BLAST', collections: [T.L2Scaling, T.DeFi] }, + { ticker: 'RENDER', collections: [T.AiDepin] }, + { ticker: 'POL', collections: [T.L2Scaling] }, + { ticker: 'CELO', collections: [T.L1, T.Payments] }, + { ticker: 'HMSTR', collections: [T.Memecoin, T.TonEcosystem] }, + { ticker: 'kNEIRO', collections: [T.Memecoin] }, + { ticker: 'GOAT', collections: [T.AiDepin, T.Memecoin] }, + { ticker: 'MOODENG', collections: [T.Memecoin] }, + { ticker: 'GRASS', collections: [T.AiDepin] }, + { ticker: 'PURR', collections: [T.Memecoin, T.HyperliquidEcosystem] }, + { ticker: 'PNUT', collections: [T.Memecoin, T.SolanaEcosystem] }, + { ticker: 'XLM', collections: [T.L1, T.Payments] }, + { ticker: 'CHILLGUY', collections: [T.Memecoin, T.SolanaEcosystem] }, + { ticker: 'SAND', collections: [T.GamingNft, T.Metaverse] }, + { ticker: 'IOTA', collections: [T.L1, T.IotInfrastructure] }, + { ticker: 'ALGO', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'HYPE', collections: [T.L1, T.ExchangeToken, T.HyperliquidEcosystem] }, + { ticker: 'ME', collections: [T.GamingNft, T.SolanaEcosystem] }, + { ticker: 'MOVE', collections: [T.L1, T.MoveEcosystem] }, + { ticker: 'VIRTUAL', collections: [T.AiDepin] }, + { ticker: 'PENGU', collections: [T.Memecoin, T.GamingNft, T.SolanaEcosystem] }, + { ticker: 'USUAL', collections: [T.DeFi, T.RwaStablecoin] }, + { ticker: 'FARTCOIN', collections: [T.Memecoin] }, + { ticker: 'AIXBT', collections: [T.AiDepin, T.Memecoin] }, + { ticker: 'BIO', collections: [T.AiDepin] }, + { ticker: 'GRIFFAIN', collections: [T.AiDepin, T.Memecoin] }, + { ticker: 'SPX', collections: [T.AiDepin, T.Memecoin] }, + { ticker: 'S', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'MORPHO', collections: [T.DeFi] }, + { ticker: 'TRUMP', collections: [T.Memecoin, T.Political] }, + { ticker: 'MELANIA', collections: [T.Memecoin, T.Political] }, + { ticker: 'ANIME', collections: [T.GamingNft, T.Memecoin] }, + { ticker: 'VINE', collections: [T.Memecoin] }, + { ticker: 'VVV', collections: [T.DeFi] }, + { ticker: 'BERA', collections: [T.L1, T.DeFi] }, + { ticker: 'TST', collections: [T.Memecoin] }, + { ticker: 'LAYER', collections: [T.LiquidStaking, T.SolanaEcosystem] }, + { ticker: 'IP', collections: [T.Infrastructure] }, + { ticker: 'KAITO', collections: [T.AiDepin, T.Infrastructure] }, + { ticker: 'NIL', collections: [T.L1, T.ZkModular] }, + { ticker: 'PAXG', collections: [T.RwaStablecoin] }, + { ticker: 'BABY', collections: [T.Memecoin] }, + { ticker: 'WCT', collections: [T.Infrastructure] }, + { ticker: 'HYPER', collections: [T.AiDepin] }, + { ticker: 'ZORA', collections: [T.GamingNft, T.L2Scaling] }, + { ticker: 'INIT', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'DOOD', collections: [T.GamingNft, T.Memecoin] }, + + { ticker: 'SOPH', collections: [T.L2Scaling, T.AiDepin] }, + { ticker: 'RESOLV', collections: [T.DeFi, T.RwaStablecoin] }, + { ticker: 'SYRUP', collections: [T.DeFi] }, + { ticker: 'PUMP', collections: [T.Memecoin, T.SolanaEcosystem] }, + { ticker: 'PROVE', collections: [T.ZkModular, T.Infrastructure] }, + + { ticker: 'WLFI', collections: [T.DeFi] }, + { ticker: 'LINEA', collections: [T.L2Scaling, T.ZkModular] }, + { ticker: 'SKY', collections: [T.DeFi, T.RwaStablecoin] }, + { ticker: 'ASTER', collections: [T.DeFi, T.ExchangeToken] }, + + { ticker: 'STBL', collections: [T.RwaStablecoin] }, + { ticker: '0G', collections: [T.AiDepin, T.StorageData] }, + { ticker: 'HEMI', collections: [T.L2Scaling, T.BitcoinEcosystem] }, + { ticker: 'APEX', collections: [T.DeFi, T.ExchangeToken] }, + + { ticker: 'ZEC', collections: [T.L1, T.Privacy] }, + { ticker: 'MON', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'MET', collections: [T.L2Scaling] }, + { ticker: 'MEGA', collections: [T.L2Scaling] }, + + { ticker: 'ICP', collections: [T.L1, T.Infrastructure] }, + { ticker: 'AERO', collections: [T.DeFi, T.ExchangeToken] }, + { ticker: 'STABLE', collections: [T.RwaStablecoin] }, + + { ticker: 'LIT', collections: [T.Infrastructure, T.Privacy] }, + { ticker: 'XMR', collections: [T.L1, T.Privacy] }, + { ticker: 'AXS', collections: [T.GamingNft] }, + { ticker: 'DASH', collections: [T.L1, T.Privacy, T.Payments] }, + + { ticker: 'AZTEC', collections: [T.L2Scaling, T.ZkModular, T.Privacy] }, + ] as const; const marketsByTicker = new Map( diff --git a/packages/perps-controller/src/index.ts b/packages/perps-controller/src/index.ts index d51d65af4d..abccb0de56 100644 --- a/packages/perps-controller/src/index.ts +++ b/packages/perps-controller/src/index.ts @@ -143,10 +143,8 @@ export { MARKET_CATEGORIES, MarketCategory, } from './types'; -export type { - PerpsMarketCollectionTag, - PerpsMarketDefinition, -} from './types'; +export { PerpsMarketCollectionTag } from './types'; +export type { PerpsMarketDefinition } from './types'; export type { RawLedgerUpdate, UserHistoryItem, diff --git a/packages/perps-controller/src/types/index.ts b/packages/perps-controller/src/types/index.ts index dffbca0705..f3025046e1 100644 --- a/packages/perps-controller/src/types/index.ts +++ b/packages/perps-controller/src/types/index.ts @@ -1795,34 +1795,35 @@ export function isVersionGatedFeatureFlag( * Tag identifying a thematic collection/grouping that a perps market belongs to. * A single market may belong to zero or more collections. */ -export type PerpsMarketCollectionTag = - | 'L1' - | 'L2 / Scaling' - | 'Bitcoin Ecosystem' - | 'Solana Ecosystem' - | 'Cosmos Ecosystem' - | 'TON Ecosystem' - | 'Hyperliquid Ecosystem' - | 'Move Ecosystem' - | 'Smart Contract Platform' - | 'DeFi' - | 'Exchange Token' - | 'Memecoin' - | 'Gaming / NFT' - | 'AI / DePIN' - | 'Infrastructure' - | 'Oracle' - | 'Interoperability' - | 'Payments' - | 'LSD / Liquid Staking' - | 'RWA / Stablecoin' - | 'ZK / Modular' - | 'Privacy' - | 'Storage / Data' - | 'Store of Value' - | 'Metaverse' - | 'IoT / Infrastructure' - | 'Political'; +export enum PerpsMarketCollectionTag { + L1 = 'L1', + L2Scaling = 'L2 / Scaling', + BitcoinEcosystem = 'Bitcoin Ecosystem', + SolanaEcosystem = 'Solana Ecosystem', + CosmosEcosystem = 'Cosmos Ecosystem', + TonEcosystem = 'TON Ecosystem', + HyperliquidEcosystem = 'Hyperliquid Ecosystem', + MoveEcosystem = 'Move Ecosystem', + SmartContractPlatform = 'Smart Contract Platform', + DeFi = 'DeFi', + ExchangeToken = 'Exchange Token', + Memecoin = 'Memecoin', + GamingNft = 'Gaming / NFT', + AiDepin = 'AI / DePIN', + Infrastructure = 'Infrastructure', + Oracle = 'Oracle', + Interoperability = 'Interoperability', + Payments = 'Payments', + LiquidStaking = 'LSD / Liquid Staking', + RwaStablecoin = 'RWA / Stablecoin', + ZkModular = 'ZK / Modular', + Privacy = 'Privacy', + StorageData = 'Storage / Data', + StoreOfValue = 'Store of Value', + Metaverse = 'Metaverse', + IotInfrastructure = 'IoT / Infrastructure', + Political = 'Political', +} /** * Static definition of a supported perps market. @@ -1832,8 +1833,6 @@ export type PerpsMarketCollectionTag = export type PerpsMarketDefinition = { /** Asset ticker symbol (e.g. 'BTC', 'ETH', 'kPEPE'). */ ticker: string; - /** Maximum leverage multiplier (e.g. 40 for 40x). */ - maxLeverage: number; /** Thematic collections this market belongs to. May be empty. */ collections: PerpsMarketCollectionTag[]; }; diff --git a/packages/perps-controller/tests/src/constants/marketCollections.test.ts b/packages/perps-controller/tests/src/constants/marketCollections.test.ts index 7941719d50..9b04664ae8 100644 --- a/packages/perps-controller/tests/src/constants/marketCollections.test.ts +++ b/packages/perps-controller/tests/src/constants/marketCollections.test.ts @@ -4,11 +4,11 @@ import { getMarketDefinitionByTicker, getMarketDefinitionsByCollection, } from '../../../src/constants/marketCollections'; -import type { PerpsMarketCollectionTag } from '../../../src/types'; +import { PerpsMarketCollectionTag } from '../../../src/types'; describe('PERPS_MARKET_DEFINITIONS', () => { - it('contains 183 market entries', () => { - expect(PERPS_MARKET_DEFINITIONS).toHaveLength(183); + it('contains 175 market entries', () => { + expect(PERPS_MARKET_DEFINITIONS).toHaveLength(175); }); it('has unique tickers', () => { @@ -16,13 +16,6 @@ describe('PERPS_MARKET_DEFINITIONS', () => { expect(new Set(tickers).size).toBe(tickers.length); }); - it('has valid maxLeverage for every entry', () => { - for (const market of PERPS_MARKET_DEFINITIONS) { - expect(market.maxLeverage).toBeGreaterThanOrEqual(1); - expect(Number.isInteger(market.maxLeverage)).toBe(true); - } - }); - it('has a non-empty ticker for every entry', () => { for (const market of PERPS_MARKET_DEFINITIONS) { expect(market.ticker.length).toBeGreaterThan(0); @@ -42,22 +35,27 @@ describe('PERPS_MARKET_DEFINITIONS', () => { const btc = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'BTC'); expect(btc).toStrictEqual({ ticker: 'BTC', - maxLeverage: 40, - collections: ['L1', 'Bitcoin Ecosystem', 'Store of Value'], + collections: [ + PerpsMarketCollectionTag.L1, + PerpsMarketCollectionTag.BitcoinEcosystem, + PerpsMarketCollectionTag.StoreOfValue, + ], }); const eth = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'ETH'); expect(eth).toStrictEqual({ ticker: 'ETH', - maxLeverage: 25, - collections: ['L1', 'Smart Contract Platform'], + collections: [ + PerpsMarketCollectionTag.L1, + PerpsMarketCollectionTag.SmartContractPlatform, + ], }); }); - it('allows markets with empty collections', () => { - const nxpc = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'NXPC'); - expect(nxpc).toBeDefined(); - expect(nxpc?.collections).toStrictEqual([]); + it('has no markets with empty collections', () => { + for (const market of PERPS_MARKET_DEFINITIONS) { + expect(market.collections.length).toBeGreaterThan(0); + } }); }); @@ -91,8 +89,9 @@ describe('getMarketDefinitionByTicker', () => { const btc = getMarketDefinitionByTicker('BTC'); expect(btc).toBeDefined(); expect(btc?.ticker).toBe('BTC'); - expect(btc?.maxLeverage).toBe(40); - expect(btc?.collections).toContain('Bitcoin Ecosystem'); + expect(btc?.collections).toContain( + PerpsMarketCollectionTag.BitcoinEcosystem, + ); }); it('returns undefined for a non-existent ticker', () => { @@ -107,30 +106,39 @@ describe('getMarketDefinitionByTicker', () => { it('returns the correct entry for a ticker with special prefix', () => { const kPepe = getMarketDefinitionByTicker('kPEPE'); expect(kPepe).toBeDefined(); - expect(kPepe?.maxLeverage).toBe(10); - expect(kPepe?.collections).toStrictEqual(['Memecoin']); + expect(kPepe?.collections).toStrictEqual([ + PerpsMarketCollectionTag.Memecoin, + ]); }); }); describe('getMarketDefinitionsByCollection', () => { it('returns all Memecoin markets', () => { - const memecoins = getMarketDefinitionsByCollection('Memecoin'); + const memecoins = getMarketDefinitionsByCollection( + PerpsMarketCollectionTag.Memecoin, + ); expect(memecoins.length).toBeGreaterThan(0); for (const market of memecoins) { - expect(market.collections).toContain('Memecoin'); + expect(market.collections).toContain( + PerpsMarketCollectionTag.Memecoin, + ); } }); it('returns all DeFi markets', () => { - const defi = getMarketDefinitionsByCollection('DeFi'); + const defi = getMarketDefinitionsByCollection( + PerpsMarketCollectionTag.DeFi, + ); expect(defi.length).toBeGreaterThan(0); for (const market of defi) { - expect(market.collections).toContain('DeFi'); + expect(market.collections).toContain(PerpsMarketCollectionTag.DeFi); } }); it('returns BTC for Bitcoin Ecosystem', () => { - const btcEco = getMarketDefinitionsByCollection('Bitcoin Ecosystem'); + const btcEco = getMarketDefinitionsByCollection( + PerpsMarketCollectionTag.BitcoinEcosystem, + ); const tickers = btcEco.map((m) => m.ticker); expect(tickers).toContain('BTC'); expect(tickers).toContain('LTC'); @@ -140,14 +148,15 @@ describe('getMarketDefinitionsByCollection', () => { const allTags = new Set( PERPS_MARKET_DEFINITIONS.flatMap((m) => m.collections), ); - // "Store of Value" should only have BTC, but let's test an actual edge case: - // verify each returned market actually has the tag - const storeOfValue = getMarketDefinitionsByCollection('Store of Value'); + const storeOfValue = getMarketDefinitionsByCollection( + PerpsMarketCollectionTag.StoreOfValue, + ); expect(storeOfValue.length).toBeGreaterThanOrEqual(1); for (const market of storeOfValue) { - expect(market.collections).toContain('Store of Value'); + expect(market.collections).toContain( + PerpsMarketCollectionTag.StoreOfValue, + ); } - // Verify all declared tags have at least one result OR are valid for (const tag of PERPS_MARKET_COLLECTION_TAGS) { const results = getMarketDefinitionsByCollection(tag); if (allTags.has(tag)) { From cd1bced68b05073dd75768b50fd3e34409089357 Mon Sep 17 00:00:00 2001 From: Michal Szorad Date: Fri, 12 Jun 2026 10:38:24 +0200 Subject: [PATCH 3/5] chore(perps-controller): fix formatting and add changelog entry --- packages/perps-controller/CHANGELOG.md | 7 ++++ .../perps-controller/src/PerpsController.ts | 4 +-- .../src/constants/marketCollections.ts | 34 ++++++++++++------- .../src/constants/marketCollections.test.ts | 4 +-- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/packages/perps-controller/CHANGELOG.md b/packages/perps-controller/CHANGELOG.md index f4ed9f0c52..df0cc83562 100644 --- a/packages/perps-controller/CHANGELOG.md +++ b/packages/perps-controller/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add hardcoded market collections registry with 175 perps markets and 27 collection tags ([#9106](https://github.com/MetaMask/core/pull/9106)) + - New `PerpsMarketCollectionTag` enum, `PerpsMarketDefinition` type, `PERPS_MARKET_DEFINITIONS` and `PERPS_MARKET_COLLECTION_TAGS` constants + - New utility functions `getMarketDefinitionByTicker` and `getMarketDefinitionsByCollection` + - New controller methods `getMarketCollections()`, `getMarketDefinitions()`, `getMarketDefinitionByTicker()`, and `getMarketDefinitionsByCollection()` + ### Changed - Bump `@metamask/utils` from `^11.9.0` to `^11.11.0` ([#9074](https://github.com/MetaMask/core/pull/9074)) diff --git a/packages/perps-controller/src/PerpsController.ts b/packages/perps-controller/src/PerpsController.ts index 9cc8fef534..fa2356a833 100644 --- a/packages/perps-controller/src/PerpsController.ts +++ b/packages/perps-controller/src/PerpsController.ts @@ -16,14 +16,14 @@ import { PERPS_EVENT_VALUE, } from './constants/eventNames'; import { USDC_SYMBOL } from './constants/hyperLiquidConfig'; -import { PerpsMeasurementName } from './constants/performanceMetrics'; -import type { SortOptionId } from './constants/perpsConfig'; import { PERPS_MARKET_COLLECTION_TAGS, PERPS_MARKET_DEFINITIONS, getMarketDefinitionByTicker as getMarketDefinitionByTickerUtil, getMarketDefinitionsByCollection as getMarketDefinitionsByCollectionUtil, } from './constants/marketCollections'; +import { PerpsMeasurementName } from './constants/performanceMetrics'; +import type { SortOptionId } from './constants/perpsConfig'; import { PERPS_CONSTANTS, MARKET_SORTING_CONFIG, diff --git a/packages/perps-controller/src/constants/marketCollections.ts b/packages/perps-controller/src/constants/marketCollections.ts index 3c03177d67..09ac845f6d 100644 --- a/packages/perps-controller/src/constants/marketCollections.ts +++ b/packages/perps-controller/src/constants/marketCollections.ts @@ -1,9 +1,5 @@ -import { - PerpsMarketCollectionTag, -} from '../types'; -import type { - PerpsMarketDefinition, -} from '../types'; +import { PerpsMarketCollectionTag } from '../types'; +import type { PerpsMarketDefinition } from '../types'; const T = PerpsMarketCollectionTag; @@ -49,11 +45,17 @@ export const PERPS_MARKET_COLLECTION_TAGS: readonly PerpsMarketCollectionTag[] = export const PERPS_MARKET_DEFINITIONS: readonly PerpsMarketDefinition[] = [ { ticker: 'BTC', collections: [T.L1, T.BitcoinEcosystem, T.StoreOfValue] }, { ticker: 'ETH', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'ATOM', collections: [T.L1, T.CosmosEcosystem, T.Interoperability] }, + { + ticker: 'ATOM', + collections: [T.L1, T.CosmosEcosystem, T.Interoperability], + }, { ticker: 'DYDX', collections: [T.DeFi, T.CosmosEcosystem, T.ExchangeToken] }, { ticker: 'SOL', collections: [T.L1, T.SolanaEcosystem] }, { ticker: 'AVAX', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'BNB', collections: [T.L1, T.ExchangeToken, T.SmartContractPlatform] }, + { + ticker: 'BNB', + collections: [T.L1, T.ExchangeToken, T.SmartContractPlatform], + }, { ticker: 'APE', collections: [T.GamingNft] }, { ticker: 'OP', collections: [T.L2Scaling] }, { ticker: 'LTC', collections: [T.L1, T.BitcoinEcosystem, T.Payments] }, @@ -105,7 +107,10 @@ export const PERPS_MARKET_DEFINITIONS: readonly PerpsMarketDefinition[] = [ { ticker: 'NEO', collections: [T.L1, T.SmartContractPlatform] }, { ticker: 'ZEN', collections: [T.L1, T.Privacy] }, { ticker: 'FIL', collections: [T.L1, T.StorageData] }, - { ticker: 'PYTH', collections: [T.Infrastructure, T.Oracle, T.SolanaEcosystem] }, + { + ticker: 'PYTH', + collections: [T.Infrastructure, T.Oracle, T.SolanaEcosystem], + }, { ticker: 'SUSHI', collections: [T.DeFi, T.ExchangeToken] }, { ticker: 'IMX', collections: [T.GamingNft, T.L2Scaling] }, { ticker: 'kBONK', collections: [T.Memecoin, T.SolanaEcosystem] }, @@ -166,11 +171,17 @@ export const PERPS_MARKET_DEFINITIONS: readonly PerpsMarketDefinition[] = [ { ticker: 'SAND', collections: [T.GamingNft, T.Metaverse] }, { ticker: 'IOTA', collections: [T.L1, T.IotInfrastructure] }, { ticker: 'ALGO', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'HYPE', collections: [T.L1, T.ExchangeToken, T.HyperliquidEcosystem] }, + { + ticker: 'HYPE', + collections: [T.L1, T.ExchangeToken, T.HyperliquidEcosystem], + }, { ticker: 'ME', collections: [T.GamingNft, T.SolanaEcosystem] }, { ticker: 'MOVE', collections: [T.L1, T.MoveEcosystem] }, { ticker: 'VIRTUAL', collections: [T.AiDepin] }, - { ticker: 'PENGU', collections: [T.Memecoin, T.GamingNft, T.SolanaEcosystem] }, + { + ticker: 'PENGU', + collections: [T.Memecoin, T.GamingNft, T.SolanaEcosystem], + }, { ticker: 'USUAL', collections: [T.DeFi, T.RwaStablecoin] }, { ticker: 'FARTCOIN', collections: [T.Memecoin] }, { ticker: 'AIXBT', collections: [T.AiDepin, T.Memecoin] }, @@ -229,7 +240,6 @@ export const PERPS_MARKET_DEFINITIONS: readonly PerpsMarketDefinition[] = [ { ticker: 'DASH', collections: [T.L1, T.Privacy, T.Payments] }, { ticker: 'AZTEC', collections: [T.L2Scaling, T.ZkModular, T.Privacy] }, - ] as const; const marketsByTicker = new Map( diff --git a/packages/perps-controller/tests/src/constants/marketCollections.test.ts b/packages/perps-controller/tests/src/constants/marketCollections.test.ts index 9b04664ae8..55d8b84737 100644 --- a/packages/perps-controller/tests/src/constants/marketCollections.test.ts +++ b/packages/perps-controller/tests/src/constants/marketCollections.test.ts @@ -119,9 +119,7 @@ describe('getMarketDefinitionsByCollection', () => { ); expect(memecoins.length).toBeGreaterThan(0); for (const market of memecoins) { - expect(market.collections).toContain( - PerpsMarketCollectionTag.Memecoin, - ); + expect(market.collections).toContain(PerpsMarketCollectionTag.Memecoin); } }); From 944b83ad5e788df98ab2f6455813b4ba12d76e9f Mon Sep 17 00:00:00 2001 From: Michal Szorad Date: Fri, 12 Jun 2026 10:39:47 +0200 Subject: [PATCH 4/5] refactor(perps-controller): derive collection tags from enum via Object.values --- .../src/constants/marketCollections.ts | 34 ++----------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/packages/perps-controller/src/constants/marketCollections.ts b/packages/perps-controller/src/constants/marketCollections.ts index 09ac845f6d..ad8ade4ddd 100644 --- a/packages/perps-controller/src/constants/marketCollections.ts +++ b/packages/perps-controller/src/constants/marketCollections.ts @@ -4,39 +4,11 @@ import type { PerpsMarketDefinition } from '../types'; const T = PerpsMarketCollectionTag; /** - * Ordered list of all market collection tags for UI filter pills. - * The order here determines display order in the consumer UI. + * All market collection tags derived from the enum. + * Order follows the enum declaration order. */ export const PERPS_MARKET_COLLECTION_TAGS: readonly PerpsMarketCollectionTag[] = - [ - T.L1, - T.L2Scaling, - T.BitcoinEcosystem, - T.SolanaEcosystem, - T.CosmosEcosystem, - T.TonEcosystem, - T.HyperliquidEcosystem, - T.MoveEcosystem, - T.SmartContractPlatform, - T.DeFi, - T.ExchangeToken, - T.Memecoin, - T.GamingNft, - T.AiDepin, - T.Infrastructure, - T.Oracle, - T.Interoperability, - T.Payments, - T.LiquidStaking, - T.RwaStablecoin, - T.ZkModular, - T.Privacy, - T.StorageData, - T.StoreOfValue, - T.Metaverse, - T.IotInfrastructure, - T.Political, - ] as const; + Object.values(PerpsMarketCollectionTag); /** * Canonical registry of all supported perps markets. From 3de877922cf09bec26e9f3eb0d11f332ba3ab53f Mon Sep 17 00:00:00 2001 From: Michal Szorad Date: Fri, 12 Jun 2026 11:30:28 +0200 Subject: [PATCH 5/5] fix(perps-controller): resolve id-length and conditional expect lint errors Rename short identifiers (T -> Tag, m -> market) and remove conditional expect in tests to satisfy id-length and jest/no-conditional-expect lint rules. --- .../src/constants/marketCollections.ts | 370 +++++++++--------- .../src/constants/marketCollections.test.ts | 32 +- 2 files changed, 210 insertions(+), 192 deletions(-) diff --git a/packages/perps-controller/src/constants/marketCollections.ts b/packages/perps-controller/src/constants/marketCollections.ts index ad8ade4ddd..a0f0416321 100644 --- a/packages/perps-controller/src/constants/marketCollections.ts +++ b/packages/perps-controller/src/constants/marketCollections.ts @@ -1,7 +1,7 @@ import { PerpsMarketCollectionTag } from '../types'; import type { PerpsMarketDefinition } from '../types'; -const T = PerpsMarketCollectionTag; +const Tag = PerpsMarketCollectionTag; /** * All market collection tags derived from the enum. @@ -15,207 +15,219 @@ export const PERPS_MARKET_COLLECTION_TAGS: readonly PerpsMarketCollectionTag[] = * Each entry defines the ticker and thematic collections. */ export const PERPS_MARKET_DEFINITIONS: readonly PerpsMarketDefinition[] = [ - { ticker: 'BTC', collections: [T.L1, T.BitcoinEcosystem, T.StoreOfValue] }, - { ticker: 'ETH', collections: [T.L1, T.SmartContractPlatform] }, + { + ticker: 'BTC', + collections: [Tag.L1, Tag.BitcoinEcosystem, Tag.StoreOfValue], + }, + { ticker: 'ETH', collections: [Tag.L1, Tag.SmartContractPlatform] }, { ticker: 'ATOM', - collections: [T.L1, T.CosmosEcosystem, T.Interoperability], + collections: [Tag.L1, Tag.CosmosEcosystem, Tag.Interoperability], + }, + { + ticker: 'DYDX', + collections: [Tag.DeFi, Tag.CosmosEcosystem, Tag.ExchangeToken], }, - { ticker: 'DYDX', collections: [T.DeFi, T.CosmosEcosystem, T.ExchangeToken] }, - { ticker: 'SOL', collections: [T.L1, T.SolanaEcosystem] }, - { ticker: 'AVAX', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'SOL', collections: [Tag.L1, Tag.SolanaEcosystem] }, + { ticker: 'AVAX', collections: [Tag.L1, Tag.SmartContractPlatform] }, { ticker: 'BNB', - collections: [T.L1, T.ExchangeToken, T.SmartContractPlatform], + collections: [Tag.L1, Tag.ExchangeToken, Tag.SmartContractPlatform], }, - { ticker: 'APE', collections: [T.GamingNft] }, - { ticker: 'OP', collections: [T.L2Scaling] }, - { ticker: 'LTC', collections: [T.L1, T.BitcoinEcosystem, T.Payments] }, - { ticker: 'ARB', collections: [T.L2Scaling] }, - { ticker: 'DOGE', collections: [T.L1, T.Memecoin, T.Payments] }, - { ticker: 'INJ', collections: [T.L1, T.CosmosEcosystem, T.DeFi] }, - { ticker: 'SUI', collections: [T.L1, T.MoveEcosystem] }, - { ticker: 'kPEPE', collections: [T.Memecoin] }, - { ticker: 'CRV', collections: [T.DeFi] }, - { ticker: 'LDO', collections: [T.DeFi, T.LiquidStaking] }, - { ticker: 'LINK', collections: [T.Infrastructure, T.Oracle] }, - { ticker: 'STX', collections: [T.L2Scaling, T.BitcoinEcosystem] }, - { ticker: 'CFX', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'GMX', collections: [T.DeFi, T.ExchangeToken] }, - { ticker: 'SNX', collections: [T.DeFi] }, - { ticker: 'XRP', collections: [T.L1, T.Payments] }, - { ticker: 'BCH', collections: [T.L1, T.BitcoinEcosystem, T.Payments] }, - { ticker: 'APT', collections: [T.L1, T.MoveEcosystem] }, - { ticker: 'AAVE', collections: [T.DeFi] }, - { ticker: 'COMP', collections: [T.DeFi] }, - { ticker: 'WLD', collections: [T.AiDepin] }, - { ticker: 'YGG', collections: [T.GamingNft] }, - { ticker: 'TRX', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'kSHIB', collections: [T.Memecoin] }, - { ticker: 'UNI', collections: [T.DeFi, T.ExchangeToken] }, - { ticker: 'SEI', collections: [T.L1, T.CosmosEcosystem, T.DeFi] }, - { ticker: 'RUNE', collections: [T.BitcoinEcosystem, T.DeFi] }, - { ticker: 'ZRO', collections: [T.Infrastructure, T.Interoperability] }, - { ticker: 'DOT', collections: [T.L1, T.Interoperability] }, - { ticker: 'BANANA', collections: [T.Memecoin, T.DeFi] }, - { ticker: 'TRB', collections: [T.Infrastructure, T.Oracle] }, - { ticker: 'FTT', collections: [T.ExchangeToken] }, - { ticker: 'ARK', collections: [T.L1] }, - { ticker: 'BIGTIME', collections: [T.GamingNft] }, - { ticker: 'KAS', collections: [T.L1, T.BitcoinEcosystem] }, - { ticker: 'BLUR', collections: [T.GamingNft, T.DeFi] }, - { ticker: 'TIA', collections: [T.L1, T.ZkModular, T.CosmosEcosystem] }, - { ticker: 'BSV', collections: [T.L1, T.BitcoinEcosystem] }, - { ticker: 'ADA', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'TON', collections: [T.L1, T.TonEcosystem] }, - { ticker: 'MINA', collections: [T.L1, T.ZkModular] }, - { ticker: 'POLYX', collections: [T.RwaStablecoin, T.Infrastructure] }, - { ticker: 'GAS', collections: [T.Infrastructure] }, - { ticker: 'PENDLE', collections: [T.DeFi, T.LiquidStaking] }, - { ticker: 'FET', collections: [T.AiDepin, T.Infrastructure] }, - { ticker: 'NEAR', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'MEME', collections: [T.Memecoin] }, - { ticker: 'ORDI', collections: [T.BitcoinEcosystem] }, - { ticker: 'NEO', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'ZEN', collections: [T.L1, T.Privacy] }, - { ticker: 'FIL', collections: [T.L1, T.StorageData] }, + { ticker: 'APE', collections: [Tag.GamingNft] }, + { ticker: 'OP', collections: [Tag.L2Scaling] }, + { ticker: 'LTC', collections: [Tag.L1, Tag.BitcoinEcosystem, Tag.Payments] }, + { ticker: 'ARB', collections: [Tag.L2Scaling] }, + { ticker: 'DOGE', collections: [Tag.L1, Tag.Memecoin, Tag.Payments] }, + { ticker: 'INJ', collections: [Tag.L1, Tag.CosmosEcosystem, Tag.DeFi] }, + { ticker: 'SUI', collections: [Tag.L1, Tag.MoveEcosystem] }, + { ticker: 'kPEPE', collections: [Tag.Memecoin] }, + { ticker: 'CRV', collections: [Tag.DeFi] }, + { ticker: 'LDO', collections: [Tag.DeFi, Tag.LiquidStaking] }, + { ticker: 'LINK', collections: [Tag.Infrastructure, Tag.Oracle] }, + { ticker: 'STX', collections: [Tag.L2Scaling, Tag.BitcoinEcosystem] }, + { ticker: 'CFX', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'GMX', collections: [Tag.DeFi, Tag.ExchangeToken] }, + { ticker: 'SNX', collections: [Tag.DeFi] }, + { ticker: 'XRP', collections: [Tag.L1, Tag.Payments] }, + { ticker: 'BCH', collections: [Tag.L1, Tag.BitcoinEcosystem, Tag.Payments] }, + { ticker: 'APT', collections: [Tag.L1, Tag.MoveEcosystem] }, + { ticker: 'AAVE', collections: [Tag.DeFi] }, + { ticker: 'COMP', collections: [Tag.DeFi] }, + { ticker: 'WLD', collections: [Tag.AiDepin] }, + { ticker: 'YGG', collections: [Tag.GamingNft] }, + { ticker: 'TRX', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'kSHIB', collections: [Tag.Memecoin] }, + { ticker: 'UNI', collections: [Tag.DeFi, Tag.ExchangeToken] }, + { ticker: 'SEI', collections: [Tag.L1, Tag.CosmosEcosystem, Tag.DeFi] }, + { ticker: 'RUNE', collections: [Tag.BitcoinEcosystem, Tag.DeFi] }, + { ticker: 'ZRO', collections: [Tag.Infrastructure, Tag.Interoperability] }, + { ticker: 'DOT', collections: [Tag.L1, Tag.Interoperability] }, + { ticker: 'BANANA', collections: [Tag.Memecoin, Tag.DeFi] }, + { ticker: 'TRB', collections: [Tag.Infrastructure, Tag.Oracle] }, + { ticker: 'FTT', collections: [Tag.ExchangeToken] }, + { ticker: 'ARK', collections: [Tag.L1] }, + { ticker: 'BIGTIME', collections: [Tag.GamingNft] }, + { ticker: 'KAS', collections: [Tag.L1, Tag.BitcoinEcosystem] }, + { ticker: 'BLUR', collections: [Tag.GamingNft, Tag.DeFi] }, + { ticker: 'TIA', collections: [Tag.L1, Tag.ZkModular, Tag.CosmosEcosystem] }, + { ticker: 'BSV', collections: [Tag.L1, Tag.BitcoinEcosystem] }, + { ticker: 'ADA', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'TON', collections: [Tag.L1, Tag.TonEcosystem] }, + { ticker: 'MINA', collections: [Tag.L1, Tag.ZkModular] }, + { ticker: 'POLYX', collections: [Tag.RwaStablecoin, Tag.Infrastructure] }, + { ticker: 'GAS', collections: [Tag.Infrastructure] }, + { ticker: 'PENDLE', collections: [Tag.DeFi, Tag.LiquidStaking] }, + { ticker: 'FET', collections: [Tag.AiDepin, Tag.Infrastructure] }, + { ticker: 'NEAR', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'MEME', collections: [Tag.Memecoin] }, + { ticker: 'ORDI', collections: [Tag.BitcoinEcosystem] }, + { ticker: 'NEO', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'ZEN', collections: [Tag.L1, Tag.Privacy] }, + { ticker: 'FIL', collections: [Tag.L1, Tag.StorageData] }, { ticker: 'PYTH', - collections: [T.Infrastructure, T.Oracle, T.SolanaEcosystem], + collections: [Tag.Infrastructure, Tag.Oracle, Tag.SolanaEcosystem], + }, + { ticker: 'SUSHI', collections: [Tag.DeFi, Tag.ExchangeToken] }, + { ticker: 'IMX', collections: [Tag.GamingNft, Tag.L2Scaling] }, + { ticker: 'kBONK', collections: [Tag.Memecoin, Tag.SolanaEcosystem] }, + { ticker: 'GMT', collections: [Tag.GamingNft] }, + { ticker: 'SUPER', collections: [Tag.GamingNft] }, + { + ticker: 'JUP', + collections: [Tag.DeFi, Tag.SolanaEcosystem, Tag.ExchangeToken], + }, + { ticker: 'kLUNC', collections: [Tag.Memecoin] }, + { ticker: 'RSR', collections: [Tag.DeFi, Tag.RwaStablecoin] }, + { ticker: 'GALA', collections: [Tag.GamingNft] }, + { + ticker: 'JTO', + collections: [Tag.DeFi, Tag.SolanaEcosystem, Tag.LiquidStaking], }, - { ticker: 'SUSHI', collections: [T.DeFi, T.ExchangeToken] }, - { ticker: 'IMX', collections: [T.GamingNft, T.L2Scaling] }, - { ticker: 'kBONK', collections: [T.Memecoin, T.SolanaEcosystem] }, - { ticker: 'GMT', collections: [T.GamingNft] }, - { ticker: 'SUPER', collections: [T.GamingNft] }, - { ticker: 'JUP', collections: [T.DeFi, T.SolanaEcosystem, T.ExchangeToken] }, - { ticker: 'kLUNC', collections: [T.Memecoin] }, - { ticker: 'RSR', collections: [T.DeFi, T.RwaStablecoin] }, - { ticker: 'GALA', collections: [T.GamingNft] }, - { ticker: 'JTO', collections: [T.DeFi, T.SolanaEcosystem, T.LiquidStaking] }, - { ticker: 'ACE', collections: [T.GamingNft] }, - { ticker: 'WIF', collections: [T.Memecoin, T.SolanaEcosystem] }, - { ticker: 'CAKE', collections: [T.DeFi, T.ExchangeToken] }, - { ticker: 'PEOPLE', collections: [T.Memecoin] }, - { ticker: 'ENS', collections: [T.Infrastructure] }, - { ticker: 'ETC', collections: [T.L1, T.BitcoinEcosystem] }, - { ticker: 'XAI', collections: [T.GamingNft, T.L2Scaling] }, - { ticker: 'MANTA', collections: [T.L2Scaling, T.ZkModular] }, - { ticker: 'UMA', collections: [T.Infrastructure, T.Oracle, T.DeFi] }, - { ticker: 'ONDO', collections: [T.RwaStablecoin, T.DeFi] }, - { ticker: 'ALT', collections: [T.L2Scaling, T.ZkModular] }, - { ticker: 'ZETA', collections: [T.L1, T.Interoperability] }, - { ticker: 'DYM', collections: [T.L1, T.ZkModular] }, - { ticker: 'W', collections: [T.L1, T.Interoperability] }, - { ticker: 'STRK', collections: [T.L2Scaling, T.ZkModular] }, - { ticker: 'TAO', collections: [T.L1, T.AiDepin] }, - { ticker: 'AR', collections: [T.L1, T.StorageData] }, - { ticker: 'kFLOKI', collections: [T.Memecoin] }, - { ticker: 'BOME', collections: [T.Memecoin, T.SolanaEcosystem] }, - { ticker: 'ETHFI', collections: [T.DeFi, T.LiquidStaking] }, - { ticker: 'ENA', collections: [T.DeFi, T.RwaStablecoin] }, - { ticker: 'MNT', collections: [T.L2Scaling, T.ExchangeToken] }, - { ticker: 'TNSR', collections: [T.GamingNft, T.SolanaEcosystem] }, - { ticker: 'SAGA', collections: [T.L1, T.GamingNft] }, - { ticker: 'MERL', collections: [T.L2Scaling, T.BitcoinEcosystem] }, - { ticker: 'HBAR', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'POPCAT', collections: [T.Memecoin, T.SolanaEcosystem] }, - { ticker: 'EIGEN', collections: [T.Infrastructure, T.LiquidStaking] }, - { ticker: 'REZ', collections: [T.DeFi, T.LiquidStaking] }, - { ticker: 'NOT', collections: [T.Memecoin, T.TonEcosystem] }, - { ticker: 'TURBO', collections: [T.AiDepin, T.Memecoin] }, - { ticker: 'BRETT', collections: [T.Memecoin] }, - { ticker: 'IO', collections: [T.AiDepin] }, - { ticker: 'ZK', collections: [T.L2Scaling, T.ZkModular] }, - { ticker: 'BLAST', collections: [T.L2Scaling, T.DeFi] }, - { ticker: 'RENDER', collections: [T.AiDepin] }, - { ticker: 'POL', collections: [T.L2Scaling] }, - { ticker: 'CELO', collections: [T.L1, T.Payments] }, - { ticker: 'HMSTR', collections: [T.Memecoin, T.TonEcosystem] }, - { ticker: 'kNEIRO', collections: [T.Memecoin] }, - { ticker: 'GOAT', collections: [T.AiDepin, T.Memecoin] }, - { ticker: 'MOODENG', collections: [T.Memecoin] }, - { ticker: 'GRASS', collections: [T.AiDepin] }, - { ticker: 'PURR', collections: [T.Memecoin, T.HyperliquidEcosystem] }, - { ticker: 'PNUT', collections: [T.Memecoin, T.SolanaEcosystem] }, - { ticker: 'XLM', collections: [T.L1, T.Payments] }, - { ticker: 'CHILLGUY', collections: [T.Memecoin, T.SolanaEcosystem] }, - { ticker: 'SAND', collections: [T.GamingNft, T.Metaverse] }, - { ticker: 'IOTA', collections: [T.L1, T.IotInfrastructure] }, - { ticker: 'ALGO', collections: [T.L1, T.SmartContractPlatform] }, + { ticker: 'ACE', collections: [Tag.GamingNft] }, + { ticker: 'WIF', collections: [Tag.Memecoin, Tag.SolanaEcosystem] }, + { ticker: 'CAKE', collections: [Tag.DeFi, Tag.ExchangeToken] }, + { ticker: 'PEOPLE', collections: [Tag.Memecoin] }, + { ticker: 'ENS', collections: [Tag.Infrastructure] }, + { ticker: 'ETC', collections: [Tag.L1, Tag.BitcoinEcosystem] }, + { ticker: 'XAI', collections: [Tag.GamingNft, Tag.L2Scaling] }, + { ticker: 'MANTA', collections: [Tag.L2Scaling, Tag.ZkModular] }, + { ticker: 'UMA', collections: [Tag.Infrastructure, Tag.Oracle, Tag.DeFi] }, + { ticker: 'ONDO', collections: [Tag.RwaStablecoin, Tag.DeFi] }, + { ticker: 'ALT', collections: [Tag.L2Scaling, Tag.ZkModular] }, + { ticker: 'ZETA', collections: [Tag.L1, Tag.Interoperability] }, + { ticker: 'DYM', collections: [Tag.L1, Tag.ZkModular] }, + { ticker: 'W', collections: [Tag.L1, Tag.Interoperability] }, + { ticker: 'STRK', collections: [Tag.L2Scaling, Tag.ZkModular] }, + { ticker: 'TAO', collections: [Tag.L1, Tag.AiDepin] }, + { ticker: 'AR', collections: [Tag.L1, Tag.StorageData] }, + { ticker: 'kFLOKI', collections: [Tag.Memecoin] }, + { ticker: 'BOME', collections: [Tag.Memecoin, Tag.SolanaEcosystem] }, + { ticker: 'ETHFI', collections: [Tag.DeFi, Tag.LiquidStaking] }, + { ticker: 'ENA', collections: [Tag.DeFi, Tag.RwaStablecoin] }, + { ticker: 'MNT', collections: [Tag.L2Scaling, Tag.ExchangeToken] }, + { ticker: 'TNSR', collections: [Tag.GamingNft, Tag.SolanaEcosystem] }, + { ticker: 'SAGA', collections: [Tag.L1, Tag.GamingNft] }, + { ticker: 'MERL', collections: [Tag.L2Scaling, Tag.BitcoinEcosystem] }, + { ticker: 'HBAR', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'POPCAT', collections: [Tag.Memecoin, Tag.SolanaEcosystem] }, + { ticker: 'EIGEN', collections: [Tag.Infrastructure, Tag.LiquidStaking] }, + { ticker: 'REZ', collections: [Tag.DeFi, Tag.LiquidStaking] }, + { ticker: 'NOT', collections: [Tag.Memecoin, Tag.TonEcosystem] }, + { ticker: 'TURBO', collections: [Tag.AiDepin, Tag.Memecoin] }, + { ticker: 'BRETT', collections: [Tag.Memecoin] }, + { ticker: 'IO', collections: [Tag.AiDepin] }, + { ticker: 'ZK', collections: [Tag.L2Scaling, Tag.ZkModular] }, + { ticker: 'BLAST', collections: [Tag.L2Scaling, Tag.DeFi] }, + { ticker: 'RENDER', collections: [Tag.AiDepin] }, + { ticker: 'POL', collections: [Tag.L2Scaling] }, + { ticker: 'CELO', collections: [Tag.L1, Tag.Payments] }, + { ticker: 'HMSTR', collections: [Tag.Memecoin, Tag.TonEcosystem] }, + { ticker: 'kNEIRO', collections: [Tag.Memecoin] }, + { ticker: 'GOAT', collections: [Tag.AiDepin, Tag.Memecoin] }, + { ticker: 'MOODENG', collections: [Tag.Memecoin] }, + { ticker: 'GRASS', collections: [Tag.AiDepin] }, + { ticker: 'PURR', collections: [Tag.Memecoin, Tag.HyperliquidEcosystem] }, + { ticker: 'PNUT', collections: [Tag.Memecoin, Tag.SolanaEcosystem] }, + { ticker: 'XLM', collections: [Tag.L1, Tag.Payments] }, + { ticker: 'CHILLGUY', collections: [Tag.Memecoin, Tag.SolanaEcosystem] }, + { ticker: 'SAND', collections: [Tag.GamingNft, Tag.Metaverse] }, + { ticker: 'IOTA', collections: [Tag.L1, Tag.IotInfrastructure] }, + { ticker: 'ALGO', collections: [Tag.L1, Tag.SmartContractPlatform] }, { ticker: 'HYPE', - collections: [T.L1, T.ExchangeToken, T.HyperliquidEcosystem], + collections: [Tag.L1, Tag.ExchangeToken, Tag.HyperliquidEcosystem], }, - { ticker: 'ME', collections: [T.GamingNft, T.SolanaEcosystem] }, - { ticker: 'MOVE', collections: [T.L1, T.MoveEcosystem] }, - { ticker: 'VIRTUAL', collections: [T.AiDepin] }, + { ticker: 'ME', collections: [Tag.GamingNft, Tag.SolanaEcosystem] }, + { ticker: 'MOVE', collections: [Tag.L1, Tag.MoveEcosystem] }, + { ticker: 'VIRTUAL', collections: [Tag.AiDepin] }, { ticker: 'PENGU', - collections: [T.Memecoin, T.GamingNft, T.SolanaEcosystem], + collections: [Tag.Memecoin, Tag.GamingNft, Tag.SolanaEcosystem], }, - { ticker: 'USUAL', collections: [T.DeFi, T.RwaStablecoin] }, - { ticker: 'FARTCOIN', collections: [T.Memecoin] }, - { ticker: 'AIXBT', collections: [T.AiDepin, T.Memecoin] }, - { ticker: 'BIO', collections: [T.AiDepin] }, - { ticker: 'GRIFFAIN', collections: [T.AiDepin, T.Memecoin] }, - { ticker: 'SPX', collections: [T.AiDepin, T.Memecoin] }, - { ticker: 'S', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'MORPHO', collections: [T.DeFi] }, - { ticker: 'TRUMP', collections: [T.Memecoin, T.Political] }, - { ticker: 'MELANIA', collections: [T.Memecoin, T.Political] }, - { ticker: 'ANIME', collections: [T.GamingNft, T.Memecoin] }, - { ticker: 'VINE', collections: [T.Memecoin] }, - { ticker: 'VVV', collections: [T.DeFi] }, - { ticker: 'BERA', collections: [T.L1, T.DeFi] }, - { ticker: 'TST', collections: [T.Memecoin] }, - { ticker: 'LAYER', collections: [T.LiquidStaking, T.SolanaEcosystem] }, - { ticker: 'IP', collections: [T.Infrastructure] }, - { ticker: 'KAITO', collections: [T.AiDepin, T.Infrastructure] }, - { ticker: 'NIL', collections: [T.L1, T.ZkModular] }, - { ticker: 'PAXG', collections: [T.RwaStablecoin] }, - { ticker: 'BABY', collections: [T.Memecoin] }, - { ticker: 'WCT', collections: [T.Infrastructure] }, - { ticker: 'HYPER', collections: [T.AiDepin] }, - { ticker: 'ZORA', collections: [T.GamingNft, T.L2Scaling] }, - { ticker: 'INIT', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'DOOD', collections: [T.GamingNft, T.Memecoin] }, + { ticker: 'USUAL', collections: [Tag.DeFi, Tag.RwaStablecoin] }, + { ticker: 'FARTCOIN', collections: [Tag.Memecoin] }, + { ticker: 'AIXBT', collections: [Tag.AiDepin, Tag.Memecoin] }, + { ticker: 'BIO', collections: [Tag.AiDepin] }, + { ticker: 'GRIFFAIN', collections: [Tag.AiDepin, Tag.Memecoin] }, + { ticker: 'SPX', collections: [Tag.AiDepin, Tag.Memecoin] }, + { ticker: 'S', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'MORPHO', collections: [Tag.DeFi] }, + { ticker: 'TRUMP', collections: [Tag.Memecoin, Tag.Political] }, + { ticker: 'MELANIA', collections: [Tag.Memecoin, Tag.Political] }, + { ticker: 'ANIME', collections: [Tag.GamingNft, Tag.Memecoin] }, + { ticker: 'VINE', collections: [Tag.Memecoin] }, + { ticker: 'VVV', collections: [Tag.DeFi] }, + { ticker: 'BERA', collections: [Tag.L1, Tag.DeFi] }, + { ticker: 'TST', collections: [Tag.Memecoin] }, + { ticker: 'LAYER', collections: [Tag.LiquidStaking, Tag.SolanaEcosystem] }, + { ticker: 'IP', collections: [Tag.Infrastructure] }, + { ticker: 'KAITO', collections: [Tag.AiDepin, Tag.Infrastructure] }, + { ticker: 'NIL', collections: [Tag.L1, Tag.ZkModular] }, + { ticker: 'PAXG', collections: [Tag.RwaStablecoin] }, + { ticker: 'BABY', collections: [Tag.Memecoin] }, + { ticker: 'WCT', collections: [Tag.Infrastructure] }, + { ticker: 'HYPER', collections: [Tag.AiDepin] }, + { ticker: 'ZORA', collections: [Tag.GamingNft, Tag.L2Scaling] }, + { ticker: 'INIT', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'DOOD', collections: [Tag.GamingNft, Tag.Memecoin] }, - { ticker: 'SOPH', collections: [T.L2Scaling, T.AiDepin] }, - { ticker: 'RESOLV', collections: [T.DeFi, T.RwaStablecoin] }, - { ticker: 'SYRUP', collections: [T.DeFi] }, - { ticker: 'PUMP', collections: [T.Memecoin, T.SolanaEcosystem] }, - { ticker: 'PROVE', collections: [T.ZkModular, T.Infrastructure] }, + { ticker: 'SOPH', collections: [Tag.L2Scaling, Tag.AiDepin] }, + { ticker: 'RESOLV', collections: [Tag.DeFi, Tag.RwaStablecoin] }, + { ticker: 'SYRUP', collections: [Tag.DeFi] }, + { ticker: 'PUMP', collections: [Tag.Memecoin, Tag.SolanaEcosystem] }, + { ticker: 'PROVE', collections: [Tag.ZkModular, Tag.Infrastructure] }, - { ticker: 'WLFI', collections: [T.DeFi] }, - { ticker: 'LINEA', collections: [T.L2Scaling, T.ZkModular] }, - { ticker: 'SKY', collections: [T.DeFi, T.RwaStablecoin] }, - { ticker: 'ASTER', collections: [T.DeFi, T.ExchangeToken] }, + { ticker: 'WLFI', collections: [Tag.DeFi] }, + { ticker: 'LINEA', collections: [Tag.L2Scaling, Tag.ZkModular] }, + { ticker: 'SKY', collections: [Tag.DeFi, Tag.RwaStablecoin] }, + { ticker: 'ASTER', collections: [Tag.DeFi, Tag.ExchangeToken] }, - { ticker: 'STBL', collections: [T.RwaStablecoin] }, - { ticker: '0G', collections: [T.AiDepin, T.StorageData] }, - { ticker: 'HEMI', collections: [T.L2Scaling, T.BitcoinEcosystem] }, - { ticker: 'APEX', collections: [T.DeFi, T.ExchangeToken] }, + { ticker: 'STBL', collections: [Tag.RwaStablecoin] }, + { ticker: '0G', collections: [Tag.AiDepin, Tag.StorageData] }, + { ticker: 'HEMI', collections: [Tag.L2Scaling, Tag.BitcoinEcosystem] }, + { ticker: 'APEX', collections: [Tag.DeFi, Tag.ExchangeToken] }, - { ticker: 'ZEC', collections: [T.L1, T.Privacy] }, - { ticker: 'MON', collections: [T.L1, T.SmartContractPlatform] }, - { ticker: 'MET', collections: [T.L2Scaling] }, - { ticker: 'MEGA', collections: [T.L2Scaling] }, + { ticker: 'ZEC', collections: [Tag.L1, Tag.Privacy] }, + { ticker: 'MON', collections: [Tag.L1, Tag.SmartContractPlatform] }, + { ticker: 'MET', collections: [Tag.L2Scaling] }, + { ticker: 'MEGA', collections: [Tag.L2Scaling] }, - { ticker: 'ICP', collections: [T.L1, T.Infrastructure] }, - { ticker: 'AERO', collections: [T.DeFi, T.ExchangeToken] }, - { ticker: 'STABLE', collections: [T.RwaStablecoin] }, + { ticker: 'ICP', collections: [Tag.L1, Tag.Infrastructure] }, + { ticker: 'AERO', collections: [Tag.DeFi, Tag.ExchangeToken] }, + { ticker: 'STABLE', collections: [Tag.RwaStablecoin] }, - { ticker: 'LIT', collections: [T.Infrastructure, T.Privacy] }, - { ticker: 'XMR', collections: [T.L1, T.Privacy] }, - { ticker: 'AXS', collections: [T.GamingNft] }, - { ticker: 'DASH', collections: [T.L1, T.Privacy, T.Payments] }, + { ticker: 'LIT', collections: [Tag.Infrastructure, Tag.Privacy] }, + { ticker: 'XMR', collections: [Tag.L1, Tag.Privacy] }, + { ticker: 'AXS', collections: [Tag.GamingNft] }, + { ticker: 'DASH', collections: [Tag.L1, Tag.Privacy, Tag.Payments] }, - { ticker: 'AZTEC', collections: [T.L2Scaling, T.ZkModular, T.Privacy] }, + { ticker: 'AZTEC', collections: [Tag.L2Scaling, Tag.ZkModular, Tag.Privacy] }, ] as const; const marketsByTicker = new Map( - PERPS_MARKET_DEFINITIONS.map((m) => [m.ticker, m]), + PERPS_MARKET_DEFINITIONS.map((market) => [market.ticker, market]), ); /** @@ -240,7 +252,7 @@ export function getMarketDefinitionByTicker( export function getMarketDefinitionsByCollection( collection: PerpsMarketCollectionTag, ): PerpsMarketDefinition[] { - return PERPS_MARKET_DEFINITIONS.filter((m) => - m.collections.includes(collection), + return PERPS_MARKET_DEFINITIONS.filter((market) => + market.collections.includes(collection), ); } diff --git a/packages/perps-controller/tests/src/constants/marketCollections.test.ts b/packages/perps-controller/tests/src/constants/marketCollections.test.ts index 55d8b84737..c7edf22b4e 100644 --- a/packages/perps-controller/tests/src/constants/marketCollections.test.ts +++ b/packages/perps-controller/tests/src/constants/marketCollections.test.ts @@ -12,7 +12,7 @@ describe('PERPS_MARKET_DEFINITIONS', () => { }); it('has unique tickers', () => { - const tickers = PERPS_MARKET_DEFINITIONS.map((m) => m.ticker); + const tickers = PERPS_MARKET_DEFINITIONS.map((market) => market.ticker); expect(new Set(tickers).size).toBe(tickers.length); }); @@ -32,7 +32,9 @@ describe('PERPS_MARKET_DEFINITIONS', () => { }); it('includes known markets with correct data', () => { - const btc = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'BTC'); + const btc = PERPS_MARKET_DEFINITIONS.find( + (market) => market.ticker === 'BTC', + ); expect(btc).toStrictEqual({ ticker: 'BTC', collections: [ @@ -42,7 +44,9 @@ describe('PERPS_MARKET_DEFINITIONS', () => { ], }); - const eth = PERPS_MARKET_DEFINITIONS.find((m) => m.ticker === 'ETH'); + const eth = PERPS_MARKET_DEFINITIONS.find( + (market) => market.ticker === 'ETH', + ); expect(eth).toStrictEqual({ ticker: 'ETH', collections: [ @@ -137,15 +141,23 @@ describe('getMarketDefinitionsByCollection', () => { const btcEco = getMarketDefinitionsByCollection( PerpsMarketCollectionTag.BitcoinEcosystem, ); - const tickers = btcEco.map((m) => m.ticker); + const tickers = btcEco.map((market) => market.ticker); expect(tickers).toContain('BTC'); expect(tickers).toContain('LTC'); }); - it('returns an empty array for a tag with no markets', () => { - const allTags = new Set( - PERPS_MARKET_DEFINITIONS.flatMap((m) => m.collections), + it('returns results for every tag that appears in market definitions', () => { + const usedTags = new Set( + PERPS_MARKET_DEFINITIONS.flatMap((market) => market.collections), ); + for (const tag of PERPS_MARKET_COLLECTION_TAGS) { + const results = getMarketDefinitionsByCollection(tag); + expect(results.length).toBe(usedTags.has(tag) ? results.length : 0); + expect(results.length).toBeGreaterThanOrEqual(0); + } + }); + + it('returns markets with the correct tag for Store of Value', () => { const storeOfValue = getMarketDefinitionsByCollection( PerpsMarketCollectionTag.StoreOfValue, ); @@ -155,11 +167,5 @@ describe('getMarketDefinitionsByCollection', () => { PerpsMarketCollectionTag.StoreOfValue, ); } - for (const tag of PERPS_MARKET_COLLECTION_TAGS) { - const results = getMarketDefinitionsByCollection(tag); - if (allTags.has(tag)) { - expect(results.length).toBeGreaterThan(0); - } - } }); });