@metamask-previews/perps-controller 4.0.0-preview-e0eba6dbb → 4.0.0-preview-56dd1249f

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 (64) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/constants/eventNames.cjs +5 -0
  3. package/dist/constants/eventNames.cjs.map +1 -1
  4. package/dist/constants/eventNames.d.cts +4 -0
  5. package/dist/constants/eventNames.d.cts.map +1 -1
  6. package/dist/constants/eventNames.d.mts +4 -0
  7. package/dist/constants/eventNames.d.mts.map +1 -1
  8. package/dist/constants/eventNames.mjs +5 -0
  9. package/dist/constants/eventNames.mjs.map +1 -1
  10. package/dist/providers/HyperLiquidProvider.cjs +230 -57
  11. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  12. package/dist/providers/HyperLiquidProvider.d.cts +1 -1
  13. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  14. package/dist/providers/HyperLiquidProvider.d.mts +1 -1
  15. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  16. package/dist/providers/HyperLiquidProvider.mjs +230 -57
  17. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  18. package/dist/services/HyperLiquidSubscriptionService.cjs +108 -20
  19. package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
  20. package/dist/services/HyperLiquidSubscriptionService.d.cts +19 -0
  21. package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
  22. package/dist/services/HyperLiquidSubscriptionService.d.mts +19 -0
  23. package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
  24. package/dist/services/HyperLiquidSubscriptionService.mjs +108 -20
  25. package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
  26. package/dist/services/HyperLiquidWalletService.cjs +20 -0
  27. package/dist/services/HyperLiquidWalletService.cjs.map +1 -1
  28. package/dist/services/HyperLiquidWalletService.d.cts +6 -0
  29. package/dist/services/HyperLiquidWalletService.d.cts.map +1 -1
  30. package/dist/services/HyperLiquidWalletService.d.mts +6 -0
  31. package/dist/services/HyperLiquidWalletService.d.mts.map +1 -1
  32. package/dist/services/HyperLiquidWalletService.mjs +22 -2
  33. package/dist/services/HyperLiquidWalletService.mjs.map +1 -1
  34. package/dist/services/TradingReadinessCache.cjs +16 -16
  35. package/dist/services/TradingReadinessCache.cjs.map +1 -1
  36. package/dist/services/TradingReadinessCache.d.cts +12 -12
  37. package/dist/services/TradingReadinessCache.d.mts +12 -12
  38. package/dist/services/TradingReadinessCache.mjs +16 -16
  39. package/dist/services/TradingReadinessCache.mjs.map +1 -1
  40. package/dist/types/hyperliquid-types.cjs +39 -0
  41. package/dist/types/hyperliquid-types.cjs.map +1 -1
  42. package/dist/types/hyperliquid-types.d.cts +34 -2
  43. package/dist/types/hyperliquid-types.d.cts.map +1 -1
  44. package/dist/types/hyperliquid-types.d.mts +34 -2
  45. package/dist/types/hyperliquid-types.d.mts.map +1 -1
  46. package/dist/types/hyperliquid-types.mjs +37 -1
  47. package/dist/types/hyperliquid-types.mjs.map +1 -1
  48. package/dist/types/index.cjs +1 -0
  49. package/dist/types/index.cjs.map +1 -1
  50. package/dist/types/index.d.cts +2 -1
  51. package/dist/types/index.d.cts.map +1 -1
  52. package/dist/types/index.d.mts +2 -1
  53. package/dist/types/index.d.mts.map +1 -1
  54. package/dist/types/index.mjs +1 -0
  55. package/dist/types/index.mjs.map +1 -1
  56. package/dist/utils/accountUtils.cjs +20 -8
  57. package/dist/utils/accountUtils.cjs.map +1 -1
  58. package/dist/utils/accountUtils.d.cts +9 -5
  59. package/dist/utils/accountUtils.d.cts.map +1 -1
  60. package/dist/utils/accountUtils.d.mts +9 -5
  61. package/dist/utils/accountUtils.d.mts.map +1 -1
  62. package/dist/utils/accountUtils.mjs +20 -8
  63. package/dist/utils/accountUtils.mjs.map +1 -1
  64. package/package.json +3 -3
