@metamask-previews/perps-controller 15.1.0-preview-00a181c → 15.1.0-preview-a302de5c3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +0 -14
  2. package/dist/PerpsController-method-action-types.cjs.map +1 -1
  3. package/dist/PerpsController-method-action-types.d.cts +1 -20
  4. package/dist/PerpsController-method-action-types.d.cts.map +1 -1
  5. package/dist/PerpsController-method-action-types.d.mts +1 -20
  6. package/dist/PerpsController-method-action-types.d.mts.map +1 -1
  7. package/dist/PerpsController-method-action-types.mjs.map +1 -1
  8. package/dist/PerpsController.cjs +154 -65
  9. package/dist/PerpsController.cjs.map +1 -1
  10. package/dist/PerpsController.d.cts +43 -37
  11. package/dist/PerpsController.d.cts.map +1 -1
  12. package/dist/PerpsController.d.mts +43 -37
  13. package/dist/PerpsController.d.mts.map +1 -1
  14. package/dist/PerpsController.mjs +151 -64
  15. package/dist/PerpsController.mjs.map +1 -1
  16. package/dist/aggregation/SubscriptionMultiplexer.cjs +1 -1
  17. package/dist/aggregation/SubscriptionMultiplexer.cjs.map +1 -1
  18. package/dist/aggregation/SubscriptionMultiplexer.d.cts +1 -1
  19. package/dist/aggregation/SubscriptionMultiplexer.d.mts +1 -1
  20. package/dist/aggregation/SubscriptionMultiplexer.mjs +1 -1
  21. package/dist/aggregation/SubscriptionMultiplexer.mjs.map +1 -1
  22. package/dist/constants/index.cjs +1 -0
  23. package/dist/constants/index.cjs.map +1 -1
  24. package/dist/constants/index.d.cts +1 -0
  25. package/dist/constants/index.d.cts.map +1 -1
  26. package/dist/constants/index.d.mts +1 -0
  27. package/dist/constants/index.d.mts.map +1 -1
  28. package/dist/constants/index.mjs +1 -0
  29. package/dist/constants/index.mjs.map +1 -1
  30. package/dist/constants/myxConfig.cjs +253 -0
  31. package/dist/constants/myxConfig.cjs.map +1 -0
  32. package/dist/constants/myxConfig.d.cts +145 -0
  33. package/dist/constants/myxConfig.d.cts.map +1 -0
  34. package/dist/constants/myxConfig.d.mts +145 -0
  35. package/dist/constants/myxConfig.d.mts.map +1 -0
  36. package/dist/constants/myxConfig.mjs +243 -0
  37. package/dist/constants/myxConfig.mjs.map +1 -0
  38. package/dist/constants/perpsConfig.cjs +9 -4
  39. package/dist/constants/perpsConfig.cjs.map +1 -1
  40. package/dist/constants/perpsConfig.d.cts +5 -3
  41. package/dist/constants/perpsConfig.d.cts.map +1 -1
  42. package/dist/constants/perpsConfig.d.mts +5 -3
  43. package/dist/constants/perpsConfig.d.mts.map +1 -1
  44. package/dist/constants/perpsConfig.mjs +9 -4
  45. package/dist/constants/perpsConfig.mjs.map +1 -1
  46. package/dist/index.cjs +175 -146
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +2 -2
  49. package/dist/index.d.cts.map +1 -1
  50. package/dist/index.d.mts +2 -2
  51. package/dist/index.d.mts.map +1 -1
  52. package/dist/index.mjs +1 -0
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/providers/AggregatedPerpsProvider.cjs +2 -8
  55. package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
  56. package/dist/providers/AggregatedPerpsProvider.d.cts +2 -3
  57. package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
  58. package/dist/providers/AggregatedPerpsProvider.d.mts +2 -3
  59. package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
  60. package/dist/providers/AggregatedPerpsProvider.mjs +2 -8
  61. package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
  62. package/dist/providers/HyperLiquidProvider.cjs +22 -118
  63. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  64. package/dist/providers/HyperLiquidProvider.d.cts +0 -31
  65. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  66. package/dist/providers/HyperLiquidProvider.d.mts +0 -31
  67. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  68. package/dist/providers/HyperLiquidProvider.mjs +22 -118
  69. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  70. package/dist/providers/LighterProvider.cjs +1 -1
  71. package/dist/providers/LighterProvider.cjs.map +1 -1
  72. package/dist/providers/LighterProvider.mjs +1 -1
  73. package/dist/providers/LighterProvider.mjs.map +1 -1
  74. package/dist/routing/ProviderRouter.cjs +1 -1
  75. package/dist/routing/ProviderRouter.cjs.map +1 -1
  76. package/dist/routing/ProviderRouter.d.cts +1 -1
  77. package/dist/routing/ProviderRouter.d.mts +1 -1
  78. package/dist/routing/ProviderRouter.mjs +1 -1
  79. package/dist/routing/ProviderRouter.mjs.map +1 -1
  80. package/dist/services/HyperLiquidClientService.cjs.map +1 -1
  81. package/dist/services/HyperLiquidClientService.d.cts +16 -26
  82. package/dist/services/HyperLiquidClientService.d.cts.map +1 -1
  83. package/dist/services/HyperLiquidClientService.d.mts +16 -26
  84. package/dist/services/HyperLiquidClientService.d.mts.map +1 -1
  85. package/dist/services/HyperLiquidClientService.mjs.map +1 -1
  86. package/dist/services/HyperLiquidWalletService.cjs +30 -80
  87. package/dist/services/HyperLiquidWalletService.cjs.map +1 -1
  88. package/dist/services/HyperLiquidWalletService.d.cts +22 -48
  89. package/dist/services/HyperLiquidWalletService.d.cts.map +1 -1
  90. package/dist/services/HyperLiquidWalletService.d.mts +22 -48
  91. package/dist/services/HyperLiquidWalletService.d.mts.map +1 -1
  92. package/dist/services/HyperLiquidWalletService.mjs +30 -80
  93. package/dist/services/HyperLiquidWalletService.mjs.map +1 -1
  94. package/dist/services/LighterWalletService.cjs +1 -1
  95. package/dist/services/LighterWalletService.cjs.map +1 -1
  96. package/dist/services/LighterWalletService.d.cts +1 -1
  97. package/dist/services/LighterWalletService.d.mts +1 -1
  98. package/dist/services/LighterWalletService.mjs +1 -1
  99. package/dist/services/LighterWalletService.mjs.map +1 -1
  100. package/dist/types/index.cjs.map +1 -1
  101. package/dist/types/index.d.cts +16 -10
  102. package/dist/types/index.d.cts.map +1 -1
  103. package/dist/types/index.d.mts +16 -10
  104. package/dist/types/index.d.mts.map +1 -1
  105. package/dist/types/index.mjs.map +1 -1
  106. package/dist/types/myx-types.cjs +41 -0
  107. package/dist/types/myx-types.cjs.map +1 -0
  108. package/dist/types/myx-types.d.cts +94 -0
  109. package/dist/types/myx-types.d.cts.map +1 -0
  110. package/dist/types/myx-types.d.mts +94 -0
  111. package/dist/types/myx-types.d.mts.map +1 -0
  112. package/dist/types/myx-types.mjs +26 -0
  113. package/dist/types/myx-types.mjs.map +1 -0
  114. package/dist/utils/lighterAdapter.cjs +2 -1
  115. package/dist/utils/lighterAdapter.cjs.map +1 -1
  116. package/dist/utils/lighterAdapter.d.cts +2 -1
  117. package/dist/utils/lighterAdapter.d.cts.map +1 -1
  118. package/dist/utils/lighterAdapter.d.mts +2 -1
  119. package/dist/utils/lighterAdapter.d.mts.map +1 -1
  120. package/dist/utils/lighterAdapter.mjs +2 -1
  121. package/dist/utils/lighterAdapter.mjs.map +1 -1
  122. package/dist/utils/myxAdapter.cjs +569 -0
  123. package/dist/utils/myxAdapter.cjs.map +1 -0
  124. package/dist/utils/myxAdapter.d.cts +168 -0
  125. package/dist/utils/myxAdapter.d.cts.map +1 -0
  126. package/dist/utils/myxAdapter.d.mts +168 -0
  127. package/dist/utils/myxAdapter.d.mts.map +1 -0
  128. package/dist/utils/myxAdapter.mjs +548 -0
  129. package/dist/utils/myxAdapter.mjs.map +1 -0
  130. package/package.json +8 -2
