@metamask-previews/perps-controller 5.0.0-preview-bd0d4d2e9 → 5.0.0-preview-938a7fe

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12
12
  - **BREAKING:** Rename `AccountState.availableBalance` to `spendableBalance` and `AccountState.availableToTradeBalance` to `withdrawableBalance` for clearer semantics across abstraction modes ([#8678](https://github.com/MetaMask/core/pull/8678))
13
13
  - Mode-aware spot fold: `addSpotBalanceToAccountState` now folds free spot USDC into both `spendableBalance` and `withdrawableBalance` for Unified/Portfolio modes, while Standard/DEX-abstraction modes keep spot separate ([#8678](https://github.com/MetaMask/core/pull/8678))
14
14
  - Add throttled WS-driven `userAbstraction` refresh so HL-web mode flips propagate back without requiring a restart or account switch ([#8678](https://github.com/MetaMask/core/pull/8678))
15
+ - Fix position direction display for flipped positions ([#8707](https://github.com/MetaMask/core/pull/8707))
15
16
 
16
17
  ## [5.0.0]
17
18
 
@@ -283,6 +283,9 @@ class HyperLiquidProvider {
283
283
  * @returns A promise that resolves to the result.
284
284
  */
285
285
  async placeOrder(params, retryCount = 0) {
286
+ // Hoisted so the retry path in the catch block can use the fetched price
287
+ // even when the caller (e.g. flipPosition) omits currentPrice from params.
288
+ let effectivePrice;
286
289
  try {
287
290
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Placing order via HyperLiquid SDK:', params);
288
291
  // Basic sync validation (backward compatibility)
@@ -295,9 +298,37 @@ class HyperLiquidProvider {
295
298
  if (!validation.isValid) {
296
299
  throw new Error(validation.error);
297
300
  }
298
- // Validate order at provider level (enforces USD validation rules)
299
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_validateOrderBeforePlacement).call(this, params);
300
- // Ensure provider is ready for trading (includes signing operations)
301
+ // Extract DEX name for API calls (main DEX = null)
302
+ const { dex: dexName } = (0, hyperLiquidAdapter_1.parseAssetName)(params.symbol);
303
+ // 1. Get asset info and current price before validation so price-less
304
+ // callers (e.g. flipPosition) can validate against the live fetched price.
305
+ const { assetInfo, currentPrice, meta } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
306
+ symbol: params.symbol,
307
+ dexName,
308
+ });
309
+ // Allow override with UI-provided price (optimization to avoid API call).
310
+ effectivePrice =
311
+ params.currentPrice && params.currentPrice > 0
312
+ ? params.currentPrice
313
+ : currentPrice;
314
+ if (params.currentPrice && params.currentPrice > 0) {
315
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Using provided current price:', {
316
+ coin: params.symbol,
317
+ providedPrice: effectivePrice,
318
+ source: 'UI price feed',
319
+ });
320
+ }
321
+ // Validate order at provider level (enforces USD validation rules).
322
+ // Pass effectivePrice so price-less market orders (e.g. flipPosition)
323
+ // validate against the live fetched price instead of failing with
324
+ // ORDER_PRICE_REQUIRED.
325
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_validateOrderBeforePlacement).call(this, {
326
+ ...params,
327
+ currentPrice: effectivePrice,
328
+ });
329
+ // Ensure provider is ready for trading (includes signing operations).
330
+ // Kept after validation so invalid orders never trigger signature prompts
331
+ // (builder-fee approval, DEX abstraction enablement, etc.).
301
332
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
302
333
  // Debug: Log asset map state before order placement
303
334
  const allMapKeys = Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys());
@@ -313,24 +344,6 @@ class HyperLiquidProvider {
313
344
  allowlistMarkets: __classPrivateFieldGet(this, _HyperLiquidProvider_allowlistMarkets, "f"),
314
345
  blocklistMarkets: __classPrivateFieldGet(this, _HyperLiquidProvider_blocklistMarkets, "f"),
315
346
  });
316
- // Extract DEX name for API calls (main DEX = null)
317
- const { dex: dexName } = (0, hyperLiquidAdapter_1.parseAssetName)(params.symbol);
318
- // 1. Get asset info and current price
319
- const { assetInfo, currentPrice, meta } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
320
- symbol: params.symbol,
321
- dexName,
322
- });
323
- // Allow override with UI-provided price (optimization to avoid API call)
324
- const effectivePrice = params.currentPrice && params.currentPrice > 0
325
- ? params.currentPrice
326
- : currentPrice;
327
- if (params.currentPrice && params.currentPrice > 0) {
328
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Using provided current price:', {
329
- coin: params.symbol,
330
- providedPrice: effectivePrice,
331
- source: 'UI price feed',
332
- });
333
- }
334
347
  // 2. Calculate final position size with USD reconciliation
335
348
  const { finalPositionSize } = (0, orderCalculations_1.calculateFinalPositionSize)({
336
349
  usdAmount: params.usdAmount,
@@ -423,10 +436,13 @@ class HyperLiquidProvider {
423
436
  originalValue = params.usdAmount;
424
437
  adjustedUsdAmount = (parseFloat(params.usdAmount) * 1.015).toFixed(2);
425
438
  }
426
- else if (params.currentPrice) {
427
- // Size-based order: calculate USD from size and adjust
439
+ else if (effectivePrice) {
440
+ // Size-based order: calculate USD from size and adjust.
441
+ // Use the hoisted effectivePrice (fetched live price) so callers that
442
+ // omit currentPrice (e.g. flipPosition) can still recover from the
443
+ // $10-minimum edge case.
428
444
  const sizeValue = parseFloat(params.size);
429
- const estimatedUsd = sizeValue * params.currentPrice;
445
+ const estimatedUsd = sizeValue * effectivePrice;
430
446
  originalValue = `${estimatedUsd.toFixed(2)} (calculated from size ${params.size})`;
431
447
  adjustedUsdAmount = (estimatedUsd * 1.015).toFixed(2);
432
448
  }