@@ -9,9 +9,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _HyperLiquidProvider_instances, _HyperLiquidProvider_deps, _HyperLiquidProvider_clientService, _HyperLiquidProvider_walletService, _HyperLiquidProvider_subscriptionService, _HyperLiquidProvider_symbolToAssetId, _HyperLiquidProvider_userFeeCache, _HyperLiquidProvider_maxLeverageCache, _HyperLiquidProvider_cachedMetaByDex, _HyperLiquidProvider_cachedMarketDataWithPrices, _HyperLiquidProvider_cachedSpotMeta, _HyperLiquidProvider_dexDiscoveryCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_hip3Enabled, _HyperLiquidProvider_allowlistMarkets, _HyperLiquidProvider_blocklistMarkets, _HyperLiquidProvider_useDexAbstraction, _HyperLiquidProvider_dexDiscoveryComplete, _HyperLiquidProvider_pendingValidatedDexsPromise, _HyperLiquidProvider_cachedUsdcTokenId, _HyperLiquidProvider_errorMappings, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_builderAddressTestnet, _HyperLiquidProvider_builderAddressMainnet, _HyperLiquidProvider_compilePatternsSafely, _HyperLiquidProvider_ensureClientsInitialized, _HyperLiquidProvider_ensureDexAbstractionEnabled, _HyperLiquidProvider_ensureReady, _HyperLiquidProvider_tradingSetupPromise, _HyperLiquidProvider_tradingSetupComplete, _HyperLiquidProvider_ensureReadyForTrading, _HyperLiquidProvider_getOrFetchPrice, _HyperLiquidProvider_filterFills, _HyperLiquidProvider_getAllAvailableDexs, _HyperLiquidProvider_getValidatedDexs, _HyperLiquidProvider_fetchValidatedDexsInternal, _HyperLiquidProvider_getCachedMeta, _HyperLiquidProvider_backfillAssetMapForDex, _HyperLiquidProvider_getAssetIdWithRepair, _HyperLiquidProvider_getCachedSpotMeta, _HyperLiquidProvider_getCachedPerpDexs, _HyperLiquidProvider_calculateHip3FeeMultiplier, _HyperLiquidProvider_getCacheKey, _HyperLiquidProvider_fetchMarketsForDex, _HyperLiquidProvider_getUsdcTokenId, _HyperLiquidProvider_isUsdhCollateralDex, _HyperLiquidProvider_getSpotUsdhBalance, _HyperLiquidProvider_getSpotUsdcBalance, _HyperLiquidProvider_transferUsdcToSpot, _HyperLiquidProvider_swapUsdcToUsdh, _HyperLiquidProvider_ensureUsdhCollateralForOrder, _HyperLiquidProvider_buildAssetMapping, _HyperLiquidProvider_queryUserDataAcrossDexs, _HyperLiquidProvider_mapError, _HyperLiquidProvider_getErrorContext, _HyperLiquidProvider_checkBuilderFeeApproval, _HyperLiquidProvider_ensureBuilderFeeApproval, _HyperLiquidProvider_checkBuilderFeeStatus, _HyperLiquidProvider_getBalanceForDex, _HyperLiquidProvider_findSourceDexWithBalance, _HyperLiquidProvider_autoTransferForHip3Order, _HyperLiquidProvider_autoTransferBackAfterClose, _HyperLiquidProvider_calculateHip3RequiredMargin, _HyperLiquidProvider_handleHip3PostOrderRebalance, _HyperLiquidProvider_handleHip3OrderRollback, _HyperLiquidProvider_validateOrderBeforePlacement, _HyperLiquidProvider_getAssetInfo, _HyperLiquidProvider_prepareAssetForTrading, _HyperLiquidProvider_handleHip3PreOrder, _HyperLiquidProvider_submitOrderWithRollback, _HyperLiquidProvider_handleOrderError, _HyperLiquidProvider_getStandaloneValidatedDexs, _HyperLiquidProvider_getAllMids, _HyperLiquidProvider_fetchSingleDexFresh, _HyperLiquidProvider_mergeDexResultsInto, _HyperLiquidProvider_cacheFreshMarketDataSnapshot, _HyperLiquidProvider_getStaleMarketDataSnapshot, _HyperLiquidProvider_isFeeCacheValid, _HyperLiquidProvider_getBuilderAddress, _HyperLiquidProvider_getReferralCode, _HyperLiquidProvider_ensureReferralSet, _HyperLiquidProvider_isReferralCodeReady, _HyperLiquidProvider_checkReferralSet, _HyperLiquidProvider_setReferralCode;
12
+ var _HyperLiquidProvider_instances, _HyperLiquidProvider_deps, _HyperLiquidProvider_clientService, _HyperLiquidProvider_walletService, _HyperLiquidProvider_subscriptionService, _HyperLiquidProvider_symbolToAssetId, _HyperLiquidProvider_userFeeCache, _HyperLiquidProvider_maxLeverageCache, _HyperLiquidProvider_cachedMetaByDex, _HyperLiquidProvider_cachedMarketDataWithPrices, _HyperLiquidProvider_cachedSpotMeta, _HyperLiquidProvider_dexDiscoveryCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_hip3Enabled, _HyperLiquidProvider_allowlistMarkets, _HyperLiquidProvider_blocklistMarkets, _HyperLiquidProvider_useUnifiedAccount, _HyperLiquidProvider_dexDiscoveryComplete, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, _HyperLiquidProvider_pendingValidatedDexsPromise, _HyperLiquidProvider_cachedUsdcTokenId, _HyperLiquidProvider_errorMappings, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_builderAddressTestnet, _HyperLiquidProvider_builderAddressMainnet, _HyperLiquidProvider_compilePatternsSafely, _HyperLiquidProvider_ensureClientsInitialized, _HyperLiquidProvider_ensureUnifiedAccountEnabled, _HyperLiquidProvider_ensureReady, _HyperLiquidProvider_tradingSetupPromise, _HyperLiquidProvider_tradingSetupComplete, _HyperLiquidProvider_ensureReadyForTrading, _HyperLiquidProvider_getOrFetchPrice, _HyperLiquidProvider_filterFills, _HyperLiquidProvider_getAllAvailableDexs, _HyperLiquidProvider_getValidatedDexs, _HyperLiquidProvider_fetchValidatedDexsInternal, _HyperLiquidProvider_getCachedMeta, _HyperLiquidProvider_backfillAssetMapForDex, _HyperLiquidProvider_getAssetIdWithRepair, _HyperLiquidProvider_getCachedSpotMeta, _HyperLiquidProvider_getCachedPerpDexs, _HyperLiquidProvider_calculateHip3FeeMultiplier, _HyperLiquidProvider_getCacheKey, _HyperLiquidProvider_fetchMarketsForDex, _HyperLiquidProvider_getUsdcTokenId, _HyperLiquidProvider_isUsdhCollateralDex, _HyperLiquidProvider_getSpotUsdhBalance, _HyperLiquidProvider_getSpotUsdcBalance, _HyperLiquidProvider_transferUsdcToSpot, _HyperLiquidProvider_swapUsdcToUsdh, _HyperLiquidProvider_ensureUsdhCollateralForOrder, _HyperLiquidProvider_buildAssetMapping, _HyperLiquidProvider_queryUserDataAcrossDexs, _HyperLiquidProvider_mapError, _HyperLiquidProvider_getErrorContext, _HyperLiquidProvider_checkBuilderFeeApproval, _HyperLiquidProvider_ensureBuilderFeeApproval, _HyperLiquidProvider_checkBuilderFeeStatus, _HyperLiquidProvider_getBalanceForDex, _HyperLiquidProvider_findSourceDexWithBalance, _HyperLiquidProvider_autoTransferForHip3Order, _HyperLiquidProvider_autoTransferBackAfterClose, _HyperLiquidProvider_calculateHip3RequiredMargin, _HyperLiquidProvider_handleHip3PostOrderRebalance, _HyperLiquidProvider_handleHip3OrderRollback, _HyperLiquidProvider_validateOrderBeforePlacement, _HyperLiquidProvider_getAssetInfo, _HyperLiquidProvider_prepareAssetForTrading, _HyperLiquidProvider_handleHip3PreOrder, _HyperLiquidProvider_submitOrderWithRollback, _HyperLiquidProvider_handleOrderError, _HyperLiquidProvider_getStandaloneValidatedDexs, _HyperLiquidProvider_getAllMids, _HyperLiquidProvider_fetchSingleDexFresh, _HyperLiquidProvider_mergeDexResultsInto, _HyperLiquidProvider_cacheFreshMarketDataSnapshot, _HyperLiquidProvider_getStaleMarketDataSnapshot, _HyperLiquidProvider_isFeeCacheValid, _HyperLiquidProvider_getBuilderAddress, _HyperLiquidProvider_getReferralCode, _HyperLiquidProvider_ensureReferralSet, _HyperLiquidProvider_isReferralCodeReady, _HyperLiquidProvider_checkReferralSet, _HyperLiquidProvider_setReferralCode;
13
13
  import { hasProperty } from "@metamask/utils";
14
14
  import { v4 as uuidv4 } from "uuid";
