@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.
- package/CHANGELOG.md +16 -0
- package/dist/constants/eventNames.cjs +5 -0
- package/dist/constants/eventNames.cjs.map +1 -1
- package/dist/constants/eventNames.d.cts +4 -0
- package/dist/constants/eventNames.d.cts.map +1 -1
- package/dist/constants/eventNames.d.mts +4 -0
- package/dist/constants/eventNames.d.mts.map +1 -1
- package/dist/constants/eventNames.mjs +5 -0
- package/dist/constants/eventNames.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +230 -57
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +230 -57
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.cjs +108 -20
- package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts +19 -0
- package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts +19 -0
- package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.mjs +108 -20
- package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
- package/dist/services/HyperLiquidWalletService.cjs +20 -0
- package/dist/services/HyperLiquidWalletService.cjs.map +1 -1
- package/dist/services/HyperLiquidWalletService.d.cts +6 -0
- package/dist/services/HyperLiquidWalletService.d.cts.map +1 -1
- package/dist/services/HyperLiquidWalletService.d.mts +6 -0
- package/dist/services/HyperLiquidWalletService.d.mts.map +1 -1
- package/dist/services/HyperLiquidWalletService.mjs +22 -2
- package/dist/services/HyperLiquidWalletService.mjs.map +1 -1
- package/dist/services/TradingReadinessCache.cjs +16 -16
- package/dist/services/TradingReadinessCache.cjs.map +1 -1
- package/dist/services/TradingReadinessCache.d.cts +12 -12
- package/dist/services/TradingReadinessCache.d.mts +12 -12
- package/dist/services/TradingReadinessCache.mjs +16 -16
- package/dist/services/TradingReadinessCache.mjs.map +1 -1
- package/dist/types/hyperliquid-types.cjs +39 -0
- package/dist/types/hyperliquid-types.cjs.map +1 -1
- package/dist/types/hyperliquid-types.d.cts +34 -2
- package/dist/types/hyperliquid-types.d.cts.map +1 -1
- package/dist/types/hyperliquid-types.d.mts +34 -2
- package/dist/types/hyperliquid-types.d.mts.map +1 -1
- package/dist/types/hyperliquid-types.mjs +37 -1
- package/dist/types/hyperliquid-types.mjs.map +1 -1
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +2 -1
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +2 -1
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs +1 -0
- package/dist/types/index.mjs.map +1 -1
- package/dist/utils/accountUtils.cjs +20 -8
- package/dist/utils/accountUtils.cjs.map +1 -1
- package/dist/utils/accountUtils.d.cts +9 -5
- package/dist/utils/accountUtils.d.cts.map +1 -1
- package/dist/utils/accountUtils.d.mts +9 -5
- package/dist/utils/accountUtils.d.mts.map +1 -1
- package/dist/utils/accountUtils.mjs +20 -8
- package/dist/utils/accountUtils.mjs.map +1 -1
- 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,
|
|
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
|
-
|
|
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
|
|
145
|
-
__classPrivateFieldSet(this,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1178
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Position closed -
|
|
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
|
-
|
|
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:
|
|
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(),
|
|
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
|
-
},
|
|
3801
|
+
}, _HyperLiquidProvider_ensureUnifiedAccountEnabled =
|
|
3760
3802
|
/**
|
|
3761
|
-
* Attempt to enable HIP-3
|
|
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
|
|
3772
|
-
|
|
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:
|
|
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('
|
|
3847
|
+
const inFlightPromise = PerpsSigningCache.isInFlight('unifiedAccount', network, userAddress);
|
|
3792
3848
|
if (inFlightPromise) {
|
|
3793
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider:
|
|
3849
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Unified Account setup in-flight, waiting...', { network, userAddress });
|
|
3794
3850
|
await inFlightPromise;
|
|
3795
|
-
|
|
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('
|
|
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:
|
|
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
|
|
3809
|
-
|
|
3874
|
+
// Check current abstraction mode on-chain
|
|
3875
|
+
currentMode = await infoClient.userAbstraction({
|
|
3810
3876
|
user: userAddress,
|
|
3811
3877
|
});
|
|
3812
|
-
if (
|
|
3813
|
-
|
|
3814
|
-
//
|
|
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
|
-
//
|
|
3823
|
-
|
|
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
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
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('[
|
|
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
|
|
3846
|
-
//
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
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:
|
|
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
|
-
|
|
3858
|
-
|
|
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
|
-
//
|
|
3894
|
-
//
|
|
3895
|
-
//
|
|
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
|
-
//
|
|
5731
|
+
// Unified Account will pull USDH from spot automatically
|
|
5559
5732
|
return { transferInfo: null };
|
|
5560
5733
|
}
|
|
5561
|
-
if (__classPrivateFieldGet(this,
|
|
5562
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Using
|
|
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,
|
|
5764
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_useUnifiedAccount, true, "f");
|
|
5592
5765
|
return { transferInfo: null };
|
|
5593
5766
|
}
|
|
5594
5767
|
throw transferError;
|