@@ -0,0 +1,548 @@
1
+ /**
2
+ * MYX SDK Adapter Utilities
3
+ *
4
+ * Adapters for transforming between MetaMask Perps API types and MYX SDK types.
5
+ * Includes adapters for market display, positions, orders, account state, and fills.
6
+ *
7
+ * Portable: no mobile-specific imports.
8
+ * Formatters are injected via MarketDataFormatters interface (same pattern as marketDataTransform.ts).
9
+ *
10
+ * Key differences from HyperLiquid:
11
+ * - API prices are normal floats (SDK contract layer uses 30 decimals internally)
12
+ * - Sizes use 18 decimals (vs HyperLiquid's szDecimals per asset)
13
+ * - Multiple pools can exist per symbol (MPM model)
14
+ * - USDT collateral (vs USDC)
15
+ */
16
+ import { fromMYXPrice, fromMYXSize, fromMYXCollateral, MYX_MAX_LEVERAGE, MYX_MINIMUM_ORDER_SIZE_USD } from "../constants/myxConfig.mjs";
17
+ import { MYX_HL_OVERLAPPING_MARKETS, MYXDirection, MYXDirectionEnum, MYXOperationEnum, MYXOrderStatusEnum, MYXOrderTypeEnum, MYXExecTypeEnum, MYXTradeFlowTypeEnum } from "../types/myx-types.mjs";
18
+ /**
19
+ * Format a price change value with sign prefix.
20
+ * Uses injected formatters (same pattern as marketDataTransform.ts formatChange).
21
+ *
22
+ * @param change - The price change value to format.
23
+ * @param formatters - Injectable formatters for platform-agnostic formatting.
24
+ * @returns The formatted change string with sign and dollar symbol.
25
+ */
26
+ function formatChange(change, formatters) {
27
+ if (isNaN(change) || !isFinite(change)) {
28
+ return '$0.00';
29
+ }
30
+ if (change === 0) {
31
+ return '$0.00';
32
+ }
33
+ const formatted = formatters.formatPerpsFiat(Math.abs(change), {
34
+ ranges: formatters.priceRangesUniversal,
35
+ });
36
+ const valueWithoutDollar = formatted.replace('$', '');
37
+ return change > 0 ? `+$${valueWithoutDollar}` : `-$${valueWithoutDollar}`;
38
+ }
39
+ // ============================================================================
40
+ // Market Transformation
41
+ // ============================================================================
42
+ /**
43
+ * Transform MYX Pool/Market info to MetaMask Perps API MarketInfo format
44
+ *
45
+ * @param pool - Pool symbol data from MYX SDK (PoolSymbolAllResponse)
46
+ * @returns MetaMask Perps API market info object
47
+ */
48
+ export function adaptMarketFromMYX(pool) {
49
+ // Extract base symbol from pool data
50
+ const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);
51
+ // MYX uses fixed 18 decimals for sizes
52
+ const szDecimals = 18;
53
+ return {
54
+ name: symbol,
55
+ szDecimals,
56
+ maxLeverage: MYX_MAX_LEVERAGE,
57
+ marginTableId: 0, // MYX doesn't use margin tables like HyperLiquid
58
+ minimumOrderSize: MYX_MINIMUM_ORDER_SIZE_USD,
59
+ providerId: 'myx',
60
+ };
61
+ }
62
+ /**
63
+ * Convert MYX ticker data to price and change values
64
+ *
65
+ * @param ticker - Ticker data from MYX SDK
66
+ * @returns Object with price string and 24h change percentage
67
+ */
68
+ export function adaptPriceFromMYX(ticker) {
69
+ // MYX API returns normal float strings (e.g. "64854.76")
70
+ const priceNum = fromMYXPrice(ticker.price);
71
+ // Change is provided as a percentage string (e.g., "2.5" means 2.5%)
72
+ const change24h = ticker.change ? parseFloat(ticker.change) : 0;
73
+ return {
74
+ price: priceNum.toString(),
75
+ change24h,
76
+ };
77
+ }
78
+ /**
79
+ * Transform MYX pool and ticker to PerpsMarketData for UI display
80
+ *
81
+ * @param pool - Pool symbol data from MYX SDK
82
+ * @param ticker - Optional ticker data for price info
83
+ * @param formatters - Injectable formatters for platform-agnostic formatting
84
+ * @returns Formatted market data for UI display
85
+ */
86
+ export function adaptMarketDataFromMYX(pool, ticker, formatters) {
87
+ const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);
88
+ // Get price data from ticker if available
89
+ let price = '0';
90
+ let change24h = 0;
91
+ let volume = '0';
92
+ if (ticker) {
93
+ const priceData = adaptPriceFromMYX(ticker);
94
+ price = priceData.price;
95
+ change24h = priceData.change24h;
96
+ // Volume is already in USD (not 30-decimal format)
97
+ volume = ticker.volume || '0';
98
+ }
99
+ // Format using injected formatters (consistent with HyperLiquid via marketDataTransform.ts)
100
+ const priceNum = parseFloat(price);
101
+ const formattedPrice = formatters.formatPerpsFiat(priceNum);
102
+ const priceChange = priceNum * (change24h / 100);
103
+ const formattedChange = formatChange(priceChange, formatters);
104
+ const formattedChangePercent = formatters.formatPercentage(change24h);
105
+ const formattedVolume = formatters.formatVolume(parseFloat(volume));
106
+ return {
107
+ symbol,
108
+ name: getTokenName(symbol),
109
+ maxLeverage: `${MYX_MAX_LEVERAGE}x`,
110
+ price: formattedPrice,
111
+ change24h: formattedChange,
112
+ change24hPercent: formattedChangePercent,
113
+ volume: formattedVolume,
114
+ providerId: 'myx',
115
+ };
116
+ }
117
+ // ============================================================================
118
+ // Market Filtering
119
+ // ============================================================================
120
+ /**
121
+ * Filter MYX markets to only include MYX-exclusive markets
122
+ * Removes markets that overlap with HyperLiquid
123
+ *
124
+ * @param pools - Array of MYX pool symbols
125
+ * @returns Filtered array with only MYX-exclusive markets
126
+ */
127
+ export function filterMYXExclusiveMarkets(pools) {
128
+ return pools.filter((pool) => {
129
+ const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);
130
+ // Exclude markets that overlap with HyperLiquid
131
+ return !MYX_HL_OVERLAPPING_MARKETS.includes(symbol);
132
+ });
133
+ }
134
+ /**
135
+ * Check if a symbol overlaps with HyperLiquid markets
136
+ *
137
+ * @param symbol - Market symbol to check
138
+ * @returns true if the symbol is available on both MYX and HyperLiquid
139
+ */
140
+ export function isOverlappingMarket(symbol) {
141
+ return MYX_HL_OVERLAPPING_MARKETS.includes(symbol);
142
+ }
143
+ // ============================================================================
144
+ // Pool ID Utilities
145
+ // ============================================================================
146
+ /**
147
+ * Build a map of poolId to symbol for quick lookup
148
+ *
149
+ * @param pools - Array of MYX pool symbols
150
+ * @returns Map of poolId to symbol
151
+ */
152
+ export function buildPoolSymbolMap(pools) {
153
+ const map = new Map();
154
+ for (const pool of pools) {
155
+ const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);
156
+ map.set(pool.poolId, symbol);
157
+ }
158
+ return map;
159
+ }
160
+ /**
161
+ * Build a map of symbol to poolIds (for multi-pool support)
162
+ *
163
+ * @param pools - Array of MYX pool symbols
164
+ * @returns Map of symbol to array of poolIds
165
+ */
166
+ export function buildSymbolPoolsMap(pools) {
167
+ const map = new Map();
168
+ for (const pool of pools) {
169
+ const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);
170
+ const existing = map.get(symbol) ?? [];
171
+ existing.push(pool.poolId);
172
+ map.set(symbol, existing);
173
+ }
174
+ return map;
175
+ }
176
+ /**
177
+ * Extract symbol from pool ID
178
+ * Pool IDs typically contain the symbol as a suffix or can be parsed.
179
+ * When baseSymbol is unavailable, returns a truncated address for UI display.
180
+ *
181
+ * @param poolId - MYX pool ID string
182
+ * @returns Extracted symbol or truncated poolId as fallback
183
+ */
184
+ export function extractSymbolFromPoolId(poolId) {
185
+ // Pool IDs in MYX are hex addresses ("0x...")
186
+ // The actual symbol comes from the pool's baseSymbol field
187
+ // Truncate hex addresses so they're UI-friendly
188
+ if (poolId.startsWith('0x') && poolId.length > 10) {
189
+ return `${poolId.slice(0, 6)}...${poolId.slice(-4)}`;
190
+ }
191
+ return poolId;
192
+ }
193
+ /**
194
+ * Get full token name from symbol
195
+ * Returns the symbol as name if not found (MYX-specific tokens)
196
+ *
197
+ * @param symbol - The market symbol to look up.
198
+ * @returns The human-readable token name, or the symbol itself if not found.
199
+ */
200
+ function getTokenName(symbol) {
201
+ const tokenNames = {
202
+ BTC: 'Bitcoin',
203
+ ETH: 'Ethereum',
204
+ BNB: 'BNB',
205
+ MYX: 'MYX Protocol',
206
+ RHEA: 'Rhea Finance',
207
+ PARTI: 'Particle Network',
208
+ SKYAI: 'SkyAI',
209
+ PUMP: 'PumpFun',
210
+ WLFI: 'World Liberty Financial',
211
+ };
212
+ return tokenNames[symbol] || symbol;
213
+ }
214
+ // ============================================================================
215
+ // Position Adapter
216
+ // ============================================================================
217
+ /**
218
+ * Adapt MYX SDK PositionType to MetaMask Position
219
+ *
220
+ * @param pos - MYX position from SDK
221
+ * @param poolSymbolMap - Map of poolId to symbol
222
+ * @returns MetaMask Position object
223
+ */
224
+ export function adaptPositionFromMYX(pos, poolSymbolMap) {
225
+ const symbol = poolSymbolMap.get(pos.poolId) ?? pos.poolId;
226
+ const sizeNum = fromMYXSize(pos.size);
227
+ const entryPriceNum = fromMYXPrice(pos.entryPrice);
228
+ const collateralNum = fromMYXCollateral(pos.collateralAmount);
229
+ // Direction: 0 = LONG (positive size), 1 = SHORT (negative size)
230
+ const isLong = pos.direction === MYXDirection.LONG;
231
+ const signedSize = isLong ? sizeNum : -sizeNum;
232
+ // Position value = size * entry price
233
+ const positionValue = Math.abs(sizeNum * entryPriceNum);
234
+ // Leverage = position value / collateral (approximate)
235
+ const leverage = collateralNum > 0 ? positionValue / collateralNum : 1;
236
+ return {
237
+ symbol,
238
+ size: signedSize.toString(),
239
+ entryPrice: entryPriceNum.toString(),
240
+ positionValue: positionValue.toString(),
241
+ unrealizedPnl: '0', // Requires mark price - will be enriched by WS or separate call
242
+ marginUsed: collateralNum.toString(),
243
+ leverage: {
244
+ type: 'isolated',
245
+ value: Math.round(leverage),
246
+ rawUsd: collateralNum.toString(),
247
+ },
248
+ liquidationPrice: null, // Requires separate calculation
249
+ maxLeverage: MYX_MAX_LEVERAGE,
250
+ returnOnEquity: '0',
251
+ cumulativeFunding: {
252
+ allTime: '0',
253
+ sinceOpen: '0',
254
+ sinceChange: '0',
255
+ },
256
+ takeProfitPrice: undefined,
257
+ stopLossPrice: undefined,
258
+ takeProfitCount: 0,
259
+ stopLossCount: 0,
260
+ providerId: 'myx',
261
+ };
262
+ }
263
+ // ============================================================================
264
+ // Order Adapter
265
+ // ============================================================================
266
+ /**
267
+ * Adapt MYX SDK open order (PositionType-shaped from getOrders) to MetaMask Order.
268
+ * Note: getOrders returns PositionType[] per the SDK types.
269
+ * For richer order data, use getOrderHistory.
270
+ *
271
+ * @param historyOrder - MYX history order item
272
+ * @param poolSymbolMap - Map of poolId to symbol
273
+ * @returns MetaMask Order object
274
+ */
275
+ export function adaptOrderFromMYX(historyOrder, poolSymbolMap) {
276
+ const symbol = historyOrder.baseSymbol ??
277
+ poolSymbolMap.get(historyOrder.poolId) ??
278
+ historyOrder.poolId;
279
+ const priceNum = fromMYXPrice(historyOrder.price);
280
+ const sizeNum = fromMYXSize(historyOrder.size);
281
+ const filledSizeNum = fromMYXSize(historyOrder.filledSize);
282
+ const remainingSize = Math.max(0, sizeNum - filledSizeNum);
283
+ // Map direction
284
+ const side = historyOrder.direction === MYXDirectionEnum.Long ? 'buy' : 'sell';
285
+ // Map order type
286
+ let orderType = 'market';
287
+ if (historyOrder.orderType === MYXOrderTypeEnum.Limit) {
288
+ orderType = 'limit';
289
+ }
290
+ // Map status
291
+ let status = 'open';
292
+ switch (historyOrder.orderStatus) {
293
+ case MYXOrderStatusEnum.Successful:
294
+ status = 'filled';
295
+ break;
296
+ case MYXOrderStatusEnum.Cancelled:
297
+ status = 'canceled';
298
+ break;
299
+ case MYXOrderStatusEnum.Expired:
300
+ status = 'canceled';
301
+ break;
302
+ default:
303
+ status = 'open';
304
+ }
305
+ // Detect trigger orders
306
+ const isTrigger = historyOrder.execType === MYXExecTypeEnum.TP ||
307
+ historyOrder.execType === MYXExecTypeEnum.SL;
308
+ let detailedOrderType;
309
+ if (historyOrder.execType === MYXExecTypeEnum.TP) {
310
+ detailedOrderType = 'Take Profit';
311
+ }
312
+ else if (historyOrder.execType === MYXExecTypeEnum.SL) {
313
+ detailedOrderType = 'Stop Loss';
314
+ }
315
+ else if (historyOrder.execType === MYXExecTypeEnum.Liquidation) {
316
+ detailedOrderType = 'Liquidation';
317
+ }
318
+ return {
319
+ orderId: String(historyOrder.orderId),
320
+ symbol,
321
+ side,
322
+ orderType,
323
+ size: sizeNum.toString(),
324
+ originalSize: sizeNum.toString(),
325
+ price: priceNum.toString(),
326
+ filledSize: filledSizeNum.toString(),
327
+ remainingSize: remainingSize.toString(),
328
+ status,
329
+ timestamp: historyOrder.txTime,
330
+ isTrigger,
331
+ detailedOrderType,
332
+ reduceOnly: historyOrder.operation === MYXOperationEnum.Decrease ? true : undefined,
333
+ providerId: 'myx',
334
+ };
335
+ }
336
+ // ============================================================================
337
+ // Account State Adapter
338
+ // ============================================================================
339
+ /**
340
+ * Adapt MYX account info response to MetaMask AccountState.
341
+ *
342
+ * @param accountInfo - Raw account info from MYX SDK
343
+ * @param walletBalance - Wallet USDT balance (from getWalletQuoteTokenBalance)
344
+ * @returns MetaMask AccountState
345
+ */
346
+ export function adaptAccountStateFromMYX(accountInfo, walletBalance) {
347
+ // accountInfo structure varies; extract what we can
348
+ // TODO: Verify SDK semantics — if totalCollateral already includes unrealizedPnl,
349
+ // the totalBalance formula below double-counts. Needs SDK documentation check.
350
+ const rawCollateral = accountInfo?.totalCollateral ?? '0';
351
+ const rawPnl = accountInfo?.unrealizedPnl ?? '0';
352
+ const marginUsed = accountInfo ? fromMYXCollateral(String(rawCollateral)) : 0;
353
+ const unrealizedPnl = accountInfo ? fromMYXCollateral(String(rawPnl)) : 0;
354
+ const balance = walletBalance ? fromMYXCollateral(walletBalance) : 0;
355
+ const totalBalance = balance + marginUsed + unrealizedPnl;
356
+ return {
357
+ spendableBalance: balance.toString(),
358
+ withdrawableBalance: balance.toString(),
359
+ totalBalance: totalBalance.toString(),
360
+ marginUsed: marginUsed.toString(),
361
+ unrealizedPnl: unrealizedPnl.toString(),
362
+ returnOnEquity: '0',
363
+ };
364
+ }
365
+ // ============================================================================
366
+ // Order Fill Adapter
367
+ // ============================================================================
368
+ /**
369
+ * Adapt MYX history order item (filled) to MetaMask OrderFill
370
+ *
371
+ * @param order - MYX history order item
372
+ * @param poolSymbolMap - Map of poolId to symbol
373
+ * @returns MetaMask OrderFill
374
+ */
375
+ export function adaptOrderFillFromMYX(order, poolSymbolMap) {
376
+ const symbol = order.baseSymbol ?? poolSymbolMap.get(order.poolId) ?? order.poolId;
377
+ const sizeNum = fromMYXSize(order.filledSize || order.size);
378
+ const priceNum = fromMYXPrice(order.lastPrice || order.price);
379
+ const side = order.direction === MYXDirectionEnum.Long ? 'buy' : 'sell';
380
+ const feeNum = fromMYXCollateral(order.tradingFee || '0');
381
+ const pnlNum = fromMYXCollateral(order.realizedPnl || '0');
382
+ let orderType = 'regular';
383
+ if (order.execType === MYXExecTypeEnum.TP) {
384
+ orderType = 'take_profit';
385
+ }
386
+ else if (order.execType === MYXExecTypeEnum.SL) {
387
+ orderType = 'stop_loss';
388
+ }
389
+ else if (order.execType === MYXExecTypeEnum.Liquidation) {
390
+ orderType = 'liquidation';
391
+ }
392
+ return {
393
+ orderId: String(order.orderId),
394
+ symbol,
395
+ side,
396
+ size: sizeNum.toString(),
397
+ price: priceNum.toString(),
398
+ pnl: pnlNum.toString(),
399
+ direction: side,
400
+ fee: feeNum.toString(),
401
+ feeToken: 'USDT',
402
+ timestamp: order.txTime,
403
+ success: order.orderStatus === MYXOrderStatusEnum.Successful,
404
+ orderType,
405
+ providerId: 'myx',
406
+ };
407
+ }
408
+ // ============================================================================
409
+ // Funding Adapter
410
+ // ============================================================================
411
+ /**
412
+ * Adapt MYX trade flow items (funding type) to MetaMask Funding
413
+ *
414
+ * @param flows - MYX trade flow items filtered to funding type
415
+ * @param poolSymbolMap - Map of poolId to symbol
416
+ * @returns Array of MetaMask Funding objects
417
+ */
418
+ export function adaptFundingFromMYX(flows, poolSymbolMap) {
419
+ return flows
420
+ .filter((flow) => flow.fundingFee && flow.fundingFee !== '0' && flow.fundingFee !== '')
421
+ .map((flow) => {
422
+ const symbol = poolSymbolMap.get(flow.poolId) ?? flow.poolId;
423
+ const amountUsd = fromMYXCollateral(flow.fundingFee);
424
+ return {
425
+ symbol,
426
+ amountUsd: amountUsd.toString(),
427
+ rate: undefined, // Funding rate not available in MYX trade flow data
428
+ timestamp: flow.txTime,
429
+ transactionHash: flow.txHash,
430
+ };
431
+ });
432
+ }
433
+ // ============================================================================
434
+ // User History Adapter
435
+ // ============================================================================
436
+ /**
437
+ * Adapt MYX trade flow items to MetaMask UserHistoryItem
438
+ *
439
+ * @param flows - MYX trade flow items
440
+ * @returns Array of UserHistoryItem
441
+ */
442
+ export function adaptUserHistoryFromMYX(flows) {
443
+ return flows
444
+ .filter((flow) => flow.type === MYXTradeFlowTypeEnum.MarginAccountDeposit ||
445
+ flow.type === MYXTradeFlowTypeEnum.TransferToWallet)
446
+ .map((flow) => {
447
+ const isDeposit = flow.type === MYXTradeFlowTypeEnum.MarginAccountDeposit;
448
+ const amount = fromMYXCollateral(flow.collateralAmount || '0');
449
+ return {
450
+ id: String(flow.orderId),
451
+ timestamp: flow.txTime,
452
+ type: isDeposit ? 'deposit' : 'withdrawal',
453
+ amount: Math.abs(amount).toString(),
454
+ asset: 'USDT',
455
+ txHash: flow.txHash,
456
+ status: 'completed',
457
+ details: {
458
+ source: 'myx',
459
+ },
460
+ };
461
+ });
462
+ }
463
+ // ============================================================================
464
+ // Candle (Kline) Adapter
465
+ // ============================================================================
466
+ /**
467
+ * Adapt MYX KlineDataItemType to MetaMask CandleStick.
468
+ * KlineDataItemType fields (time, open, close, high, low) are already
469
+ * human-readable strings — no 30-decimal conversion needed.
470
+ *
471
+ * @param item - MYX kline data item from SDK
472
+ * @returns MetaMask CandleStick object
473
+ */
474
+ export function adaptCandleFromMYX(item) {
475
+ return {
476
+ time: item.time,
477
+ open: item.open,
478
+ high: item.high,
479
+ low: item.low,
480
+ close: item.close,
481
+ volume: '0', // KlineDataItemType has no volume field
482
+ };
483
+ }
484
+ /**
485
+ * Adapt MYX WebSocket KlineData to MetaMask CandleStick.
486
+ * WS KlineData uses single-letter fields: {t, o, h, l, c, v}.
487
+ *
488
+ * @param data - MYX WebSocket kline data
489
+ * @returns MetaMask CandleStick object
490
+ */
491
+ export function adaptCandleFromMYXWebSocket(data) {
492
+ return {
493
+ time: data.t,
494
+ open: data.o,
495
+ high: data.h,
496
+ low: data.l,
497
+ close: data.c,
498
+ volume: data.v,
499
+ };
500
+ }
501
+ /**
502
+ * Map CandlePeriod values to MYX KlineResolution.
503
+ * MYX SDK supports: '1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w', '1M'.
504
+ * Unsupported CandlePeriod values are mapped to the nearest supported resolution.
505
+ */
506
+ const CANDLE_PERIOD_TO_MYX_RESOLUTION = {
507
+ '1m': '1m',
508
+ '3m': '5m', // No 3m → use 5m
509
+ '5m': '5m',
510
+ '15m': '15m',
511
+ '30m': '30m',
512
+ '1h': '1h',
513
+ '2h': '4h', // No 2h → use 4h
514
+ '4h': '4h',
515
+ '8h': '4h', // No 8h → use 4h
516
+ '12h': '1d', // No 12h → use 1d
517
+ '1d': '1d',
518
+ '3d': '1w', // No 3d → use 1w
519
+ '1w': '1w',
520
+ '1M': '1M',
521
+ };
522
+ /**
523
+ * Convert a CandlePeriod string to MYX KlineResolution.
524
+ *
525
+ * @param period - CandlePeriod value (e.g., '1m', '3m', '1h')
526
+ * @returns MYX KlineResolution string
527
+ */
528
+ export function toMYXKlineResolution(period) {
529
+ return CANDLE_PERIOD_TO_MYX_RESOLUTION[period] ?? '1h';
530
+ }
531
+ // ============================================================================
532
+ // Response Validation
533
+ // ============================================================================
534
+ /**
535
+ * Assert MYX API response is successful.
536
+ * MYX uses code 9200 or 0 for success.
537
+ *
538
+ * @param response - MYX API response with code field
539
+ * @param response.code - Response code (9200 or 0 = success)
540
+ * @param response.message - Optional error message
541
+ * @param context - Context string for error messages
542
+ */
543
+ export function assertMYXSuccess(response, context) {
544
+ if (response.code !== 9200 && response.code !== 0) {
545
+ throw new Error(`MYX ${context} failed: code=${response.code} message=${response.message ?? 'unknown'}`);
546
+ }
547
+ }
548
+ //# sourceMappingURL=myxAdapter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"myxAdapter.mjs","sourceRoot":"","sources":["../../src/utils/myxAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MYX SDK Adapter Utilities\n *\n * Adapters for transforming between MetaMask Perps API types and MYX SDK types.\n * Includes adapters for market display, positions, orders, account state, and fills.\n *\n * Portable: no mobile-specific imports.\n * Formatters are injected via MarketDataFormatters interface (same pattern as marketDataTransform.ts).\n *\n * Key differences from HyperLiquid:\n * - API prices are normal floats (SDK contract layer uses 30 decimals internally)\n * - Sizes use 18 decimals (vs HyperLiquid's szDecimals per asset)\n * - Multiple pools can exist per symbol (MPM model)\n * - USDT collateral (vs USDC)\n */\n\nimport {\n fromMYXPrice,\n fromMYXSize,\n fromMYXCollateral,\n MYX_MAX_LEVERAGE,\n MYX_MINIMUM_ORDER_SIZE_USD,\n} from '../constants/myxConfig.js';\nimport type {\n AccountState,\n CandleStick,\n Funding,\n MarketInfo,\n Order,\n OrderFill,\n PerpsMarketData,\n Position,\n MarketDataFormatters,\n UserHistoryItem,\n} from '../types/index.js';\nimport {\n MYX_HL_OVERLAPPING_MARKETS,\n MYXDirection,\n MYXDirectionEnum,\n MYXOperationEnum,\n MYXOrderStatusEnum,\n MYXOrderTypeEnum,\n MYXExecTypeEnum,\n MYXTradeFlowTypeEnum,\n} from '../types/myx-types.js';\nimport type {\n MYXPoolSymbol,\n MYXTicker,\n MYXPositionType,\n MYXHistoryOrderItem,\n MYXTradeFlowItem,\n MYXKlineData,\n MYXKlineWsData,\n} from '../types/myx-types.js';\n\n/**\n * Format a price change value with sign prefix.\n * Uses injected formatters (same pattern as marketDataTransform.ts formatChange).\n *\n * @param change - The price change value to format.\n * @param formatters - Injectable formatters for platform-agnostic formatting.\n * @returns The formatted change string with sign and dollar symbol.\n */\nfunction formatChange(\n change: number,\n formatters: MarketDataFormatters,\n): string {\n if (isNaN(change) || !isFinite(change)) {\n return '$0.00';\n }\n if (change === 0) {\n return '$0.00';\n }\n\n const formatted = formatters.formatPerpsFiat(Math.abs(change), {\n ranges: formatters.priceRangesUniversal,\n });\n\n const valueWithoutDollar = formatted.replace('$', '');\n return change > 0 ? `+$${valueWithoutDollar}` : `-$${valueWithoutDollar}`;\n}\n\n// ============================================================================\n// Market Transformation\n// ============================================================================\n\n/**\n * Transform MYX Pool/Market info to MetaMask Perps API MarketInfo format\n *\n * @param pool - Pool symbol data from MYX SDK (PoolSymbolAllResponse)\n * @returns MetaMask Perps API market info object\n */\nexport function adaptMarketFromMYX(pool: MYXPoolSymbol): MarketInfo {\n // Extract base symbol from pool data\n const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);\n\n // MYX uses fixed 18 decimals for sizes\n const szDecimals = 18;\n\n return {\n name: symbol,\n szDecimals,\n maxLeverage: MYX_MAX_LEVERAGE,\n marginTableId: 0, // MYX doesn't use margin tables like HyperLiquid\n minimumOrderSize: MYX_MINIMUM_ORDER_SIZE_USD,\n providerId: 'myx',\n };\n}\n\n/**\n * Convert MYX ticker data to price and change values\n *\n * @param ticker - Ticker data from MYX SDK\n * @returns Object with price string and 24h change percentage\n */\nexport function adaptPriceFromMYX(ticker: MYXTicker): {\n price: string;\n change24h: number;\n} {\n // MYX API returns normal float strings (e.g. \"64854.76\")\n const priceNum = fromMYXPrice(ticker.price);\n\n // Change is provided as a percentage string (e.g., \"2.5\" means 2.5%)\n const change24h = ticker.change ? parseFloat(ticker.change) : 0;\n\n return {\n price: priceNum.toString(),\n change24h,\n };\n}\n\n/**\n * Transform MYX pool and ticker to PerpsMarketData for UI display\n *\n * @param pool - Pool symbol data from MYX SDK\n * @param ticker - Optional ticker data for price info\n * @param formatters - Injectable formatters for platform-agnostic formatting\n * @returns Formatted market data for UI display\n */\nexport function adaptMarketDataFromMYX(\n pool: MYXPoolSymbol,\n ticker: MYXTicker | undefined,\n formatters: MarketDataFormatters,\n): PerpsMarketData {\n const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);\n\n // Get price data from ticker if available\n let price = '0';\n let change24h = 0;\n let volume = '0';\n\n if (ticker) {\n const priceData = adaptPriceFromMYX(ticker);\n price = priceData.price;\n change24h = priceData.change24h;\n // Volume is already in USD (not 30-decimal format)\n volume = ticker.volume || '0';\n }\n\n // Format using injected formatters (consistent with HyperLiquid via marketDataTransform.ts)\n const priceNum = parseFloat(price);\n const formattedPrice = formatters.formatPerpsFiat(priceNum);\n const priceChange = priceNum * (change24h / 100);\n const formattedChange = formatChange(priceChange, formatters);\n const formattedChangePercent = formatters.formatPercentage(change24h);\n const formattedVolume = formatters.formatVolume(parseFloat(volume));\n\n return {\n symbol,\n name: getTokenName(symbol),\n maxLeverage: `${MYX_MAX_LEVERAGE}x`,\n price: formattedPrice,\n change24h: formattedChange,\n change24hPercent: formattedChangePercent,\n volume: formattedVolume,\n providerId: 'myx',\n };\n}\n\n// ============================================================================\n// Market Filtering\n// ============================================================================\n\n/**\n * Filter MYX markets to only include MYX-exclusive markets\n * Removes markets that overlap with HyperLiquid\n *\n * @param pools - Array of MYX pool symbols\n * @returns Filtered array with only MYX-exclusive markets\n */\nexport function filterMYXExclusiveMarkets(\n pools: MYXPoolSymbol[],\n): MYXPoolSymbol[] {\n return pools.filter((pool) => {\n const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);\n // Exclude markets that overlap with HyperLiquid\n return !MYX_HL_OVERLAPPING_MARKETS.includes(\n symbol as (typeof MYX_HL_OVERLAPPING_MARKETS)[number],\n );\n });\n}\n\n/**\n * Check if a symbol overlaps with HyperLiquid markets\n *\n * @param symbol - Market symbol to check\n * @returns true if the symbol is available on both MYX and HyperLiquid\n */\nexport function isOverlappingMarket(symbol: string): boolean {\n return MYX_HL_OVERLAPPING_MARKETS.includes(\n symbol as (typeof MYX_HL_OVERLAPPING_MARKETS)[number],\n );\n}\n\n// ============================================================================\n// Pool ID Utilities\n// ============================================================================\n\n/**\n * Build a map of poolId to symbol for quick lookup\n *\n * @param pools - Array of MYX pool symbols\n * @returns Map of poolId to symbol\n */\nexport function buildPoolSymbolMap(\n pools: MYXPoolSymbol[],\n): Map<string, string> {\n const map = new Map<string, string>();\n for (const pool of pools) {\n const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);\n map.set(pool.poolId, symbol);\n }\n return map;\n}\n\n/**\n * Build a map of symbol to poolIds (for multi-pool support)\n *\n * @param pools - Array of MYX pool symbols\n * @returns Map of symbol to array of poolIds\n */\nexport function buildSymbolPoolsMap(\n pools: MYXPoolSymbol[],\n): Map<string, string[]> {\n const map = new Map<string, string[]>();\n for (const pool of pools) {\n const symbol = pool.baseSymbol || extractSymbolFromPoolId(pool.poolId);\n const existing = map.get(symbol) ?? [];\n existing.push(pool.poolId);\n map.set(symbol, existing);\n }\n return map;\n}\n\n/**\n * Extract symbol from pool ID\n * Pool IDs typically contain the symbol as a suffix or can be parsed.\n * When baseSymbol is unavailable, returns a truncated address for UI display.\n *\n * @param poolId - MYX pool ID string\n * @returns Extracted symbol or truncated poolId as fallback\n */\nexport function extractSymbolFromPoolId(poolId: string): string {\n // Pool IDs in MYX are hex addresses (\"0x...\")\n // The actual symbol comes from the pool's baseSymbol field\n // Truncate hex addresses so they're UI-friendly\n if (poolId.startsWith('0x') && poolId.length > 10) {\n return `${poolId.slice(0, 6)}...${poolId.slice(-4)}`;\n }\n return poolId;\n}\n\n/**\n * Get full token name from symbol\n * Returns the symbol as name if not found (MYX-specific tokens)\n *\n * @param symbol - The market symbol to look up.\n * @returns The human-readable token name, or the symbol itself if not found.\n */\nfunction getTokenName(symbol: string): string {\n const tokenNames: Record<string, string> = {\n BTC: 'Bitcoin',\n ETH: 'Ethereum',\n BNB: 'BNB',\n MYX: 'MYX Protocol',\n RHEA: 'Rhea Finance',\n PARTI: 'Particle Network',\n SKYAI: 'SkyAI',\n PUMP: 'PumpFun',\n WLFI: 'World Liberty Financial',\n };\n\n return tokenNames[symbol] || symbol;\n}\n\n// ============================================================================\n// Position Adapter\n// ============================================================================\n\n/**\n * Adapt MYX SDK PositionType to MetaMask Position\n *\n * @param pos - MYX position from SDK\n * @param poolSymbolMap - Map of poolId to symbol\n * @returns MetaMask Position object\n */\nexport function adaptPositionFromMYX(\n pos: MYXPositionType,\n poolSymbolMap: Map<string, string>,\n): Position {\n const symbol = poolSymbolMap.get(pos.poolId) ?? pos.poolId;\n const sizeNum = fromMYXSize(pos.size);\n const entryPriceNum = fromMYXPrice(pos.entryPrice);\n const collateralNum = fromMYXCollateral(pos.collateralAmount);\n\n // Direction: 0 = LONG (positive size), 1 = SHORT (negative size)\n const isLong = pos.direction === MYXDirection.LONG;\n const signedSize = isLong ? sizeNum : -sizeNum;\n\n // Position value = size * entry price\n const positionValue = Math.abs(sizeNum * entryPriceNum);\n\n // Leverage = position value / collateral (approximate)\n const leverage = collateralNum > 0 ? positionValue / collateralNum : 1;\n\n return {\n symbol,\n size: signedSize.toString(),\n entryPrice: entryPriceNum.toString(),\n positionValue: positionValue.toString(),\n unrealizedPnl: '0', // Requires mark price - will be enriched by WS or separate call\n marginUsed: collateralNum.toString(),\n leverage: {\n type: 'isolated',\n value: Math.round(leverage),\n rawUsd: collateralNum.toString(),\n },\n liquidationPrice: null, // Requires separate calculation\n maxLeverage: MYX_MAX_LEVERAGE,\n returnOnEquity: '0',\n cumulativeFunding: {\n allTime: '0',\n sinceOpen: '0',\n sinceChange: '0',\n },\n takeProfitPrice: undefined,\n stopLossPrice: undefined,\n takeProfitCount: 0,\n stopLossCount: 0,\n providerId: 'myx',\n };\n}\n\n// ============================================================================\n// Order Adapter\n// ============================================================================\n\n/**\n * Adapt MYX SDK open order (PositionType-shaped from getOrders) to MetaMask Order.\n * Note: getOrders returns PositionType[] per the SDK types.\n * For richer order data, use getOrderHistory.\n *\n * @param historyOrder - MYX history order item\n * @param poolSymbolMap - Map of poolId to symbol\n * @returns MetaMask Order object\n */\nexport function adaptOrderFromMYX(\n historyOrder: MYXHistoryOrderItem,\n poolSymbolMap: Map<string, string>,\n): Order {\n const symbol =\n historyOrder.baseSymbol ??\n poolSymbolMap.get(historyOrder.poolId) ??\n historyOrder.poolId;\n\n const priceNum = fromMYXPrice(historyOrder.price);\n const sizeNum = fromMYXSize(historyOrder.size);\n const filledSizeNum = fromMYXSize(historyOrder.filledSize);\n const remainingSize = Math.max(0, sizeNum - filledSizeNum);\n\n // Map direction\n const side: 'buy' | 'sell' =\n historyOrder.direction === MYXDirectionEnum.Long ? 'buy' : 'sell';\n\n // Map order type\n let orderType: 'market' | 'limit' = 'market';\n if (historyOrder.orderType === MYXOrderTypeEnum.Limit) {\n orderType = 'limit';\n }\n\n // Map status\n let status: Order['status'] = 'open';\n switch (historyOrder.orderStatus) {\n case MYXOrderStatusEnum.Successful:\n status = 'filled';\n break;\n case MYXOrderStatusEnum.Cancelled:\n status = 'canceled';\n break;\n case MYXOrderStatusEnum.Expired:\n status = 'canceled';\n break;\n default:\n status = 'open';\n }\n\n // Detect trigger orders\n const isTrigger =\n historyOrder.execType === MYXExecTypeEnum.TP ||\n historyOrder.execType === MYXExecTypeEnum.SL;\n let detailedOrderType: string | undefined;\n if (historyOrder.execType === MYXExecTypeEnum.TP) {\n detailedOrderType = 'Take Profit';\n } else if (historyOrder.execType === MYXExecTypeEnum.SL) {\n detailedOrderType = 'Stop Loss';\n } else if (historyOrder.execType === MYXExecTypeEnum.Liquidation) {\n detailedOrderType = 'Liquidation';\n }\n\n return {\n orderId: String(historyOrder.orderId),\n symbol,\n side,\n orderType,\n size: sizeNum.toString(),\n originalSize: sizeNum.toString(),\n price: priceNum.toString(),\n filledSize: filledSizeNum.toString(),\n remainingSize: remainingSize.toString(),\n status,\n timestamp: historyOrder.txTime,\n isTrigger,\n detailedOrderType,\n reduceOnly:\n historyOrder.operation === MYXOperationEnum.Decrease ? true : undefined,\n providerId: 'myx',\n };\n}\n\n// ============================================================================\n// Account State Adapter\n// ============================================================================\n\n/**\n * Adapt MYX account info response to MetaMask AccountState.\n *\n * @param accountInfo - Raw account info from MYX SDK\n * @param walletBalance - Wallet USDT balance (from getWalletQuoteTokenBalance)\n * @returns MetaMask AccountState\n */\nexport function adaptAccountStateFromMYX(\n accountInfo: Record<string, unknown> | undefined,\n walletBalance?: string,\n): AccountState {\n // accountInfo structure varies; extract what we can\n // TODO: Verify SDK semantics — if totalCollateral already includes unrealizedPnl,\n // the totalBalance formula below double-counts. Needs SDK documentation check.\n const rawCollateral = accountInfo?.totalCollateral ?? '0';\n const rawPnl = accountInfo?.unrealizedPnl ?? '0';\n const marginUsed = accountInfo ? fromMYXCollateral(String(rawCollateral)) : 0;\n const unrealizedPnl = accountInfo ? fromMYXCollateral(String(rawPnl)) : 0;\n const balance = walletBalance ? fromMYXCollateral(walletBalance) : 0;\n\n const totalBalance = balance + marginUsed + unrealizedPnl;\n\n return {\n spendableBalance: balance.toString(),\n withdrawableBalance: balance.toString(),\n totalBalance: totalBalance.toString(),\n marginUsed: marginUsed.toString(),\n unrealizedPnl: unrealizedPnl.toString(),\n returnOnEquity: '0',\n };\n}\n\n// ============================================================================\n// Order Fill Adapter\n// ============================================================================\n\n/**\n * Adapt MYX history order item (filled) to MetaMask OrderFill\n *\n * @param order - MYX history order item\n * @param poolSymbolMap - Map of poolId to symbol\n * @returns MetaMask OrderFill\n */\nexport function adaptOrderFillFromMYX(\n order: MYXHistoryOrderItem,\n poolSymbolMap: Map<string, string>,\n): OrderFill {\n const symbol =\n order.baseSymbol ?? poolSymbolMap.get(order.poolId) ?? order.poolId;\n const sizeNum = fromMYXSize(order.filledSize || order.size);\n const priceNum = fromMYXPrice(order.lastPrice || order.price);\n const side = order.direction === MYXDirectionEnum.Long ? 'buy' : 'sell';\n const feeNum = fromMYXCollateral(order.tradingFee || '0');\n const pnlNum = fromMYXCollateral(order.realizedPnl || '0');\n\n let orderType: OrderFill['orderType'] = 'regular';\n if (order.execType === MYXExecTypeEnum.TP) {\n orderType = 'take_profit';\n } else if (order.execType === MYXExecTypeEnum.SL) {\n orderType = 'stop_loss';\n } else if (order.execType === MYXExecTypeEnum.Liquidation) {\n orderType = 'liquidation';\n }\n\n return {\n orderId: String(order.orderId),\n symbol,\n side,\n size: sizeNum.toString(),\n price: priceNum.toString(),\n pnl: pnlNum.toString(),\n direction: side,\n fee: feeNum.toString(),\n feeToken: 'USDT',\n timestamp: order.txTime,\n success: order.orderStatus === MYXOrderStatusEnum.Successful,\n orderType,\n providerId: 'myx',\n };\n}\n\n// ============================================================================\n// Funding Adapter\n// ============================================================================\n\n/**\n * Adapt MYX trade flow items (funding type) to MetaMask Funding\n *\n * @param flows - MYX trade flow items filtered to funding type\n * @param poolSymbolMap - Map of poolId to symbol\n * @returns Array of MetaMask Funding objects\n */\nexport function adaptFundingFromMYX(\n flows: MYXTradeFlowItem[],\n poolSymbolMap: Map<string, string>,\n): Funding[] {\n return flows\n .filter(\n (flow) =>\n flow.fundingFee && flow.fundingFee !== '0' && flow.fundingFee !== '',\n )\n .map((flow) => {\n const symbol = poolSymbolMap.get(flow.poolId) ?? flow.poolId;\n const amountUsd = fromMYXCollateral(flow.fundingFee);\n return {\n symbol,\n amountUsd: amountUsd.toString(),\n rate: undefined, // Funding rate not available in MYX trade flow data\n timestamp: flow.txTime,\n transactionHash: flow.txHash,\n };\n });\n}\n\n// ============================================================================\n// User History Adapter\n// ============================================================================\n\n/**\n * Adapt MYX trade flow items to MetaMask UserHistoryItem\n *\n * @param flows - MYX trade flow items\n * @returns Array of UserHistoryItem\n */\nexport function adaptUserHistoryFromMYX(\n flows: MYXTradeFlowItem[],\n): UserHistoryItem[] {\n return flows\n .filter(\n (flow) =>\n flow.type === MYXTradeFlowTypeEnum.MarginAccountDeposit ||\n flow.type === MYXTradeFlowTypeEnum.TransferToWallet,\n )\n .map((flow) => {\n const isDeposit = flow.type === MYXTradeFlowTypeEnum.MarginAccountDeposit;\n const amount = fromMYXCollateral(flow.collateralAmount || '0');\n return {\n id: String(flow.orderId),\n timestamp: flow.txTime,\n type: isDeposit ? 'deposit' : 'withdrawal',\n amount: Math.abs(amount).toString(),\n asset: 'USDT',\n txHash: flow.txHash,\n status: 'completed' as const,\n details: {\n source: 'myx',\n },\n };\n });\n}\n\n// ============================================================================\n// Candle (Kline) Adapter\n// ============================================================================\n\n/**\n * Adapt MYX KlineDataItemType to MetaMask CandleStick.\n * KlineDataItemType fields (time, open, close, high, low) are already\n * human-readable strings — no 30-decimal conversion needed.\n *\n * @param item - MYX kline data item from SDK\n * @returns MetaMask CandleStick object\n */\nexport function adaptCandleFromMYX(item: MYXKlineData): CandleStick {\n return {\n time: item.time,\n open: item.open,\n high: item.high,\n low: item.low,\n close: item.close,\n volume: '0', // KlineDataItemType has no volume field\n };\n}\n\n/**\n * Adapt MYX WebSocket KlineData to MetaMask CandleStick.\n * WS KlineData uses single-letter fields: {t, o, h, l, c, v}.\n *\n * @param data - MYX WebSocket kline data\n * @returns MetaMask CandleStick object\n */\nexport function adaptCandleFromMYXWebSocket(data: MYXKlineWsData): CandleStick {\n return {\n time: data.t,\n open: data.o,\n high: data.h,\n low: data.l,\n close: data.c,\n volume: data.v,\n };\n}\n\n/**\n * Map CandlePeriod values to MYX KlineResolution.\n * MYX SDK supports: '1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w', '1M'.\n * Unsupported CandlePeriod values are mapped to the nearest supported resolution.\n */\nconst CANDLE_PERIOD_TO_MYX_RESOLUTION: Record<string, string> = {\n '1m': '1m',\n '3m': '5m', // No 3m → use 5m\n '5m': '5m',\n '15m': '15m',\n '30m': '30m',\n '1h': '1h',\n '2h': '4h', // No 2h → use 4h\n '4h': '4h',\n '8h': '4h', // No 8h → use 4h\n '12h': '1d', // No 12h → use 1d\n '1d': '1d',\n '3d': '1w', // No 3d → use 1w\n '1w': '1w',\n '1M': '1M',\n};\n\n/**\n * Convert a CandlePeriod string to MYX KlineResolution.\n *\n * @param period - CandlePeriod value (e.g., '1m', '3m', '1h')\n * @returns MYX KlineResolution string\n */\nexport function toMYXKlineResolution(period: string): string {\n return CANDLE_PERIOD_TO_MYX_RESOLUTION[period] ?? '1h';\n}\n\n// ============================================================================\n// Response Validation\n// ============================================================================\n\n/**\n * Assert MYX API response is successful.\n * MYX uses code 9200 or 0 for success.\n *\n * @param response - MYX API response with code field\n * @param response.code - Response code (9200 or 0 = success)\n * @param response.message - Optional error message\n * @param context - Context string for error messages\n */\nexport function assertMYXSuccess(\n response: { code: number; message?: string | null },\n context: string,\n): void {\n if (response.code !== 9200 && response.code !== 0) {\n throw new Error(\n `MYX ${context} failed: code=${response.code} message=${response.message ?? 'unknown'}`,\n );\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/perps-controller",
3
- "version": "15.1.0-preview-00a181c",
3
+ "version": "15.1.0-preview-a302de5c3",
4
4
  "description": "Controller for perpetual trading functionality in MetaMask",
5
5
  "keywords": [
6
6
  "Ethereum",
@@ -16,7 +16,10 @@
16
16
  "url": "https://github.com/MetaMask/core.git"
17
17
  },
18
18
  "files": [
19
- "dist/"
19
+ "dist/",
20
+ "!dist/providers/MYXProvider*",
21
+ "!dist/services/MYXClientService*",
22
+ "!dist/services/MYXWalletService*"
20
23
  ],
21
24
  "sideEffects": false,
22
25
  "main": "./dist/index.cjs",
@@ -129,6 +132,9 @@
129
132
  "typescript": "~5.3.3",
130
133
  "viem": "^2.55.8"
131
134
  },
135
+ "optionalDependencies": {
136
+ "@myx-trade/sdk": "^0.1.265"
137
+ },
132
138
  "engines": {
133
139
  "node": "^18.18 || >=20"
134
140
  }