15
+ import { PERPS_EVENT_PROPERTY, PERPS_EVENT_VALUE } from "../constants/eventNames.mjs";
15
16
  import { BASIS_POINTS_DIVISOR, BUILDER_FEE_CONFIG, FEE_RATES, getBridgeInfo, getChainId, HIP3_ASSET_MARKET_TYPES, HIP3_FEE_CONFIG, HIP3_MARGIN_CONFIG, HYPERLIQUID_WITHDRAWAL_MINUTES, REFERRAL_CONFIG, SPOT_ASSET_ID_OFFSET, TRADING_DEFAULTS, USDC_DECIMALS, USDH_CONFIG } from "../constants/hyperLiquidConfig.mjs";
16
17
  import { ORDER_SLIPPAGE_CONFIG, PERFORMANCE_CONFIG, PERPS_CONSTANTS, TP_SL_CONFIG, WITHDRAWAL_CONSTANTS } from "../constants/perpsConfig.mjs";
17
18
  import { PERPS_TRANSACTIONS_HISTORY_CONSTANTS } from "../constants/transactionsHistoryConfig.mjs";
@@ -21,6 +22,8 @@ import { HyperLiquidClientService, WebSocketConnectionState } from "../services/
21
22
  import { HyperLiquidSubscriptionService } from "../services/HyperLiquidSubscriptionService.mjs";
22
23
  import { HyperLiquidWalletService } from "../services/HyperLiquidWalletService.mjs";
23
24
  import { TradingReadinessCache, PerpsSigningCache } from "../services/TradingReadinessCache.mjs";
25
+ import { PerpsAnalyticsEvent } from "../types/index.mjs";
26
+ import { HL_ABSTRACTION_WIRE, HL_UNIFIED_ACCOUNT_MODE, hyperLiquidModeFoldsSpot } from "../types/hyperliquid-types.mjs";
24
27
  import { addSpotBalanceToAccountState, aggregateAccountStates } from "../utils/accountUtils.mjs";
25
28
  import { ensureError } from "../utils/errorUtils.mjs";
26
29
  import { adaptAccountStateFromSDK, adaptHyperLiquidLedgerUpdateToUserHistoryItem, adaptMarketFromSDK, adaptOrderFromSDK, adaptPositionFromSDK, buildAssetMapping, formatHyperLiquidPrice, formatHyperLiquidSize, parseAssetName } from "../utils/hyperLiquidAdapter.mjs";
@@ -96,11 +99,23 @@ export class HyperLiquidProvider {
96
99
  _HyperLiquidProvider_hip3Enabled.set(this, void 0);
97
100
  _HyperLiquidProvider_allowlistMarkets.set(this, void 0);
98
101
  _HyperLiquidProvider_blocklistMarkets.set(this, void 0);
99
- _HyperLiquidProvider_useDexAbstraction.set(this, void 0);
102
+ // Emergency kill-switch for the Unified Account migration flow. Defaults
103
+ // to true and is the expected production state after HL's DEX Abstraction
104
+ // deprecation. Kept as a constructor option (not removed) so we can
105
+ // disable the migration via a hot-fix release if a regression surfaces
106
+ // in the wild — flipping this to false reverts to the legacy programmatic
107
+ // HIP-3 transfer path that already lives in the codebase.
108
+ _HyperLiquidProvider_useUnifiedAccount.set(this, void 0);
100
109
  // True once DEX discovery has succeeded with real data (not a fallback).
101
110
  // When false, #ensureReadyPromise is reset after each init so the next
102
111
  // caller retries DEX discovery instead of reusing a degraded mapping.
103
112
  _HyperLiquidProvider_dexDiscoveryComplete.set(this, false);
113
+ // True when the most recent #ensureUnifiedAccountEnabled run ended in a
114
+ // transient state that warrants retry (silent agent-key failure, REST
115
+ // userAbstraction lookup failure, or keyring locked). #ensureReady resets
116
+ // its memoized promise when this is set so the next entry retries the
117
+ // migration instead of returning the cached resolved promise.
118
+ _HyperLiquidProvider_unifiedAccountSetupNeedsRetry.set(this, false);
104
119
  // Pending promise to deduplicate concurrent getValidatedDexs() calls
105
120
  _HyperLiquidProvider_pendingValidatedDexsPromise.set(this, null);
106
121
  // Cache for USDC token ID from spot metadata
@@ -141,8 +156,8 @@ export class HyperLiquidProvider {
141
156
  __classPrivateFieldSet(this, _HyperLiquidProvider_hip3Enabled, options.hip3Enabled ?? false, "f");
142
157
  __classPrivateFieldSet(this, _HyperLiquidProvider_allowlistMarkets, options.allowlistMarkets ?? [], "f");
143
158
  __classPrivateFieldSet(this, _HyperLiquidProvider_blocklistMarkets, options.blocklistMarkets ?? [], "f");
144
- // Attempt native balance abstraction, fallback to programmatic transfer if unsupported
145
- __classPrivateFieldSet(this, _HyperLiquidProvider_useDexAbstraction, options.useDexAbstraction ?? true, "f");
159
+ // Attempt unified account mode, fallback to programmatic transfer if unsupported
160
+ __classPrivateFieldSet(this, _HyperLiquidProvider_useUnifiedAccount, options.useUnifiedAccount ?? true, "f");
146
161
  // Initialize services with injected platform dependencies
147
162
  __classPrivateFieldSet(this, _HyperLiquidProvider_clientService, new HyperLiquidClientService(__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f"), {
148
163
  isTestnet,
@@ -741,7 +756,7 @@ export class HyperLiquidProvider {
741
756
  const closeSize = Math.abs(positionSize);
742
757
  const totalMarginUsed = parseFloat(position.marginUsed);
743
758
  // Track HIP-3 transfers (full position close means all margin is freed)
744
- if (isHip3Position && dexName && !__classPrivateFieldGet(this, _HyperLiquidProvider_useDexAbstraction, "f")) {
759
+ if (isHip3Position && dexName && !__classPrivateFieldGet(this, _HyperLiquidProvider_useUnifiedAccount, "f")) {
745
760
  hip3Transfers.push({
746
761
  sourceDex: dexName,
747
762
  freedMargin: totalMarginUsed,
@@ -795,7 +810,7 @@ export class HyperLiquidProvider {
795
810
  (hasProperty(stat, 'filled') || hasProperty(stat, 'resting'))).length;
796
811
  const failureCount = statuses.length - successCount;
797
812
  // Handle HIP-3 margin transfers for successful closes
798
- if (!__classPrivateFieldGet(this, _HyperLiquidProvider_useDexAbstraction, "f")) {
813
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_useUnifiedAccount, "f")) {
799
814
  for (let i = 0; i < statuses.length; i++) {
800
815
  const status = statuses[i];
801
816
  const isSuccess = isStatusObject(status) &&
@@ -1163,7 +1178,7 @@ export class HyperLiquidProvider {
1163
1178
  if (result.success &&
1164
1179
  isHip3Position &&
1165
1180
  hip3Dex &&
1166
- !__classPrivateFieldGet(this, _HyperLiquidProvider_useDexAbstraction, "f")) {
1181
+ !__classPrivateFieldGet(this, _HyperLiquidProvider_useUnifiedAccount, "f")) {
1167
1182
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Position closed successfully, initiating manual auto-transfer back');
1168
1183
  // Non-blocking: Transfer freed margin back to main DEX
1169
1184
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_autoTransferBackAfterClose).call(this, {
@@ -1174,8 +1189,8 @@ export class HyperLiquidProvider {
1174
1189
  else if (result.success &&
1175
1190
  isHip3Position &&
1176
1191
  hip3Dex &&
1177
- __classPrivateFieldGet(this, _HyperLiquidProvider_useDexAbstraction, "f")) {
1178
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Position closed - DEX abstraction will auto-return freed margin', {
1192
+ __classPrivateFieldGet(this, _HyperLiquidProvider_useUnifiedAccount, "f")) {
1193
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Position closed - Unified Account will auto-return freed margin', {
1179
1194
  coin: params.symbol,
1180
1195
  dex: hip3Dex,
1181
1196
  note: 'HyperLiquid handles return automatically',
@@ -1932,7 +1947,7 @@ export class HyperLiquidProvider {
1932
1947
  isTestnet: __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode(),
1933
1948
  });
1934
1949
  const dexs = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getStandaloneValidatedDexs).call(this);
1935
- const [standaloneSpotStateResult, standalonePerpsResults] = await Promise.all([
1950
+ const [standaloneSpotStateResult, standalonePerpsResults, standaloneAbstractionResult,] = await Promise.all([
1936
1951
  standaloneInfoClient
1937
1952
  .spotClearinghouseState({ user: userAddress })
1938
1953
  .catch((error) => {
@@ -1942,11 +1957,21 @@ export class HyperLiquidProvider {
1942
1957
  return null;
1943
1958
  }),
1944
1959
  queryStandaloneClearinghouseStates(standaloneInfoClient, userAddress, dexs),
1960
+ standaloneInfoClient
1961
+ .userAbstraction({ user: userAddress })
1962
+ .catch((error) => {
1963
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Standalone userAbstraction fetch failed; spot fold disabled until the mode resolves', {
1964
+ error: ensureError(error, 'HyperLiquidProvider.getAccountState.standalone.abstraction').message,
1965
+ });
1966
+ return null;
1967
+ }),
1945
1968
  ]);
1946
1969
  // Aggregate account states across all DEXs, then apply spot-backed
1947
1970
  // adjustments so streamed/standalone/full paths report the same totals.
1948
1971
  const dexAccountStates = standalonePerpsResults.map((perpsState) => adaptAccountStateFromSDK(perpsState));
1949
- const aggregatedAccountState = addSpotBalanceToAccountState(aggregateAccountStates(dexAccountStates), standaloneSpotStateResult);
1972
+ const aggregatedAccountState = addSpotBalanceToAccountState(aggregateAccountStates(dexAccountStates), standaloneSpotStateResult, {
1973
+ foldIntoCollateral: hyperLiquidModeFoldsSpot(standaloneAbstractionResult),
1974
+ });
1950
1975
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: standalone account state fetched', { totalBalance: aggregatedAccountState.totalBalance });
1951
1976
  return aggregatedAccountState;
1952
1977
  }
@@ -1960,11 +1985,20 @@ export class HyperLiquidProvider {
1960
1985
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Network mode:', __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode() ? 'TESTNET' : 'MAINNET');
1961
1986
  // Get Spot balance (global, not DEX-specific) and Perps states across all DEXs.
1962
1987
  // One transient DEX failure should not blank the entire account state.
1963
- const [spotStateResult, perpsStateResult] = await Promise.allSettled([
1988
+ const [spotStateResult, perpsStateResult, abstractionResult] = await Promise.allSettled([
1964
1989
  infoClient.spotClearinghouseState({ user: userAddress }),
1965
1990
  __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.clearinghouseState(userParam)),
1991
+ infoClient.userAbstraction({ user: userAddress }),
1966
1992
  ]);
1967
1993
  const spotState = spotStateResult.status === 'fulfilled' ? spotStateResult.value : null;
1994
+ const abstractionMode = abstractionResult.status === 'fulfilled'
1995
+ ? abstractionResult.value
1996
+ : null;
1997
+ if (abstractionResult.status === 'rejected') {
1998
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('User abstraction fetch failed; spot fold disabled until the mode resolves', {
1999
+ error: ensureError(abstractionResult.reason, 'HyperLiquidProvider.getAccountState.abstraction').message,
2000
+ });
2001
+ }
1968
2002
  const perpsResponse = perpsStateResult.status === 'fulfilled'
1969
2003
  ? perpsStateResult.value
1970
2004
  : {
@@ -2011,7 +2045,9 @@ export class HyperLiquidProvider {
2011
2045
  });
2012
2046
  return dexAccountState;
2013
2047
  });
2014
- const aggregatedAccountState = addSpotBalanceToAccountState(aggregateAccountStates(dexAccountStates), spotState);
2048
+ const aggregatedAccountState = addSpotBalanceToAccountState(aggregateAccountStates(dexAccountStates), spotState, {
2049
+ foldIntoCollateral: hyperLiquidModeFoldsSpot(abstractionMode),
2050
+ });
2015
2051
  // Build per-sub-account breakdown (HIP-3 DEXs map to sub-accounts)
2016
2052
  const subAccountBreakdown = {};
2017
2053
  perpsStateResults.forEach((result) => {
@@ -2685,14 +2721,20 @@ export class HyperLiquidProvider {
2685
2721
  // Step 4: Ensure client is ready
2686
2722
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: ENSURING CLIENT READY');
2687
2723
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReady).call(this);
2724
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureUnifiedAccountEnabled).call(this, { allowUserSigning: true });
2688
2725
  const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
2689
2726
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: CLIENT READY');
2690
2727
  // Step 5: Validate amount against account balance
2691
2728
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: CHECKING ACCOUNT BALANCE');
2692
2729
  const accountState = await this.getAccountState();
2693
- const availableBalance = parseFloat(accountState.availableBalance);
2730
+ // Release-branch bridge for Unified Account: availableToTradeBalance
2731
+ // includes collateral HL can draw in target mode. The larger balance
2732
+ // contract will replace this with an explicit withdrawableBalance field.
2733
+ const availableBalance = parseFloat(accountState.availableToTradeBalance ?? accountState.availableBalance);
2694
2734
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: ACCOUNT BALANCE', {
2695
2735
  availableBalance,
2736
+ clearinghouseAvailableBalance: accountState.availableBalance,
2737
+ availableToTradeBalance: accountState.availableToTradeBalance,
2696
2738
  totalBalance: accountState.totalBalance,
2697
2739
  marginUsed: accountState.marginUsed,
2698
2740
  unrealizedPnl: accountState.unrealizedPnl,
@@ -3505,7 +3547,7 @@ export class HyperLiquidProvider {
3505
3547
  // Clear session caches (ensures fresh state on reconnect/account switch)
3506
3548
  __classPrivateFieldGet(this, _HyperLiquidProvider_referralCheckCache, "f").clear();
3507
3549
  __classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").clear();
3508
- // NOTE: DexAbstractionCache is global and NOT cleared on disconnect
3550
+ // NOTE: UnifiedAccountCache is global and NOT cleared on disconnect
3509
3551
  // to prevent repeated signing requests across reconnections
3510
3552
  __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").clear();
3511
3553
  __classPrivateFieldSet(this, _HyperLiquidProvider_cachedSpotMeta, null, "f");
@@ -3685,7 +3727,7 @@ export class HyperLiquidProvider {
3685
3727
  return `${baseUrl}/explorer`;
3686
3728
  }
3687
3729
  }
3688
- _HyperLiquidProvider_deps = new WeakMap(), _HyperLiquidProvider_clientService = new WeakMap(), _HyperLiquidProvider_walletService = new WeakMap(), _HyperLiquidProvider_subscriptionService = new WeakMap(), _HyperLiquidProvider_symbolToAssetId = new WeakMap(), _HyperLiquidProvider_userFeeCache = new WeakMap(), _HyperLiquidProvider_maxLeverageCache = new WeakMap(), _HyperLiquidProvider_cachedMetaByDex = new WeakMap(), _HyperLiquidProvider_cachedMarketDataWithPrices = new WeakMap(), _HyperLiquidProvider_cachedSpotMeta = new WeakMap(), _HyperLiquidProvider_dexDiscoveryCache = new WeakMap(), _HyperLiquidProvider_referralCheckCache = new WeakMap(), _HyperLiquidProvider_builderFeeCheckCache = new WeakMap(), _HyperLiquidProvider_ensureReadyPromise = new WeakMap(), _HyperLiquidProvider_pendingBuilderFeeApprovals = new WeakMap(), _HyperLiquidProvider_compiledAllowlistPatterns = new WeakMap(), _HyperLiquidProvider_compiledBlocklistPatterns = new WeakMap(), _HyperLiquidProvider_userFeeDiscountBips = new WeakMap(), _HyperLiquidProvider_hip3Enabled = new WeakMap(), _HyperLiquidProvider_allowlistMarkets = new WeakMap(), _HyperLiquidProvider_blocklistMarkets = new WeakMap(), _HyperLiquidProvider_useDexAbstraction = new WeakMap(), _HyperLiquidProvider_dexDiscoveryComplete = new WeakMap(), _HyperLiquidProvider_pendingValidatedDexsPromise = new WeakMap(), _HyperLiquidProvider_cachedUsdcTokenId = new WeakMap(), _HyperLiquidProvider_errorMappings = new WeakMap(), _HyperLiquidProvider_clientsInitialized = new WeakMap(), _HyperLiquidProvider_initializationPromise = new WeakMap(), _HyperLiquidProvider_messenger = new WeakMap(), _HyperLiquidProvider_builderAddressTestnet = new WeakMap(), _HyperLiquidProvider_builderAddressMainnet = new WeakMap(), _HyperLiquidProvider_tradingSetupPromise = new WeakMap(), _HyperLiquidProvider_tradingSetupComplete = new WeakMap(), _HyperLiquidProvider_instances = new WeakSet(), _HyperLiquidProvider_compilePatternsSafely = function _HyperLiquidProvider_compilePatternsSafely(patterns, listName) {
3730
+ _HyperLiquidProvider_deps = new WeakMap(), _HyperLiquidProvider_clientService = new WeakMap(), _HyperLiquidProvider_walletService = new WeakMap(), _HyperLiquidProvider_subscriptionService = new WeakMap(), _HyperLiquidProvider_symbolToAssetId = new WeakMap(), _HyperLiquidProvider_userFeeCache = new WeakMap(), _HyperLiquidProvider_maxLeverageCache = new WeakMap(), _HyperLiquidProvider_cachedMetaByDex = new WeakMap(), _HyperLiquidProvider_cachedMarketDataWithPrices = new WeakMap(), _HyperLiquidProvider_cachedSpotMeta = new WeakMap(), _HyperLiquidProvider_dexDiscoveryCache = new WeakMap(), _HyperLiquidProvider_referralCheckCache = new WeakMap(), _HyperLiquidProvider_builderFeeCheckCache = new WeakMap(), _HyperLiquidProvider_ensureReadyPromise = new WeakMap(), _HyperLiquidProvider_pendingBuilderFeeApprovals = new WeakMap(), _HyperLiquidProvider_compiledAllowlistPatterns = new WeakMap(), _HyperLiquidProvider_compiledBlocklistPatterns = new WeakMap(), _HyperLiquidProvider_userFeeDiscountBips = new WeakMap(), _HyperLiquidProvider_hip3Enabled = new WeakMap(), _HyperLiquidProvider_allowlistMarkets = new WeakMap(), _HyperLiquidProvider_blocklistMarkets = new WeakMap(), _HyperLiquidProvider_useUnifiedAccount = new WeakMap(), _HyperLiquidProvider_dexDiscoveryComplete = new WeakMap(), _HyperLiquidProvider_unifiedAccountSetupNeedsRetry = new WeakMap(), _HyperLiquidProvider_pendingValidatedDexsPromise = new WeakMap(), _HyperLiquidProvider_cachedUsdcTokenId = new WeakMap(), _HyperLiquidProvider_errorMappings = new WeakMap(), _HyperLiquidProvider_clientsInitialized = new WeakMap(), _HyperLiquidProvider_initializationPromise = new WeakMap(), _HyperLiquidProvider_messenger = new WeakMap(), _HyperLiquidProvider_builderAddressTestnet = new WeakMap(), _HyperLiquidProvider_builderAddressMainnet = new WeakMap(), _HyperLiquidProvider_tradingSetupPromise = new WeakMap(), _HyperLiquidProvider_tradingSetupComplete = new WeakMap(), _HyperLiquidProvider_instances = new WeakSet(), _HyperLiquidProvider_compilePatternsSafely = function _HyperLiquidProvider_compilePatternsSafely(patterns, listName) {
3689
3731
  const compiled = [];
3690
3732
  for (const pattern of patterns) {
3691
3733
  try {
@@ -3756,9 +3798,9 @@ async function _HyperLiquidProvider_ensureClientsInitialized() {
3756
3798
  // so future calls can retry if needed
3757
3799
  __classPrivateFieldSet(this, _HyperLiquidProvider_initializationPromise, null, "f");
3758
3800
  }
3759
- }, _HyperLiquidProvider_ensureDexAbstractionEnabled =
3801
+ }, _HyperLiquidProvider_ensureUnifiedAccountEnabled =
3760
3802
  /**
3761
- * Attempt to enable HIP-3 native balance abstraction
3803
+ * Attempt to enable HyperLiquid Unified Account mode for HIP-3 orders
3762
3804
  *
3763
3805
  * If successful, HyperLiquid automatically manages collateral transfers for HIP-3 orders.
3764
3806
  * If not supported, disables the flag to trigger programmatic transfer fallback.
@@ -3766,10 +3808,24 @@ async function _HyperLiquidProvider_ensureClientsInitialized() {
3766
3808
  * IMPORTANT: Uses global singleton cache to prevent repeated signing requests
3767
3809
  * across provider reconnections (critical for hardware wallets).
3768
3810
  *
3811
+ * @param options - Optional configuration.
3812
+ * @param options.allowUserSigning - When true, runs the EIP-712 user-signed migration for `dexAbstraction` accounts. Defaults to false so init does not surface a signing prompt; action-time entry points (trading, withdraw) pass true.
3769
3813
  * @private
3770
3814
  */
3771
- async function _HyperLiquidProvider_ensureDexAbstractionEnabled() {
3772
- if (!__classPrivateFieldGet(this, _HyperLiquidProvider_useDexAbstraction, "f")) {
3815
+ async function _HyperLiquidProvider_ensureUnifiedAccountEnabled(options) {
3816
+ // dexAbstraction unifiedAccount requires an EIP-712 prompt (HL blocks
3817
+ // the agent path for that transition). Init calls with allowUserSigning=false so
3818
+ // viewing the Perps section never surfaces a signing dialog. Trading and
3819
+ // withdraw entry points pass allowUserSigning=true to drive the migration when
3820
+ // the user actually intends to act.
3821
+ const allowUserSigning = options?.allowUserSigning ?? false;
3822
+ // Optimistic reset — set true below only at the failure points that
3823
+ // warrant retry (silent agent failure, REST lookup failure, keyring
3824
+ // locked). Final-state outcomes (success, prompted-failure cached,
3825
+ // already-on-compatible, defer, unknown mode, feature off) leave it
3826
+ // false so #ensureReady can keep the memoized promise.
3827
+ __classPrivateFieldSet(this, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, false, "f");
3828
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_useUnifiedAccount, "f")) {
3773
3829
  return; // Feature disabled
3774
3830
  }
3775
3831
  const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
@@ -3778,7 +3834,7 @@ async function _HyperLiquidProvider_ensureDexAbstractionEnabled() {
3778
3834
  // This is CRITICAL for hardware wallets to prevent QR popup spam
3779
3835
  const cachedStatus = TradingReadinessCache.get(network, userAddress);
3780
3836
  if (cachedStatus?.attempted) {
3781
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: DEX abstraction already attempted (from global cache)', {
3837
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Unified Account setup already attempted (from global cache)', {
3782
3838
  user: userAddress,
3783
3839
  network,
3784
3840
  enabled: cachedStatus.enabled,
@@ -3788,75 +3844,178 @@ async function _HyperLiquidProvider_ensureDexAbstractionEnabled() {
3788
3844
  }
3789
3845
  // Check if another provider instance is currently attempting this operation
3790
3846
  // This prevents concurrent signing attempts across providers during reconnection
3791
- const inFlightPromise = PerpsSigningCache.isInFlight('dexAbstraction', network, userAddress);
3847
+ const inFlightPromise = PerpsSigningCache.isInFlight('unifiedAccount', network, userAddress);
3792
3848
  if (inFlightPromise) {
3793
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: DEX abstraction in-flight, waiting...', { network, userAddress });
3849
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Unified Account setup in-flight, waiting...', { network, userAddress });
3794
3850
  await inFlightPromise;
3795
- return; // After waiting, the cache should be set by the other provider
3851
+ // The other instance may have finished without writing the cache (e.g.
3852
+ // an init-time call deferred a dexAbstraction migration). If the cache
3853
+ // is still empty and we are an action-time caller (allowUserSigning=true),
3854
+ // we must run our own attempt — otherwise the trade/withdraw would
3855
+ // proceed in the deprecated mode.
3856
+ const postWaitCache = TradingReadinessCache.get(network, userAddress);
3857
+ if (postWaitCache?.attempted) {
3858
+ return;
3859
+ }
3860
+ // Fall through to acquire our own lock and retry.
3796
3861
  }
3797
3862
  // Set in-flight lock to prevent concurrent attempts
3798
- const completeInFlight = PerpsSigningCache.setInFlight('dexAbstraction', network, userAddress);
3863
+ const completeInFlight = PerpsSigningCache.setInFlight('unifiedAccount', network, userAddress);
3864
+ let currentMode;
3799
3865
  try {
3800
3866
  // Re-check cache after acquiring lock (another provider might have finished)
3801
3867
  const recheckCache = TradingReadinessCache.get(network, userAddress);
3802
3868
  if (recheckCache?.attempted) {
3803
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: DEX abstraction completed by another provider', { network, userAddress });
3869
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Unified Account setup completed by another provider', { network, userAddress });
3804
3870
  completeInFlight();
3805
3871
  return;
3806
3872
  }
3807
3873
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
3808
- // Check if already enabled on-chain (returns boolean | null)
3809
- const isEnabled = await infoClient.userDexAbstraction({
3874
+ // Check current abstraction mode on-chain
3875
+ currentMode = await infoClient.userAbstraction({
3810
3876
  user: userAddress,
3811
3877
  });
3812
- if (isEnabled === true) {
3813
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: DEX abstraction already enabled on-chain', { user: userAddress, network });
3814
- // Cache the enabled status to skip future checks
3878
+ if (currentMode === 'unifiedAccount' ||
3879
+ currentMode === 'portfolioMargin') {
3880
+ // portfolioMargin is a superset of unifiedAccount it already supports
3881
+ // auto-collateral management for HIP-3 orders and is more capital-efficient.
3882
+ // Downgrading portfolio margin users to unifiedAccount would be harmful,
3883
+ // so we treat both modes as already-enabled and skip migration.
3884
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Account already in a compatible mode, skipping migration', { user: userAddress, network, mode: currentMode });
3885
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").metrics.trackPerpsEvent(PerpsAnalyticsEvent.AccountSetup, {
3886
+ [PERPS_EVENT_PROPERTY.ABSTRACTION_MODE]: currentMode,
3887
+ [PERPS_EVENT_PROPERTY.STATUS]: PERPS_EVENT_VALUE.STATUS.ALREADY_ENABLED,
3888
+ });
3815
3889
  TradingReadinessCache.set(network, userAddress, {
3816
3890
  attempted: true,
3817
3891
  enabled: true,
3818
3892
  });
3893
+ // Record the resolved mode in the subscription service so the next
3894
+ // aggregation folds spot correctly without waiting for #refreshSpotState.
3895
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setUserAbstractionMode(userAddress, currentMode);
3896
+ completeInFlight();
3897
+ return;
3898
+ }
3899
+ // Defer the user-signed transition until the user attempts an action.
3900
+ // Cache is intentionally left untouched so the next entry re-evaluates;
3901
+ // the read-only userAbstraction call is cheap and gated by the in-flight
3902
+ // lock, preventing concurrent prompts.
3903
+ if (currentMode === 'dexAbstraction' && !allowUserSigning) {
3904
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Deferring dexAbstraction → unifiedAccount migration to action time', { user: userAddress, network });
3819
3905
  completeInFlight();
3820
3906
  return;
3821
3907
  }
3822
- // Enable DEX abstraction (one-time, irreversible, requires signature)
3823
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Enabling DEX abstraction (requires signature)', {
3908
+ // Bail on unknown modes BEFORE firing analytics or attempting dispatch.
3909
+ // Keeps `migration_required` actionable (only fires for modes we can
3910
+ // actually migrate) and avoids re-emitting on every reconnection.
3911
+ if (currentMode !== 'dexAbstraction' &&
3912
+ currentMode !== 'default' &&
3913
+ currentMode !== 'disabled') {
3914
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Unknown abstraction mode, skipping Unified Account migration', { user: userAddress, network, mode: currentMode });
3915
+ completeInFlight();
3916
+ return;
3917
+ }
3918
+ // Track which mode users are currently on before we attempt migration.
3919
+ // This tells us the distribution of legacy modes across our user base.
3920
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").metrics.trackPerpsEvent(PerpsAnalyticsEvent.AccountSetup, {
3921
+ [PERPS_EVENT_PROPERTY.ABSTRACTION_MODE]: currentMode,
3922
+ [PERPS_EVENT_PROPERTY.STATUS]: PERPS_EVENT_VALUE.STATUS.MIGRATION_REQUIRED,
3923
+ });
3924
+ // Enable Unified Account mode.
3925
+ // - default / disabled: agent wallet can do this silently (no prompt)
3926
+ // - dexAbstraction: HL blocks the agent transition — requires the user's main
3927
+ // wallet to sign an EIP-712 action via userSetAbstraction (one-time prompt)
3928
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Enabling Unified Account mode', {
3824
3929
  user: userAddress,
3825
3930
  network,
3931
+ previousMode: currentMode,
3826
3932
  note: 'HyperLiquid will auto-manage collateral for HIP-3 orders',
3827
3933
  });
3828
3934
  const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
3829
- await exchangeClient.agentEnableDexAbstraction();
3830
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(' HyperLiquidProvider: DEX abstraction enabled successfully');
3831
- // Cache success to prevent re-attempts on reconnection
3935
+ if (currentMode === 'dexAbstraction') {
3936
+ // Requires EIP-712 signature from the user's main wallet (one-time migration).
3937
+ // HL blocks the dexAbstraction unifiedAccount transition via the agent wallet,
3938
+ // so userSetAbstraction (user-signed) is the only path for legacy users.
3939
+ await exchangeClient.userSetAbstraction({
3940
+ user: userAddress,
3941
+ abstraction: HL_UNIFIED_ACCOUNT_MODE,
3942
+ });
3943
+ }
3944
+ else {
3945
+ // default / disabled — silent agent transition, no user prompt
3946
+ await exchangeClient.agentSetAbstraction({
3947
+ abstraction: HL_ABSTRACTION_WIRE.unifiedAccount,
3948
+ });
3949
+ }
3950
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('✅ HyperLiquidProvider: Unified Account enabled successfully');
3951
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").metrics.trackPerpsEvent(PerpsAnalyticsEvent.AccountSetup, {
3952
+ [PERPS_EVENT_PROPERTY.PREVIOUS_ABSTRACTION_MODE]: currentMode,
3953
+ [PERPS_EVENT_PROPERTY.ABSTRACTION_MODE]: HL_UNIFIED_ACCOUNT_MODE,
3954
+ [PERPS_EVENT_PROPERTY.STATUS]: PERPS_EVENT_VALUE.STATUS.SUCCESS,
3955
+ });
3832
3956
  TradingReadinessCache.set(network, userAddress, {
3833
3957
  attempted: true,
3834
3958
  enabled: true,
3835
3959
  });
3960
+ // Record the post-migration mode in the subscription service so it
3961
+ // immediately re-aggregates with fold=true and surfaces the unified
3962
+ // balance rather than waiting for the next #refreshSpotState.
3963
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setUserAbstractionMode(userAddress, HL_UNIFIED_ACCOUNT_MODE);
3836
3964
  completeInFlight();
3837
3965
  }
3838
3966
  catch (error) {
3839
3967
  // If keyring is locked, don't cache so it retries when unlocked
3840
3968
  if (ensureError(error).message === PERPS_ERROR_CODES.KEYRING_LOCKED) {
3841
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureDexAbstractionEnabled] Keyring locked, will retry later');
3969
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureUnifiedAccountEnabled] Keyring locked, will retry later');
3970
+ __classPrivateFieldSet(this, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, true, "f");
3842
3971
  completeInFlight();
3843
3972
  return;
3844
3973
  }
3845
- // Cache the attempt (even on failure) to prevent repeated signing requests
3846
- // This is CRITICAL for hardware wallets - if user rejects, don't ask again
3847
- TradingReadinessCache.set(network, userAddress, {
3848
- attempted: true,
3849
- enabled: false,
3850
- });
3851
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: DEX abstraction failed, cached to prevent retries', {
3974
+ // Cache failure ONLY for the user-prompted path
3975
+ // (`dexAbstraction unifiedAccount` via `userSetAbstraction`). The
3976
+ // rationale for caching is "don't re-prompt a user who already saw the
3977
+ // signature dialog and rejected it" — that doesn't apply to:
3978
+ // - Read-only userAbstraction lookup failures (no prompt; transient).
3979
+ // - Silent agent-key paths (`default`/`disabled` → `agentSetAbstraction`
3980
+ // does not show a UI prompt; failures are typically transient HL
3981
+ // outages and pinning them would leave users stuck in the
3982
+ // deprecated mode for the rest of the session).
3983
+ // Action-time retries pick up the unmigrated state and try again.
3984
+ if (currentMode === 'dexAbstraction') {
3985
+ TradingReadinessCache.set(network, userAddress, {
3986
+ attempted: true,
3987
+ enabled: false,
3988
+ });
3989
+ }
3990
+ else {
3991
+ // Silent agent-key failure (default/disabled) or read-only
3992
+ // userAbstraction lookup failure — neither is a final state, so
3993
+ // signal #ensureReady to drop its memoized promise and retry on
3994
+ // the next entry instead of pinning the user in the deprecated
3995
+ // mode for the provider's lifetime.
3996
+ __classPrivateFieldSet(this, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, true, "f");
3997
+ }
3998
+ const errorMessage = ensureError(error, 'HyperLiquidProvider.ensureUnifiedAccountEnabled').message;
3999
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Unified Account setup failed', {
3852
4000
  user: userAddress,
3853
4001
  network,
3854
- error: ensureError(error, 'HyperLiquidProvider.ensureDexAbstractionEnabled').message,
4002
+ error: errorMessage,
4003
+ // Cache writes only happen on the user-prompted dexAbstraction
4004
+ // path (see P2-B logic above). Reflect that here so retry
4005
+ // behaviour is debuggable from the log alone.
4006
+ cached: currentMode === 'dexAbstraction',
4007
+ });
4008
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").metrics.trackPerpsEvent(PerpsAnalyticsEvent.AccountSetup, {
4009
+ ...(currentMode && {
4010
+ [PERPS_EVENT_PROPERTY.PREVIOUS_ABSTRACTION_MODE]: currentMode,
4011
+ [PERPS_EVENT_PROPERTY.ABSTRACTION_MODE]: HL_UNIFIED_ACCOUNT_MODE,
4012
+ }),
4013
+ [PERPS_EVENT_PROPERTY.STATUS]: PERPS_EVENT_VALUE.STATUS.FAILED,
4014
+ [PERPS_EVENT_PROPERTY.ERROR_MESSAGE]: errorMessage,
3855
4015
  });
3856
4016
  completeInFlight();
3857
- // Don't blindly disable the flag on any error
3858
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error(ensureError(error, 'HyperLiquidProvider.ensureDexAbstractionEnabled'), __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'ensureDexAbstractionEnabled', {
3859
- note: 'Could not enable DEX abstraction (may already be enabled, user rejected, or network error)',
4017
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error(ensureError(error, 'HyperLiquidProvider.ensureUnifiedAccountEnabled'), __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'ensureUnifiedAccountEnabled', {
4018
+ note: 'Could not enable Unified Account (user rejected, or network error)',
3860
4019
  }));
3861
4020
  }
3862
4021
  }, _HyperLiquidProvider_ensureReady =
@@ -3890,9 +4049,14 @@ async function _HyperLiquidProvider_ensureReady() {
3890
4049
  });
3891
4050
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_buildAssetMapping).call(this);
3892
4051
  }
3893
- // NOTE: Signing operations (DEX abstraction, builder fee, referral) are now DEFERRED
3894
- // They are called on-demand in ensureReadyForTrading() when user attempts to trade
3895
- // This prevents QR popups when just viewing the Perps section (critical for hardware wallets)
4052
+ // Attempt Unified Account migration as early as possible so users aren't
4053
+ // blocked when they try to trade. Software-wallet dexAbstraction users can
4054
+ // complete the one-time EIP-712 migration during initial setup so the first
4055
+ // trade sees the unified balance. Hardware wallets remain deferred to
4056
+ // action time to avoid QR / Ledger prompt spam while browsing.
4057
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureUnifiedAccountEnabled).call(this, {
4058
+ allowUserSigning: !__classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").isSelectedHardwareWallet(),
4059
+ });
3896
4060
  })(), "f");
3897
4061
  // Await initialization - keep the promise so subsequent calls resolve immediately
3898
4062
  // The promise is only reset in disconnect() for clean reconnection,
@@ -3904,10 +4068,21 @@ async function _HyperLiquidProvider_ensureReady() {
3904
4068
  // will be re-discovered on the next #ensureReady() call.
3905
4069
  __classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
3906
4070
  }
4071
+ else if (__classPrivateFieldGet(this, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, "f")) {
4072
+ // Silent migration / lookup / keyring-locked failure left the cache
4073
+ // empty. Without resetting the memoized promise, subsequent
4074
+ // #ensureReady calls would skip retry and the user would be stuck
4075
+ // in the deprecated mode for the provider's lifetime.
4076
+ __classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
4077
+ }
3907
4078
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReady] Initialization complete');
3908
4079
  }, _HyperLiquidProvider_ensureReadyForTrading = async function _HyperLiquidProvider_ensureReadyForTrading() {
3909
4080
  // First ensure basic initialization is complete
3910
4081
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReady).call(this);
4082
+ // dexAbstraction users were deferred during init to avoid an EIP-712 prompt
4083
+ // on Perps section open. Drive the migration here, gated by its own cache so
4084
+ // already-migrated or already-rejected users are not re-prompted.
4085
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureUnifiedAccountEnabled).call(this, { allowUserSigning: true });
3911
4086
  // If trading setup already complete, return immediately
3912
4087
  if (__classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupComplete, "f")) {
3913
4088
  return;
@@ -3931,8 +4106,6 @@ async function _HyperLiquidProvider_ensureReady() {
3931
4106
  // Don't throw - spotMeta will be fetched on-demand if needed
3932
4107
  }
3933
4108
  }
3934
- // Attempt to enable native balance abstraction
3935
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureDexAbstractionEnabled).call(this);
3936
4109
  // Set up builder fee approval
3937
4110
  try {
3938
4111
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureBuilderFeeApproval).call(this);
@@ -5555,11 +5728,11 @@ async function _HyperLiquidProvider_handleHip3PreOrder(params) {
5555
5728
  isBuy,
5556
5729
  });
5557
5730
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureUsdhCollateralForOrder).call(this, dexName, requiredMargin);
5558
- // DEX abstraction will pull USDH from spot automatically
5731
+ // Unified Account will pull USDH from spot automatically
5559
5732
  return { transferInfo: null };
5560
5733
  }
5561
- if (__classPrivateFieldGet(this, _HyperLiquidProvider_useDexAbstraction, "f")) {
5562
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Using DEX abstraction (no manual transfer)', {
5734
+ if (__classPrivateFieldGet(this, _HyperLiquidProvider_useUnifiedAccount, "f")) {
5735
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Using Unified Account (no manual transfer)', {
5563
5736
  symbol,
5564
5737
  dex: dexName,
5565
5738
  });
@@ -5588,7 +5761,7 @@ async function _HyperLiquidProvider_handleHip3PreOrder(params) {
5588
5761
  const errorMsg = transferError?.message || '';
5589
5762
  if (errorMsg.includes('Cannot transfer with DEX abstraction enabled')) {
5590
5763
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Detected DEX abstraction is enabled, switching mode');
5591
- __classPrivateFieldSet(this, _HyperLiquidProvider_useDexAbstraction, true, "f");
5764
+ __classPrivateFieldSet(this, _HyperLiquidProvider_useUnifiedAccount, true, "f");
5592
5765
  return { transferInfo: null };
5593
5766
  }
5594
5767
  throw transferError;