@metamask-previews/perps-controller 6.2.0-preview-e43dfcb → 6.2.0-preview-855431b

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 (128) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/PerpsController-method-action-types.cjs.map +1 -1
  3. package/dist/PerpsController-method-action-types.d.cts +19 -1
  4. package/dist/PerpsController-method-action-types.d.cts.map +1 -1
  5. package/dist/PerpsController-method-action-types.d.mts +19 -1
  6. package/dist/PerpsController-method-action-types.d.mts.map +1 -1
  7. package/dist/PerpsController-method-action-types.mjs.map +1 -1
  8. package/dist/PerpsController.cjs +43 -5
  9. package/dist/PerpsController.cjs.map +1 -1
  10. package/dist/PerpsController.d.cts +13 -0
  11. package/dist/PerpsController.d.cts.map +1 -1
  12. package/dist/PerpsController.d.mts +13 -0
  13. package/dist/PerpsController.d.mts.map +1 -1
  14. package/dist/PerpsController.mjs +45 -7
  15. package/dist/PerpsController.mjs.map +1 -1
  16. package/dist/constants/eventNames.cjs +22 -0
  17. package/dist/constants/eventNames.cjs.map +1 -1
  18. package/dist/constants/eventNames.d.cts +15 -0
  19. package/dist/constants/eventNames.d.cts.map +1 -1
  20. package/dist/constants/eventNames.d.mts +15 -0
  21. package/dist/constants/eventNames.d.mts.map +1 -1
  22. package/dist/constants/eventNames.mjs +22 -0
  23. package/dist/constants/eventNames.mjs.map +1 -1
  24. package/dist/constants/perpsConfig.cjs +22 -1
  25. package/dist/constants/perpsConfig.cjs.map +1 -1
  26. package/dist/constants/perpsConfig.d.cts +11 -0
  27. package/dist/constants/perpsConfig.d.cts.map +1 -1
  28. package/dist/constants/perpsConfig.d.mts +11 -0
  29. package/dist/constants/perpsConfig.d.mts.map +1 -1
  30. package/dist/constants/perpsConfig.mjs +21 -0
  31. package/dist/constants/perpsConfig.mjs.map +1 -1
  32. package/dist/index.cjs +4 -3
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +1 -1
  35. package/dist/index.d.cts.map +1 -1
  36. package/dist/index.d.mts +1 -1
  37. package/dist/index.d.mts.map +1 -1
  38. package/dist/index.mjs +1 -1
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/providers/HyperLiquidProvider.cjs +178 -40
  41. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  42. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  43. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  44. package/dist/providers/HyperLiquidProvider.mjs +179 -41
  45. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  46. package/dist/services/AccountService.cjs +1 -1
  47. package/dist/services/AccountService.cjs.map +1 -1
  48. package/dist/services/AccountService.d.cts.map +1 -1
  49. package/dist/services/AccountService.d.mts.map +1 -1
  50. package/dist/services/AccountService.mjs +2 -2
  51. package/dist/services/AccountService.mjs.map +1 -1
  52. package/dist/services/DataLakeService.cjs +1 -1
  53. package/dist/services/DataLakeService.cjs.map +1 -1
  54. package/dist/services/DataLakeService.d.cts.map +1 -1
  55. package/dist/services/DataLakeService.d.mts.map +1 -1
  56. package/dist/services/DataLakeService.mjs +2 -2
  57. package/dist/services/DataLakeService.mjs.map +1 -1
  58. package/dist/services/DepositService.cjs +2 -2
  59. package/dist/services/DepositService.cjs.map +1 -1
  60. package/dist/services/DepositService.d.cts.map +1 -1
  61. package/dist/services/DepositService.d.mts.map +1 -1
  62. package/dist/services/DepositService.mjs +3 -3
  63. package/dist/services/DepositService.mjs.map +1 -1
  64. package/dist/services/HyperLiquidWalletService.cjs +5 -5
  65. package/dist/services/HyperLiquidWalletService.cjs.map +1 -1
  66. package/dist/services/HyperLiquidWalletService.d.cts.map +1 -1
  67. package/dist/services/HyperLiquidWalletService.d.mts.map +1 -1
  68. package/dist/services/HyperLiquidWalletService.mjs +6 -6
  69. package/dist/services/HyperLiquidWalletService.mjs.map +1 -1
  70. package/dist/services/RewardsIntegrationService.cjs +1 -1
  71. package/dist/services/RewardsIntegrationService.cjs.map +1 -1
  72. package/dist/services/RewardsIntegrationService.d.cts.map +1 -1
  73. package/dist/services/RewardsIntegrationService.d.mts.map +1 -1
  74. package/dist/services/RewardsIntegrationService.mjs +2 -2
  75. package/dist/services/RewardsIntegrationService.mjs.map +1 -1
  76. package/dist/services/TradingReadinessCache.cjs +42 -2
  77. package/dist/services/TradingReadinessCache.cjs.map +1 -1
  78. package/dist/services/TradingReadinessCache.d.cts +29 -0
  79. package/dist/services/TradingReadinessCache.d.cts.map +1 -1
  80. package/dist/services/TradingReadinessCache.d.mts +29 -0
  81. package/dist/services/TradingReadinessCache.d.mts.map +1 -1
  82. package/dist/services/TradingReadinessCache.mjs +42 -2
  83. package/dist/services/TradingReadinessCache.mjs.map +1 -1
  84. package/dist/services/TradingService.cjs +27 -1
  85. package/dist/services/TradingService.cjs.map +1 -1
  86. package/dist/services/TradingService.d.cts +3 -1
  87. package/dist/services/TradingService.d.cts.map +1 -1
  88. package/dist/services/TradingService.d.mts +3 -1
  89. package/dist/services/TradingService.d.mts.map +1 -1
  90. package/dist/services/TradingService.mjs +27 -1
  91. package/dist/services/TradingService.mjs.map +1 -1
  92. package/dist/types/index.cjs.map +1 -1
  93. package/dist/types/index.d.cts +10 -1
  94. package/dist/types/index.d.cts.map +1 -1
  95. package/dist/types/index.d.mts +10 -1
  96. package/dist/types/index.d.mts.map +1 -1
  97. package/dist/types/index.mjs.map +1 -1
  98. package/dist/types/messenger.cjs.map +1 -1
  99. package/dist/types/messenger.d.cts +3 -2
  100. package/dist/types/messenger.d.cts.map +1 -1
  101. package/dist/types/messenger.d.mts +3 -2
  102. package/dist/types/messenger.d.mts.map +1 -1
  103. package/dist/types/messenger.mjs.map +1 -1
  104. package/dist/utils/accountUtils.cjs +38 -1
  105. package/dist/utils/accountUtils.cjs.map +1 -1
  106. package/dist/utils/accountUtils.d.cts +8 -0
  107. package/dist/utils/accountUtils.d.cts.map +1 -1
  108. package/dist/utils/accountUtils.d.mts +8 -0
  109. package/dist/utils/accountUtils.d.mts.map +1 -1
  110. package/dist/utils/accountUtils.mjs +35 -0
  111. package/dist/utils/accountUtils.mjs.map +1 -1
  112. package/dist/utils/errorUtils.cjs +15 -1
  113. package/dist/utils/errorUtils.cjs.map +1 -1
  114. package/dist/utils/errorUtils.d.cts +10 -0
  115. package/dist/utils/errorUtils.d.cts.map +1 -1
  116. package/dist/utils/errorUtils.d.mts +10 -0
  117. package/dist/utils/errorUtils.d.mts.map +1 -1
  118. package/dist/utils/errorUtils.mjs +13 -0
  119. package/dist/utils/errorUtils.mjs.map +1 -1
  120. package/dist/utils/orderCalculations.cjs +7 -3
  121. package/dist/utils/orderCalculations.cjs.map +1 -1
  122. package/dist/utils/orderCalculations.d.cts +1 -1
  123. package/dist/utils/orderCalculations.d.cts.map +1 -1
  124. package/dist/utils/orderCalculations.d.mts +1 -1
  125. package/dist/utils/orderCalculations.d.mts.map +1 -1
  126. package/dist/utils/orderCalculations.mjs +7 -3
  127. package/dist/utils/orderCalculations.mjs.map +1 -1
  128. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"messenger.mjs","sourceRoot":"","sources":["../../src/types/messenger.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AccountTreeControllerGetAccountsFromSelectedAccountGroupAction,\n AccountTreeControllerSelectedAccountGroupChangeEvent,\n} from '@metamask/account-tree-controller';\nimport type { GeolocationControllerGetGeolocationAction } from '@metamask/geolocation-controller';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerSignTypedMessageAction,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetStateAction,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerFindNetworkClientIdByChainIdAction,\n} from '@metamask/network-controller';\nimport type { AuthenticationController } from '@metamask/profile-sync-controller';\nimport type {\n RemoteFeatureFlagControllerGetStateAction,\n RemoteFeatureFlagControllerStateChangeEvent,\n} from '@metamask/remote-feature-flag-controller';\nimport type { TransactionControllerAddTransactionAction } from '@metamask/transaction-controller';\n\n/**\n * Actions from other controllers that PerpsController is allowed to call.\n */\nexport type PerpsControllerAllowedActions =\n | GeolocationControllerGetGeolocationAction\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerFindNetworkClientIdByChainIdAction\n | KeyringControllerGetStateAction\n | KeyringControllerSignTypedMessageAction\n | TransactionControllerAddTransactionAction\n | RemoteFeatureFlagControllerGetStateAction\n | AccountTreeControllerGetAccountsFromSelectedAccountGroupAction\n | AuthenticationController.AuthenticationControllerGetBearerTokenAction;\n\n/**\n * Events from other controllers that PerpsController is allowed to subscribe to.\n */\nexport type PerpsControllerAllowedEvents =\n | RemoteFeatureFlagControllerStateChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent;\n\n/**\n * The messenger type used by PerpsController and its services.\n * Defined here (rather than in PerpsController.ts) to avoid circular imports\n * between the controller and service files.\n *\n * The first two type parameters (Actions, Events) are filled in by\n * PerpsController.ts when it unions in its own actions/events.\n * Services use this base type directly since they only need the allowed\n * external actions/events.\n */\nexport type PerpsControllerMessengerBase = Messenger<\n 'PerpsController',\n PerpsControllerAllowedActions,\n PerpsControllerAllowedEvents\n>;\n"]}
1
+ {"version":3,"file":"messenger.mjs","sourceRoot":"","sources":["../../src/types/messenger.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AccountTreeControllerGetAccountsFromSelectedAccountGroupAction,\n AccountTreeControllerSelectedAccountGroupChangeEvent,\n} from '@metamask/account-tree-controller';\nimport type {\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerSelectedAccountChangeEvent,\n} from '@metamask/accounts-controller';\nimport type { GeolocationControllerGetGeolocationAction } from '@metamask/geolocation-controller';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerSignTypedMessageAction,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkControllerGetStateAction,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerFindNetworkClientIdByChainIdAction,\n} from '@metamask/network-controller';\nimport type { AuthenticationController } from '@metamask/profile-sync-controller';\nimport type {\n RemoteFeatureFlagControllerGetStateAction,\n RemoteFeatureFlagControllerStateChangeEvent,\n} from '@metamask/remote-feature-flag-controller';\nimport type { TransactionControllerAddTransactionAction } from '@metamask/transaction-controller';\n\n/**\n * Actions from other controllers that PerpsController is allowed to call.\n */\nexport type PerpsControllerAllowedActions =\n | GeolocationControllerGetGeolocationAction\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkControllerFindNetworkClientIdByChainIdAction\n | KeyringControllerGetStateAction\n | KeyringControllerSignTypedMessageAction\n | TransactionControllerAddTransactionAction\n | RemoteFeatureFlagControllerGetStateAction\n | AccountsControllerGetSelectedAccountAction\n | AccountTreeControllerGetAccountsFromSelectedAccountGroupAction\n | AuthenticationController.AuthenticationControllerGetBearerTokenAction;\n\n/**\n * Events from other controllers that PerpsController is allowed to subscribe to.\n */\nexport type PerpsControllerAllowedEvents =\n | RemoteFeatureFlagControllerStateChangeEvent\n | AccountsControllerSelectedAccountChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent;\n\n/**\n * The messenger type used by PerpsController and its services.\n * Defined here (rather than in PerpsController.ts) to avoid circular imports\n * between the controller and service files.\n *\n * The first two type parameters (Actions, Events) are filled in by\n * PerpsController.ts when it unions in its own actions/events.\n * Services use this base type directly since they only need the allowed\n * external actions/events.\n */\nexport type PerpsControllerMessengerBase = Messenger<\n 'PerpsController',\n PerpsControllerAllowedActions,\n PerpsControllerAllowedEvents\n>;\n"]}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.aggregateAccountStates = exports.addSpotBalanceToAccountState = exports.getSpotHold = exports.getSpotBalance = exports.calculateWeightedReturnOnEquity = exports.getSelectedEvmAccount = exports.getEvmAccountFromAccountGroup = exports.findEvmAccount = void 0;
3
+ exports.aggregateAccountStates = exports.addSpotBalanceToAccountState = exports.getSpotHold = exports.getSpotBalance = exports.calculateWeightedReturnOnEquity = exports.getSelectedEvmAccountFromMessenger = exports.getSelectedEvmAccountDetailsFromMessenger = exports.getSelectedEvmAccount = exports.getEvmAccountFromAccountGroup = exports.findEvmAccount = void 0;
4
4
  const perpsConfig_1 = require("../constants/perpsConfig.cjs");
5
5
  const EVM_ACCOUNT_TYPES = new Set(['eip155:eoa', 'eip155:erc4337']);
6
6
  function isEvmAccountType(type) {
@@ -20,6 +20,43 @@ function getSelectedEvmAccount(accounts) {
20
20
  return getEvmAccountFromAccountGroup(accounts);
21
21
  }
22
22
  exports.getSelectedEvmAccount = getSelectedEvmAccount;
23
+ function isAccountLike(value) {
24
+ const account = value;
25
+ return (typeof value === 'object' &&
26
+ value !== null &&
27
+ typeof account?.address === 'string' &&
28
+ typeof account.type === 'string');
29
+ }
30
+ function getSelectedEvmAccountDetailsFromMessenger(messenger) {
31
+ try {
32
+ const selectedAccount = messenger.call('AccountsController:getSelectedAccount');
33
+ if (isAccountLike(selectedAccount)) {
34
+ const evmAccount = findEvmAccount([selectedAccount]);
35
+ if (evmAccount) {
36
+ return evmAccount;
37
+ }
38
+ }
39
+ }
40
+ catch {
41
+ // Fall back to the selected account group if the direct lookup is unavailable.
42
+ }
43
+ try {
44
+ const selectedAccountGroup = messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
45
+ return Array.isArray(selectedAccountGroup)
46
+ ? (findEvmAccount(selectedAccountGroup.filter(isAccountLike)) ??
47
+ undefined)
48
+ : undefined;
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ }
54
+ exports.getSelectedEvmAccountDetailsFromMessenger = getSelectedEvmAccountDetailsFromMessenger;
55
+ function getSelectedEvmAccountFromMessenger(messenger) {
56
+ const evmAccount = getSelectedEvmAccountDetailsFromMessenger(messenger);
57
+ return evmAccount ? { address: evmAccount.address } : undefined;
58
+ }
59
+ exports.getSelectedEvmAccountFromMessenger = getSelectedEvmAccountFromMessenger;
23
60
  function calculateWeightedReturnOnEquity(accounts) {
24
61
  if (accounts.length === 0) {
25
62
  return '0';
@@ -1 +1 @@
1
- {"version":3,"file":"accountUtils.cjs","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Account utilities for Perps components\n * Handles account selection and EVM account filtering\n */\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { AccountState, PerpsInternalAccount } from '../types';\nimport type { SpotClearinghouseStateResponse } from '../types/hyperliquid-types';\n\nconst EVM_ACCOUNT_TYPES = new Set(['eip155:eoa', 'eip155:erc4337']);\n\nfunction isEvmAccountType(type: string): boolean {\n return EVM_ACCOUNT_TYPES.has(type);\n}\n\nexport function findEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): InternalAccount | PerpsInternalAccount | null {\n const evmAccount = accounts.find(\n (account) =>\n account && isEvmAccountType(account.type as InternalAccount['type']),\n );\n return evmAccount ?? null;\n}\n\nexport function getEvmAccountFromAccountGroup(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n const evmAccount = findEvmAccount(accounts);\n return evmAccount ? { address: evmAccount.address } : undefined;\n}\n\nexport function getSelectedEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n return getEvmAccountFromAccountGroup(accounts);\n}\n\nexport type ReturnOnEquityInput = {\n unrealizedPnl: string | number;\n returnOnEquity: string | number;\n};\n\nexport function calculateWeightedReturnOnEquity(\n accounts: ReturnOnEquityInput[],\n): string {\n if (accounts.length === 0) {\n return '0';\n }\n\n let totalWeightedROE = 0;\n let totalMarginUsed = 0;\n\n for (const account of accounts) {\n const unrealizedPnl =\n typeof account.unrealizedPnl === 'string'\n ? Number.parseFloat(account.unrealizedPnl)\n : account.unrealizedPnl;\n const returnOnEquity =\n typeof account.returnOnEquity === 'string'\n ? Number.parseFloat(account.returnOnEquity)\n : account.returnOnEquity;\n\n if (Number.isNaN(unrealizedPnl) || Number.isNaN(returnOnEquity)) {\n continue;\n }\n\n if (returnOnEquity === 0) {\n continue;\n }\n\n const marginUsed = (unrealizedPnl / returnOnEquity) * 100;\n\n if (Number.isNaN(marginUsed) || marginUsed <= 0) {\n continue;\n }\n\n const roeDecimal = returnOnEquity / 100;\n\n totalWeightedROE += roeDecimal * marginUsed;\n totalMarginUsed += marginUsed;\n }\n\n if (totalMarginUsed <= 0) {\n return '0';\n }\n\n const weightedROE = (totalWeightedROE / totalMarginUsed) * 100;\n return weightedROE.toString();\n}\n\n// The release-branch balance bridge is USDC-only. Non-USDC spot assets must\n// not inflate the balances shown or validated by withdraw/payment flows.\nconst SPOT_COLLATERAL_COINS = new Set<string>(['USDC']);\n\nexport function getSpotBalance(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; total?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.total ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\nexport function getSpotHold(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; hold?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.hold ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\n/**\n * Options controlling how `addSpotBalanceToAccountState` folds spot balance\n * into the three-field AccountState contract.\n */\nexport type AddSpotBalanceOptions = {\n /**\n * When `true`, free spot USDC contributes to both `spendableBalance` and\n * `withdrawableBalance` in addition to `totalBalance` — appropriate for\n * venues where spot is automatically used as perps collateral (e.g.\n * HyperLiquid Unified/Portfolio mode, where `withdraw3` draws from the\n * unified ledger).\n *\n * When `false`, free spot contributes to `totalBalance` only; spendable\n * and withdrawable stay perps-only — appropriate for venues where spot\n * is a separate ledger the backend cannot auto-draw from (e.g. HL\n * Standard mode). The caller is responsible for translating\n * provider-specific state into this flag.\n *\n * Defaults to `true` for backward compatibility with call sites that\n * haven't yet been wired with provider-specific context.\n */\n foldIntoCollateral?: boolean;\n};\n\n/**\n * Add spot USDC to the AccountState contract. Caller decides whether the\n * spot balance counts as perps collateral via `options.foldIntoCollateral`\n * — the util stays provider-agnostic.\n *\n * @param accountState - Base AccountState produced by a provider adapter.\n * @param spotState - Raw spot clearinghouse response (HL-shaped); null or missing means no spot balance and the state is returned unchanged.\n * @param options - See {@link AddSpotBalanceOptions}.\n * @returns AccountState with spot folded into `totalBalance` always, and into spendable/withdrawable when `foldIntoCollateral` is true.\n */\nexport function addSpotBalanceToAccountState(\n accountState: AccountState,\n spotState?: SpotClearinghouseStateResponse | null,\n options?: AddSpotBalanceOptions,\n): AccountState {\n // Fail-closed default: align with `hyperLiquidModeFoldsSpot(null) → false`.\n // A caller that omits `options` should NOT silently fold spot — that would\n // over-report withdrawable funds for Standard / dexAbstraction users.\n const foldIntoCollateral = options?.foldIntoCollateral ?? false;\n\n const spotBalance = getSpotBalance(spotState);\n const spotHold = getSpotHold(spotState);\n const freeSpot = Math.max(0, spotBalance - spotHold);\n\n const currentTotal = parseFloat(accountState.totalBalance);\n const currentSpendable = parseFloat(accountState.spendableBalance);\n const currentWithdrawable = parseFloat(accountState.withdrawableBalance);\n\n // Preserve sentinel totals (e.g. PERPS_CONSTANTS.FallbackDataDisplay '--')\n // rather than coercing them to NaN.\n if (!Number.isFinite(currentTotal)) {\n return accountState;\n }\n\n if (spotBalance === 0) {\n // No spot wealth means no hold either in the HL payload shape, so the\n // later totalBalance adjustment would also be a no-op.\n return accountState;\n }\n\n // Folding is gated strictly on the resolved abstraction mode (see callers'\n // `foldIntoCollateral` argument). Standard / DEX-abstraction users keep\n // perps and spot independent, so spot must NOT surface as a perps-\n // withdrawable balance for them — withdraw3 only draws from the perps\n // ledger in those modes. Unified / portfolio-margin users get the fold;\n // live callers fail-CLOSED via `hyperLiquidModeFoldsSpot` when mode is\n // unresolved.\n const nextSpendable = resolveFoldedBalance(\n currentSpendable,\n accountState.spendableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n const nextWithdrawable = resolveFoldedBalance(\n currentWithdrawable,\n accountState.withdrawableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n\n // Total always reflects combined wealth: subtract spotHold to avoid\n // double-counting on Unified/PM accounts where marginSummary.accountValue\n // already includes the margin that HL surfaces via spot.hold. Standard\n // mode has spotHold = 0 by construction, so the subtraction is a no-op.\n const nextTotal = currentTotal + spotBalance - spotHold;\n\n return {\n ...accountState,\n totalBalance: nextTotal.toString(),\n spendableBalance: nextSpendable,\n withdrawableBalance: nextWithdrawable,\n };\n}\n\nfunction resolveFoldedBalance(\n currentNumeric: number,\n currentRaw: string,\n freeSpot: number,\n foldIntoCollateral: boolean,\n): string {\n if (!foldIntoCollateral) {\n return currentRaw;\n }\n if (Number.isFinite(currentNumeric)) {\n return (currentNumeric + freeSpot).toString();\n }\n // Non-finite currentNumeric means the adapter passed a sentinel like\n // `PERPS_CONSTANTS.FallbackDataDisplay` (\"--\") during loading. Preserve\n // the sentinel rather than synthesising a numeric fold; the caller's\n // UI treats \"--\" as \"loading\" and would otherwise show a misleading\n // spot-only figure while the per-DEX perps fetch is still in flight.\n return currentRaw;\n}\n\n/**\n * Aggregate multiple per-DEX AccountState objects into one by summing numeric fields.\n * ROE is recalculated as (totalUnrealizedPnl / totalMarginUsed) * 100.\n *\n * @param states - The array of per-DEX account states to aggregate.\n * @returns The combined account state with summed balances and recalculated ROE.\n */\nexport function aggregateAccountStates(states: AccountState[]): AccountState {\n const fallback: AccountState = {\n spendableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n withdrawableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n totalBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n marginUsed: PERPS_CONSTANTS.FallbackDataDisplay,\n unrealizedPnl: PERPS_CONSTANTS.FallbackDataDisplay,\n returnOnEquity: PERPS_CONSTANTS.FallbackDataDisplay,\n };\n\n if (states.length === 0) {\n return fallback;\n }\n\n const aggregated = states.reduce<AccountState>((acc, state, index) => {\n if (index === 0) {\n return { ...state };\n }\n\n return {\n spendableBalance: (\n parseFloat(acc.spendableBalance) + parseFloat(state.spendableBalance)\n ).toString(),\n withdrawableBalance: (\n parseFloat(acc.withdrawableBalance) +\n parseFloat(state.withdrawableBalance)\n ).toString(),\n totalBalance: (\n parseFloat(acc.totalBalance) + parseFloat(state.totalBalance)\n ).toString(),\n marginUsed: (\n parseFloat(acc.marginUsed) + parseFloat(state.marginUsed)\n ).toString(),\n unrealizedPnl: (\n parseFloat(acc.unrealizedPnl) + parseFloat(state.unrealizedPnl)\n ).toString(),\n returnOnEquity: '0',\n };\n }, fallback);\n\n // Recalculate ROE across all DEXs\n const totalMarginUsed = parseFloat(aggregated.marginUsed);\n const totalUnrealizedPnl = parseFloat(aggregated.unrealizedPnl);\n if (totalMarginUsed > 0) {\n aggregated.returnOnEquity = (\n (totalUnrealizedPnl / totalMarginUsed) *\n 100\n ).toString();\n } else {\n aggregated.returnOnEquity = '0';\n }\n\n return aggregated;\n}\n"]}
1
+ {"version":3,"file":"accountUtils.cjs","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Account utilities for Perps components\n * Handles account selection and EVM account filtering\n */\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { AccountState, PerpsInternalAccount } from '../types';\nimport type { SpotClearinghouseStateResponse } from '../types/hyperliquid-types';\n\nconst EVM_ACCOUNT_TYPES = new Set(['eip155:eoa', 'eip155:erc4337']);\n\nfunction isEvmAccountType(type: string): boolean {\n return EVM_ACCOUNT_TYPES.has(type);\n}\n\nexport function findEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): InternalAccount | PerpsInternalAccount | null {\n const evmAccount = accounts.find(\n (account) =>\n account && isEvmAccountType(account.type as InternalAccount['type']),\n );\n return evmAccount ?? null;\n}\n\nexport function getEvmAccountFromAccountGroup(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n const evmAccount = findEvmAccount(accounts);\n return evmAccount ? { address: evmAccount.address } : undefined;\n}\n\nexport function getSelectedEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n return getEvmAccountFromAccountGroup(accounts);\n}\n\ntype SelectedEvmAccountMessenger = {\n call(\n actionType:\n | 'AccountsController:getSelectedAccount'\n | 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ): unknown;\n};\n\nfunction isAccountLike(\n value: unknown,\n): value is InternalAccount | PerpsInternalAccount {\n const account = value as { address?: unknown; type?: unknown } | null;\n\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof account?.address === 'string' &&\n typeof account.type === 'string'\n );\n}\n\nexport function getSelectedEvmAccountDetailsFromMessenger(\n messenger: SelectedEvmAccountMessenger,\n): InternalAccount | PerpsInternalAccount | undefined {\n try {\n const selectedAccount = messenger.call(\n 'AccountsController:getSelectedAccount',\n );\n if (isAccountLike(selectedAccount)) {\n const evmAccount = findEvmAccount([selectedAccount]);\n if (evmAccount) {\n return evmAccount;\n }\n }\n } catch {\n // Fall back to the selected account group if the direct lookup is unavailable.\n }\n\n try {\n const selectedAccountGroup = messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n );\n return Array.isArray(selectedAccountGroup)\n ? (findEvmAccount(selectedAccountGroup.filter(isAccountLike)) ??\n undefined)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function getSelectedEvmAccountFromMessenger(\n messenger: SelectedEvmAccountMessenger,\n): { address: string } | undefined {\n const evmAccount = getSelectedEvmAccountDetailsFromMessenger(messenger);\n\n return evmAccount ? { address: evmAccount.address } : undefined;\n}\n\nexport type ReturnOnEquityInput = {\n unrealizedPnl: string | number;\n returnOnEquity: string | number;\n};\n\nexport function calculateWeightedReturnOnEquity(\n accounts: ReturnOnEquityInput[],\n): string {\n if (accounts.length === 0) {\n return '0';\n }\n\n let totalWeightedROE = 0;\n let totalMarginUsed = 0;\n\n for (const account of accounts) {\n const unrealizedPnl =\n typeof account.unrealizedPnl === 'string'\n ? Number.parseFloat(account.unrealizedPnl)\n : account.unrealizedPnl;\n const returnOnEquity =\n typeof account.returnOnEquity === 'string'\n ? Number.parseFloat(account.returnOnEquity)\n : account.returnOnEquity;\n\n if (Number.isNaN(unrealizedPnl) || Number.isNaN(returnOnEquity)) {\n continue;\n }\n\n if (returnOnEquity === 0) {\n continue;\n }\n\n const marginUsed = (unrealizedPnl / returnOnEquity) * 100;\n\n if (Number.isNaN(marginUsed) || marginUsed <= 0) {\n continue;\n }\n\n const roeDecimal = returnOnEquity / 100;\n\n totalWeightedROE += roeDecimal * marginUsed;\n totalMarginUsed += marginUsed;\n }\n\n if (totalMarginUsed <= 0) {\n return '0';\n }\n\n const weightedROE = (totalWeightedROE / totalMarginUsed) * 100;\n return weightedROE.toString();\n}\n\n// The release-branch balance bridge is USDC-only. Non-USDC spot assets must\n// not inflate the balances shown or validated by withdraw/payment flows.\nconst SPOT_COLLATERAL_COINS = new Set<string>(['USDC']);\n\nexport function getSpotBalance(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; total?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.total ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\nexport function getSpotHold(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; hold?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.hold ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\n/**\n * Options controlling how `addSpotBalanceToAccountState` folds spot balance\n * into the three-field AccountState contract.\n */\nexport type AddSpotBalanceOptions = {\n /**\n * When `true`, free spot USDC contributes to both `spendableBalance` and\n * `withdrawableBalance` in addition to `totalBalance` — appropriate for\n * venues where spot is automatically used as perps collateral (e.g.\n * HyperLiquid Unified/Portfolio mode, where `withdraw3` draws from the\n * unified ledger).\n *\n * When `false`, free spot contributes to `totalBalance` only; spendable\n * and withdrawable stay perps-only — appropriate for venues where spot\n * is a separate ledger the backend cannot auto-draw from (e.g. HL\n * Standard mode). The caller is responsible for translating\n * provider-specific state into this flag.\n *\n * Defaults to `true` for backward compatibility with call sites that\n * haven't yet been wired with provider-specific context.\n */\n foldIntoCollateral?: boolean;\n};\n\n/**\n * Add spot USDC to the AccountState contract. Caller decides whether the\n * spot balance counts as perps collateral via `options.foldIntoCollateral`\n * — the util stays provider-agnostic.\n *\n * @param accountState - Base AccountState produced by a provider adapter.\n * @param spotState - Raw spot clearinghouse response (HL-shaped); null or missing means no spot balance and the state is returned unchanged.\n * @param options - See {@link AddSpotBalanceOptions}.\n * @returns AccountState with spot folded into `totalBalance` always, and into spendable/withdrawable when `foldIntoCollateral` is true.\n */\nexport function addSpotBalanceToAccountState(\n accountState: AccountState,\n spotState?: SpotClearinghouseStateResponse | null,\n options?: AddSpotBalanceOptions,\n): AccountState {\n // Fail-closed default: align with `hyperLiquidModeFoldsSpot(null) → false`.\n // A caller that omits `options` should NOT silently fold spot — that would\n // over-report withdrawable funds for Standard / dexAbstraction users.\n const foldIntoCollateral = options?.foldIntoCollateral ?? false;\n\n const spotBalance = getSpotBalance(spotState);\n const spotHold = getSpotHold(spotState);\n const freeSpot = Math.max(0, spotBalance - spotHold);\n\n const currentTotal = parseFloat(accountState.totalBalance);\n const currentSpendable = parseFloat(accountState.spendableBalance);\n const currentWithdrawable = parseFloat(accountState.withdrawableBalance);\n\n // Preserve sentinel totals (e.g. PERPS_CONSTANTS.FallbackDataDisplay '--')\n // rather than coercing them to NaN.\n if (!Number.isFinite(currentTotal)) {\n return accountState;\n }\n\n if (spotBalance === 0) {\n // No spot wealth means no hold either in the HL payload shape, so the\n // later totalBalance adjustment would also be a no-op.\n return accountState;\n }\n\n // Folding is gated strictly on the resolved abstraction mode (see callers'\n // `foldIntoCollateral` argument). Standard / DEX-abstraction users keep\n // perps and spot independent, so spot must NOT surface as a perps-\n // withdrawable balance for them — withdraw3 only draws from the perps\n // ledger in those modes. Unified / portfolio-margin users get the fold;\n // live callers fail-CLOSED via `hyperLiquidModeFoldsSpot` when mode is\n // unresolved.\n const nextSpendable = resolveFoldedBalance(\n currentSpendable,\n accountState.spendableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n const nextWithdrawable = resolveFoldedBalance(\n currentWithdrawable,\n accountState.withdrawableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n\n // Total always reflects combined wealth: subtract spotHold to avoid\n // double-counting on Unified/PM accounts where marginSummary.accountValue\n // already includes the margin that HL surfaces via spot.hold. Standard\n // mode has spotHold = 0 by construction, so the subtraction is a no-op.\n const nextTotal = currentTotal + spotBalance - spotHold;\n\n return {\n ...accountState,\n totalBalance: nextTotal.toString(),\n spendableBalance: nextSpendable,\n withdrawableBalance: nextWithdrawable,\n };\n}\n\nfunction resolveFoldedBalance(\n currentNumeric: number,\n currentRaw: string,\n freeSpot: number,\n foldIntoCollateral: boolean,\n): string {\n if (!foldIntoCollateral) {\n return currentRaw;\n }\n if (Number.isFinite(currentNumeric)) {\n return (currentNumeric + freeSpot).toString();\n }\n // Non-finite currentNumeric means the adapter passed a sentinel like\n // `PERPS_CONSTANTS.FallbackDataDisplay` (\"--\") during loading. Preserve\n // the sentinel rather than synthesising a numeric fold; the caller's\n // UI treats \"--\" as \"loading\" and would otherwise show a misleading\n // spot-only figure while the per-DEX perps fetch is still in flight.\n return currentRaw;\n}\n\n/**\n * Aggregate multiple per-DEX AccountState objects into one by summing numeric fields.\n * ROE is recalculated as (totalUnrealizedPnl / totalMarginUsed) * 100.\n *\n * @param states - The array of per-DEX account states to aggregate.\n * @returns The combined account state with summed balances and recalculated ROE.\n */\nexport function aggregateAccountStates(states: AccountState[]): AccountState {\n const fallback: AccountState = {\n spendableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n withdrawableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n totalBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n marginUsed: PERPS_CONSTANTS.FallbackDataDisplay,\n unrealizedPnl: PERPS_CONSTANTS.FallbackDataDisplay,\n returnOnEquity: PERPS_CONSTANTS.FallbackDataDisplay,\n };\n\n if (states.length === 0) {\n return fallback;\n }\n\n const aggregated = states.reduce<AccountState>((acc, state, index) => {\n if (index === 0) {\n return { ...state };\n }\n\n return {\n spendableBalance: (\n parseFloat(acc.spendableBalance) + parseFloat(state.spendableBalance)\n ).toString(),\n withdrawableBalance: (\n parseFloat(acc.withdrawableBalance) +\n parseFloat(state.withdrawableBalance)\n ).toString(),\n totalBalance: (\n parseFloat(acc.totalBalance) + parseFloat(state.totalBalance)\n ).toString(),\n marginUsed: (\n parseFloat(acc.marginUsed) + parseFloat(state.marginUsed)\n ).toString(),\n unrealizedPnl: (\n parseFloat(acc.unrealizedPnl) + parseFloat(state.unrealizedPnl)\n ).toString(),\n returnOnEquity: '0',\n };\n }, fallback);\n\n // Recalculate ROE across all DEXs\n const totalMarginUsed = parseFloat(aggregated.marginUsed);\n const totalUnrealizedPnl = parseFloat(aggregated.unrealizedPnl);\n if (totalMarginUsed > 0) {\n aggregated.returnOnEquity = (\n (totalUnrealizedPnl / totalMarginUsed) *\n 100\n ).toString();\n } else {\n aggregated.returnOnEquity = '0';\n }\n\n return aggregated;\n}\n"]}
@@ -12,6 +12,13 @@ export declare function getEvmAccountFromAccountGroup(accounts: (InternalAccount
12
12
  export declare function getSelectedEvmAccount(accounts: (InternalAccount | PerpsInternalAccount)[]): {
13
13
  address: string;
14
14
  } | undefined;
15
+ type SelectedEvmAccountMessenger = {
16
+ call(actionType: 'AccountsController:getSelectedAccount' | 'AccountTreeController:getAccountsFromSelectedAccountGroup'): unknown;
17
+ };
18
+ export declare function getSelectedEvmAccountDetailsFromMessenger(messenger: SelectedEvmAccountMessenger): InternalAccount | PerpsInternalAccount | undefined;
19
+ export declare function getSelectedEvmAccountFromMessenger(messenger: SelectedEvmAccountMessenger): {
20
+ address: string;
21
+ } | undefined;
15
22
  export type ReturnOnEquityInput = {
16
23
  unrealizedPnl: string | number;
17
24
  returnOnEquity: string | number;
@@ -61,4 +68,5 @@ export declare function addSpotBalanceToAccountState(accountState: AccountState,
61
68
  * @returns The combined account state with summed balances and recalculated ROE.
62
69
  */
63
70
  export declare function aggregateAccountStates(states: AccountState[]): AccountState;
71
+ export {};
64
72
  //# sourceMappingURL=accountUtils.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"accountUtils.d.cts","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAGtE,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,2BAAiB;AACnE,OAAO,KAAK,EAAE,8BAA8B,EAAE,uCAAmC;AAQjF,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD,eAAe,GAAG,oBAAoB,GAAG,IAAI,CAM/C;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAGjC;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAEjC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,mBAAmB,EAAE,GAC9B,MAAM,CA4CR;AAMD,wBAAgB,cAAc,CAC5B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED,wBAAgB,WAAW,CACzB,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,EACjD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,YAAY,CA0Dd;AAsBD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAqD3E"}
1
+ {"version":3,"file":"accountUtils.d.cts","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAGtE,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,2BAAiB;AACnE,OAAO,KAAK,EAAE,8BAA8B,EAAE,uCAAmC;AAQjF,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD,eAAe,GAAG,oBAAoB,GAAG,IAAI,CAM/C;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAGjC;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAEjC;AAED,KAAK,2BAA2B,GAAG;IACjC,IAAI,CACF,UAAU,EACN,uCAAuC,GACvC,2DAA2D,GAC9D,OAAO,CAAC;CACZ,CAAC;AAeF,wBAAgB,yCAAyC,CACvD,SAAS,EAAE,2BAA2B,GACrC,eAAe,GAAG,oBAAoB,GAAG,SAAS,CA0BpD;AAED,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,2BAA2B,GACrC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAIjC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,mBAAmB,EAAE,GAC9B,MAAM,CA4CR;AAMD,wBAAgB,cAAc,CAC5B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED,wBAAgB,WAAW,CACzB,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,EACjD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,YAAY,CA0Dd;AAsBD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAqD3E"}
@@ -12,6 +12,13 @@ export declare function getEvmAccountFromAccountGroup(accounts: (InternalAccount
12
12
  export declare function getSelectedEvmAccount(accounts: (InternalAccount | PerpsInternalAccount)[]): {
13
13
  address: string;
14
14
  } | undefined;
15
+ type SelectedEvmAccountMessenger = {
16
+ call(actionType: 'AccountsController:getSelectedAccount' | 'AccountTreeController:getAccountsFromSelectedAccountGroup'): unknown;
17
+ };
18
+ export declare function getSelectedEvmAccountDetailsFromMessenger(messenger: SelectedEvmAccountMessenger): InternalAccount | PerpsInternalAccount | undefined;
19
+ export declare function getSelectedEvmAccountFromMessenger(messenger: SelectedEvmAccountMessenger): {
20
+ address: string;
21
+ } | undefined;
15
22
  export type ReturnOnEquityInput = {
16
23
  unrealizedPnl: string | number;
17
24
  returnOnEquity: string | number;
@@ -61,4 +68,5 @@ export declare function addSpotBalanceToAccountState(accountState: AccountState,
61
68
  * @returns The combined account state with summed balances and recalculated ROE.
62
69
  */
63
70
  export declare function aggregateAccountStates(states: AccountState[]): AccountState;
71
+ export {};
64
72
  //# sourceMappingURL=accountUtils.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"accountUtils.d.mts","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAGtE,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,2BAAiB;AACnE,OAAO,KAAK,EAAE,8BAA8B,EAAE,uCAAmC;AAQjF,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD,eAAe,GAAG,oBAAoB,GAAG,IAAI,CAM/C;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAGjC;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAEjC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,mBAAmB,EAAE,GAC9B,MAAM,CA4CR;AAMD,wBAAgB,cAAc,CAC5B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED,wBAAgB,WAAW,CACzB,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,EACjD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,YAAY,CA0Dd;AAsBD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAqD3E"}
1
+ {"version":3,"file":"accountUtils.d.mts","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAGtE,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,2BAAiB;AACnE,OAAO,KAAK,EAAE,8BAA8B,EAAE,uCAAmC;AAQjF,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD,eAAe,GAAG,oBAAoB,GAAG,IAAI,CAM/C;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAGjC;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,GACnD;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAEjC;AAED,KAAK,2BAA2B,GAAG;IACjC,IAAI,CACF,UAAU,EACN,uCAAuC,GACvC,2DAA2D,GAC9D,OAAO,CAAC;CACZ,CAAC;AAeF,wBAAgB,yCAAyC,CACvD,SAAS,EAAE,2BAA2B,GACrC,eAAe,GAAG,oBAAoB,GAAG,SAAS,CA0BpD;AAED,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,2BAA2B,GACrC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAIjC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,mBAAmB,EAAE,GAC9B,MAAM,CA4CR;AAMD,wBAAgB,cAAc,CAC5B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED,wBAAgB,WAAW,CACzB,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,GAChD,MAAM,CAeR;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,EACjD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,YAAY,CA0Dd;AAsBD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAqD3E"}
@@ -14,6 +14,41 @@ export function getEvmAccountFromAccountGroup(accounts) {
14
14
  export function getSelectedEvmAccount(accounts) {
15
15
  return getEvmAccountFromAccountGroup(accounts);
16
16
  }
17
+ function isAccountLike(value) {
18
+ const account = value;
19
+ return (typeof value === 'object' &&
20
+ value !== null &&
21
+ typeof account?.address === 'string' &&
22
+ typeof account.type === 'string');
23
+ }
24
+ export function getSelectedEvmAccountDetailsFromMessenger(messenger) {
25
+ try {
26
+ const selectedAccount = messenger.call('AccountsController:getSelectedAccount');
27
+ if (isAccountLike(selectedAccount)) {
28
+ const evmAccount = findEvmAccount([selectedAccount]);
29
+ if (evmAccount) {
30
+ return evmAccount;
31
+ }
32
+ }
33
+ }
34
+ catch {
35
+ // Fall back to the selected account group if the direct lookup is unavailable.
36
+ }
37
+ try {
38
+ const selectedAccountGroup = messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
39
+ return Array.isArray(selectedAccountGroup)
40
+ ? (findEvmAccount(selectedAccountGroup.filter(isAccountLike)) ??
41
+ undefined)
42
+ : undefined;
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ export function getSelectedEvmAccountFromMessenger(messenger) {
49
+ const evmAccount = getSelectedEvmAccountDetailsFromMessenger(messenger);
50
+ return evmAccount ? { address: evmAccount.address } : undefined;
51
+ }
17
52
  export function calculateWeightedReturnOnEquity(accounts) {
18
53
  if (accounts.length === 0) {
19
54
  return '0';
@@ -1 +1 @@
1
- {"version":3,"file":"accountUtils.mjs","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,qCAAiC;AAI3D,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEpE,SAAS,gBAAgB,CAAC,IAAY;IACpC,OAAO,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,QAAoD;IAEpD,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAC9B,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,IAA+B,CAAC,CACvE,CAAC;IACF,OAAO,UAAU,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,QAAoD;IAEpD,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC5C,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAoD;IAEpD,OAAO,6BAA6B,CAAC,QAAQ,CAAC,CAAC;AACjD,CAAC;AAOD,MAAM,UAAU,+BAA+B,CAC7C,QAA+B;IAE/B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,aAAa,GACjB,OAAO,OAAO,CAAC,aAAa,KAAK,QAAQ;YACvC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC;YAC1C,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;QAC5B,MAAM,cAAc,GAClB,OAAO,OAAO,CAAC,cAAc,KAAK,QAAQ;YACxC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC;YAC3C,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;QAE7B,IAAI,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;YAChE,SAAS;QACX,CAAC;QAED,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;YACzB,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,CAAC,aAAa,GAAG,cAAc,CAAC,GAAG,GAAG,CAAC;QAE1D,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;YAChD,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,cAAc,GAAG,GAAG,CAAC;QAExC,gBAAgB,IAAI,UAAU,GAAG,UAAU,CAAC;QAC5C,eAAe,IAAI,UAAU,CAAC;IAChC,CAAC;IAED,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,gBAAgB,GAAG,eAAe,CAAC,GAAG,GAAG,CAAC;IAC/D,OAAO,WAAW,CAAC,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED,4EAA4E;AAC5E,yEAAyE;AACzE,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AAExD,MAAM,UAAU,cAAc,CAC5B,SAAiD;IAEjD,IAAI,CAAC,SAAS,EAAE,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,SAAS,CAAC,QAAQ,CAAC,MAAM,CAC9B,CAAC,GAAW,EAAE,OAA0C,EAAE,EAAE;QAC1D,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,OAAO,GAAG,CAAC;QACb,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,CAAC,EACD,CAAC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,SAAiD;IAEjD,IAAI,CAAC,SAAS,EAAE,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,SAAS,CAAC,QAAQ,CAAC,MAAM,CAC9B,CAAC,GAAW,EAAE,OAAyC,EAAE,EAAE;QACzD,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,OAAO,GAAG,CAAC;QACb,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;QAC9C,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,CAAC,EACD,CAAC,CACF,CAAC;AACJ,CAAC;AA0BD;;;;;;;;;GASG;AACH,MAAM,UAAU,4BAA4B,CAC1C,YAA0B,EAC1B,SAAiD,EACjD,OAA+B;IAE/B,4EAA4E;IAC5E,2EAA2E;IAC3E,sEAAsE;IACtE,MAAM,kBAAkB,GAAG,OAAO,EAAE,kBAAkB,IAAI,KAAK,CAAC;IAEhE,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC,CAAC;IAErD,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IAC3D,MAAM,gBAAgB,GAAG,UAAU,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;IACnE,MAAM,mBAAmB,GAAG,UAAU,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC;IAEzE,2EAA2E;IAC3E,oCAAoC;IACpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnC,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;QACtB,sEAAsE;QACtE,uDAAuD;QACvD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,2EAA2E;IAC3E,wEAAwE;IACxE,mEAAmE;IACnE,sEAAsE;IACtE,wEAAwE;IACxE,uEAAuE;IACvE,cAAc;IACd,MAAM,aAAa,GAAG,oBAAoB,CACxC,gBAAgB,EAChB,YAAY,CAAC,gBAAgB,EAC7B,QAAQ,EACR,kBAAkB,CACnB,CAAC;IACF,MAAM,gBAAgB,GAAG,oBAAoB,CAC3C,mBAAmB,EACnB,YAAY,CAAC,mBAAmB,EAChC,QAAQ,EACR,kBAAkB,CACnB,CAAC;IAEF,oEAAoE;IACpE,0EAA0E;IAC1E,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAExD,OAAO;QACL,GAAG,YAAY;QACf,YAAY,EAAE,SAAS,CAAC,QAAQ,EAAE;QAClC,gBAAgB,EAAE,aAAa;QAC/B,mBAAmB,EAAE,gBAAgB;KACtC,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAC3B,cAAsB,EACtB,UAAkB,EAClB,QAAgB,EAChB,kBAA2B;IAE3B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,cAAc,GAAG,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,CAAC;IACD,qEAAqE;IACrE,wEAAwE;IACxE,qEAAqE;IACrE,oEAAoE;IACpE,qEAAqE;IACrE,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAsB;IAC3D,MAAM,QAAQ,GAAiB;QAC7B,gBAAgB,EAAE,eAAe,CAAC,mBAAmB;QACrD,mBAAmB,EAAE,eAAe,CAAC,mBAAmB;QACxD,YAAY,EAAE,eAAe,CAAC,mBAAmB;QACjD,UAAU,EAAE,eAAe,CAAC,mBAAmB;QAC/C,aAAa,EAAE,eAAe,CAAC,mBAAmB;QAClD,cAAc,EAAE,eAAe,CAAC,mBAAmB;KACpD,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAe,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACnE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QACtB,CAAC;QAED,OAAO;YACL,gBAAgB,EAAE,CAChB,UAAU,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,gBAAgB,CAAC,CACtE,CAAC,QAAQ,EAAE;YACZ,mBAAmB,EAAE,CACnB,UAAU,CAAC,GAAG,CAAC,mBAAmB,CAAC;gBACnC,UAAU,CAAC,KAAK,CAAC,mBAAmB,CAAC,CACtC,CAAC,QAAQ,EAAE;YACZ,YAAY,EAAE,CACZ,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,CAC9D,CAAC,QAAQ,EAAE;YACZ,UAAU,EAAE,CACV,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAC1D,CAAC,QAAQ,EAAE;YACZ,aAAa,EAAE,CACb,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAChE,CAAC,QAAQ,EAAE;YACZ,cAAc,EAAE,GAAG;SACpB,CAAC;IACJ,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEb,kCAAkC;IAClC,MAAM,eAAe,GAAG,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC1D,MAAM,kBAAkB,GAAG,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAChE,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;QACxB,UAAU,CAAC,cAAc,GAAG,CAC1B,CAAC,kBAAkB,GAAG,eAAe,CAAC;YACtC,GAAG,CACJ,CAAC,QAAQ,EAAE,CAAC;IACf,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,cAAc,GAAG,GAAG,CAAC;IAClC,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC","sourcesContent":["/**\n * Account utilities for Perps components\n * Handles account selection and EVM account filtering\n */\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { AccountState, PerpsInternalAccount } from '../types';\nimport type { SpotClearinghouseStateResponse } from '../types/hyperliquid-types';\n\nconst EVM_ACCOUNT_TYPES = new Set(['eip155:eoa', 'eip155:erc4337']);\n\nfunction isEvmAccountType(type: string): boolean {\n return EVM_ACCOUNT_TYPES.has(type);\n}\n\nexport function findEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): InternalAccount | PerpsInternalAccount | null {\n const evmAccount = accounts.find(\n (account) =>\n account && isEvmAccountType(account.type as InternalAccount['type']),\n );\n return evmAccount ?? null;\n}\n\nexport function getEvmAccountFromAccountGroup(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n const evmAccount = findEvmAccount(accounts);\n return evmAccount ? { address: evmAccount.address } : undefined;\n}\n\nexport function getSelectedEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n return getEvmAccountFromAccountGroup(accounts);\n}\n\nexport type ReturnOnEquityInput = {\n unrealizedPnl: string | number;\n returnOnEquity: string | number;\n};\n\nexport function calculateWeightedReturnOnEquity(\n accounts: ReturnOnEquityInput[],\n): string {\n if (accounts.length === 0) {\n return '0';\n }\n\n let totalWeightedROE = 0;\n let totalMarginUsed = 0;\n\n for (const account of accounts) {\n const unrealizedPnl =\n typeof account.unrealizedPnl === 'string'\n ? Number.parseFloat(account.unrealizedPnl)\n : account.unrealizedPnl;\n const returnOnEquity =\n typeof account.returnOnEquity === 'string'\n ? Number.parseFloat(account.returnOnEquity)\n : account.returnOnEquity;\n\n if (Number.isNaN(unrealizedPnl) || Number.isNaN(returnOnEquity)) {\n continue;\n }\n\n if (returnOnEquity === 0) {\n continue;\n }\n\n const marginUsed = (unrealizedPnl / returnOnEquity) * 100;\n\n if (Number.isNaN(marginUsed) || marginUsed <= 0) {\n continue;\n }\n\n const roeDecimal = returnOnEquity / 100;\n\n totalWeightedROE += roeDecimal * marginUsed;\n totalMarginUsed += marginUsed;\n }\n\n if (totalMarginUsed <= 0) {\n return '0';\n }\n\n const weightedROE = (totalWeightedROE / totalMarginUsed) * 100;\n return weightedROE.toString();\n}\n\n// The release-branch balance bridge is USDC-only. Non-USDC spot assets must\n// not inflate the balances shown or validated by withdraw/payment flows.\nconst SPOT_COLLATERAL_COINS = new Set<string>(['USDC']);\n\nexport function getSpotBalance(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; total?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.total ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\nexport function getSpotHold(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; hold?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.hold ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\n/**\n * Options controlling how `addSpotBalanceToAccountState` folds spot balance\n * into the three-field AccountState contract.\n */\nexport type AddSpotBalanceOptions = {\n /**\n * When `true`, free spot USDC contributes to both `spendableBalance` and\n * `withdrawableBalance` in addition to `totalBalance` — appropriate for\n * venues where spot is automatically used as perps collateral (e.g.\n * HyperLiquid Unified/Portfolio mode, where `withdraw3` draws from the\n * unified ledger).\n *\n * When `false`, free spot contributes to `totalBalance` only; spendable\n * and withdrawable stay perps-only — appropriate for venues where spot\n * is a separate ledger the backend cannot auto-draw from (e.g. HL\n * Standard mode). The caller is responsible for translating\n * provider-specific state into this flag.\n *\n * Defaults to `true` for backward compatibility with call sites that\n * haven't yet been wired with provider-specific context.\n */\n foldIntoCollateral?: boolean;\n};\n\n/**\n * Add spot USDC to the AccountState contract. Caller decides whether the\n * spot balance counts as perps collateral via `options.foldIntoCollateral`\n * — the util stays provider-agnostic.\n *\n * @param accountState - Base AccountState produced by a provider adapter.\n * @param spotState - Raw spot clearinghouse response (HL-shaped); null or missing means no spot balance and the state is returned unchanged.\n * @param options - See {@link AddSpotBalanceOptions}.\n * @returns AccountState with spot folded into `totalBalance` always, and into spendable/withdrawable when `foldIntoCollateral` is true.\n */\nexport function addSpotBalanceToAccountState(\n accountState: AccountState,\n spotState?: SpotClearinghouseStateResponse | null,\n options?: AddSpotBalanceOptions,\n): AccountState {\n // Fail-closed default: align with `hyperLiquidModeFoldsSpot(null) → false`.\n // A caller that omits `options` should NOT silently fold spot — that would\n // over-report withdrawable funds for Standard / dexAbstraction users.\n const foldIntoCollateral = options?.foldIntoCollateral ?? false;\n\n const spotBalance = getSpotBalance(spotState);\n const spotHold = getSpotHold(spotState);\n const freeSpot = Math.max(0, spotBalance - spotHold);\n\n const currentTotal = parseFloat(accountState.totalBalance);\n const currentSpendable = parseFloat(accountState.spendableBalance);\n const currentWithdrawable = parseFloat(accountState.withdrawableBalance);\n\n // Preserve sentinel totals (e.g. PERPS_CONSTANTS.FallbackDataDisplay '--')\n // rather than coercing them to NaN.\n if (!Number.isFinite(currentTotal)) {\n return accountState;\n }\n\n if (spotBalance === 0) {\n // No spot wealth means no hold either in the HL payload shape, so the\n // later totalBalance adjustment would also be a no-op.\n return accountState;\n }\n\n // Folding is gated strictly on the resolved abstraction mode (see callers'\n // `foldIntoCollateral` argument). Standard / DEX-abstraction users keep\n // perps and spot independent, so spot must NOT surface as a perps-\n // withdrawable balance for them — withdraw3 only draws from the perps\n // ledger in those modes. Unified / portfolio-margin users get the fold;\n // live callers fail-CLOSED via `hyperLiquidModeFoldsSpot` when mode is\n // unresolved.\n const nextSpendable = resolveFoldedBalance(\n currentSpendable,\n accountState.spendableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n const nextWithdrawable = resolveFoldedBalance(\n currentWithdrawable,\n accountState.withdrawableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n\n // Total always reflects combined wealth: subtract spotHold to avoid\n // double-counting on Unified/PM accounts where marginSummary.accountValue\n // already includes the margin that HL surfaces via spot.hold. Standard\n // mode has spotHold = 0 by construction, so the subtraction is a no-op.\n const nextTotal = currentTotal + spotBalance - spotHold;\n\n return {\n ...accountState,\n totalBalance: nextTotal.toString(),\n spendableBalance: nextSpendable,\n withdrawableBalance: nextWithdrawable,\n };\n}\n\nfunction resolveFoldedBalance(\n currentNumeric: number,\n currentRaw: string,\n freeSpot: number,\n foldIntoCollateral: boolean,\n): string {\n if (!foldIntoCollateral) {\n return currentRaw;\n }\n if (Number.isFinite(currentNumeric)) {\n return (currentNumeric + freeSpot).toString();\n }\n // Non-finite currentNumeric means the adapter passed a sentinel like\n // `PERPS_CONSTANTS.FallbackDataDisplay` (\"--\") during loading. Preserve\n // the sentinel rather than synthesising a numeric fold; the caller's\n // UI treats \"--\" as \"loading\" and would otherwise show a misleading\n // spot-only figure while the per-DEX perps fetch is still in flight.\n return currentRaw;\n}\n\n/**\n * Aggregate multiple per-DEX AccountState objects into one by summing numeric fields.\n * ROE is recalculated as (totalUnrealizedPnl / totalMarginUsed) * 100.\n *\n * @param states - The array of per-DEX account states to aggregate.\n * @returns The combined account state with summed balances and recalculated ROE.\n */\nexport function aggregateAccountStates(states: AccountState[]): AccountState {\n const fallback: AccountState = {\n spendableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n withdrawableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n totalBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n marginUsed: PERPS_CONSTANTS.FallbackDataDisplay,\n unrealizedPnl: PERPS_CONSTANTS.FallbackDataDisplay,\n returnOnEquity: PERPS_CONSTANTS.FallbackDataDisplay,\n };\n\n if (states.length === 0) {\n return fallback;\n }\n\n const aggregated = states.reduce<AccountState>((acc, state, index) => {\n if (index === 0) {\n return { ...state };\n }\n\n return {\n spendableBalance: (\n parseFloat(acc.spendableBalance) + parseFloat(state.spendableBalance)\n ).toString(),\n withdrawableBalance: (\n parseFloat(acc.withdrawableBalance) +\n parseFloat(state.withdrawableBalance)\n ).toString(),\n totalBalance: (\n parseFloat(acc.totalBalance) + parseFloat(state.totalBalance)\n ).toString(),\n marginUsed: (\n parseFloat(acc.marginUsed) + parseFloat(state.marginUsed)\n ).toString(),\n unrealizedPnl: (\n parseFloat(acc.unrealizedPnl) + parseFloat(state.unrealizedPnl)\n ).toString(),\n returnOnEquity: '0',\n };\n }, fallback);\n\n // Recalculate ROE across all DEXs\n const totalMarginUsed = parseFloat(aggregated.marginUsed);\n const totalUnrealizedPnl = parseFloat(aggregated.unrealizedPnl);\n if (totalMarginUsed > 0) {\n aggregated.returnOnEquity = (\n (totalUnrealizedPnl / totalMarginUsed) *\n 100\n ).toString();\n } else {\n aggregated.returnOnEquity = '0';\n }\n\n return aggregated;\n}\n"]}
1
+ {"version":3,"file":"accountUtils.mjs","sourceRoot":"","sources":["../../src/utils/accountUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Account utilities for Perps components\n * Handles account selection and EVM account filtering\n */\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { AccountState, PerpsInternalAccount } from '../types';\nimport type { SpotClearinghouseStateResponse } from '../types/hyperliquid-types';\n\nconst EVM_ACCOUNT_TYPES = new Set(['eip155:eoa', 'eip155:erc4337']);\n\nfunction isEvmAccountType(type: string): boolean {\n return EVM_ACCOUNT_TYPES.has(type);\n}\n\nexport function findEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): InternalAccount | PerpsInternalAccount | null {\n const evmAccount = accounts.find(\n (account) =>\n account && isEvmAccountType(account.type as InternalAccount['type']),\n );\n return evmAccount ?? null;\n}\n\nexport function getEvmAccountFromAccountGroup(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n const evmAccount = findEvmAccount(accounts);\n return evmAccount ? { address: evmAccount.address } : undefined;\n}\n\nexport function getSelectedEvmAccount(\n accounts: (InternalAccount | PerpsInternalAccount)[],\n): { address: string } | undefined {\n return getEvmAccountFromAccountGroup(accounts);\n}\n\ntype SelectedEvmAccountMessenger = {\n call(\n actionType:\n | 'AccountsController:getSelectedAccount'\n | 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ): unknown;\n};\n\nfunction isAccountLike(\n value: unknown,\n): value is InternalAccount | PerpsInternalAccount {\n const account = value as { address?: unknown; type?: unknown } | null;\n\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof account?.address === 'string' &&\n typeof account.type === 'string'\n );\n}\n\nexport function getSelectedEvmAccountDetailsFromMessenger(\n messenger: SelectedEvmAccountMessenger,\n): InternalAccount | PerpsInternalAccount | undefined {\n try {\n const selectedAccount = messenger.call(\n 'AccountsController:getSelectedAccount',\n );\n if (isAccountLike(selectedAccount)) {\n const evmAccount = findEvmAccount([selectedAccount]);\n if (evmAccount) {\n return evmAccount;\n }\n }\n } catch {\n // Fall back to the selected account group if the direct lookup is unavailable.\n }\n\n try {\n const selectedAccountGroup = messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n );\n return Array.isArray(selectedAccountGroup)\n ? (findEvmAccount(selectedAccountGroup.filter(isAccountLike)) ??\n undefined)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function getSelectedEvmAccountFromMessenger(\n messenger: SelectedEvmAccountMessenger,\n): { address: string } | undefined {\n const evmAccount = getSelectedEvmAccountDetailsFromMessenger(messenger);\n\n return evmAccount ? { address: evmAccount.address } : undefined;\n}\n\nexport type ReturnOnEquityInput = {\n unrealizedPnl: string | number;\n returnOnEquity: string | number;\n};\n\nexport function calculateWeightedReturnOnEquity(\n accounts: ReturnOnEquityInput[],\n): string {\n if (accounts.length === 0) {\n return '0';\n }\n\n let totalWeightedROE = 0;\n let totalMarginUsed = 0;\n\n for (const account of accounts) {\n const unrealizedPnl =\n typeof account.unrealizedPnl === 'string'\n ? Number.parseFloat(account.unrealizedPnl)\n : account.unrealizedPnl;\n const returnOnEquity =\n typeof account.returnOnEquity === 'string'\n ? Number.parseFloat(account.returnOnEquity)\n : account.returnOnEquity;\n\n if (Number.isNaN(unrealizedPnl) || Number.isNaN(returnOnEquity)) {\n continue;\n }\n\n if (returnOnEquity === 0) {\n continue;\n }\n\n const marginUsed = (unrealizedPnl / returnOnEquity) * 100;\n\n if (Number.isNaN(marginUsed) || marginUsed <= 0) {\n continue;\n }\n\n const roeDecimal = returnOnEquity / 100;\n\n totalWeightedROE += roeDecimal * marginUsed;\n totalMarginUsed += marginUsed;\n }\n\n if (totalMarginUsed <= 0) {\n return '0';\n }\n\n const weightedROE = (totalWeightedROE / totalMarginUsed) * 100;\n return weightedROE.toString();\n}\n\n// The release-branch balance bridge is USDC-only. Non-USDC spot assets must\n// not inflate the balances shown or validated by withdraw/payment flows.\nconst SPOT_COLLATERAL_COINS = new Set<string>(['USDC']);\n\nexport function getSpotBalance(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; total?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.total ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\nexport function getSpotHold(\n spotState?: SpotClearinghouseStateResponse | null,\n): number {\n if (!spotState?.balances || !Array.isArray(spotState.balances)) {\n return 0;\n }\n\n return spotState.balances.reduce(\n (sum: number, balance: { coin?: string; hold?: string }) => {\n if (!balance.coin || !SPOT_COLLATERAL_COINS.has(balance.coin)) {\n return sum;\n }\n const value = parseFloat(balance.hold ?? '0');\n return Number.isFinite(value) ? sum + value : sum;\n },\n 0,\n );\n}\n\n/**\n * Options controlling how `addSpotBalanceToAccountState` folds spot balance\n * into the three-field AccountState contract.\n */\nexport type AddSpotBalanceOptions = {\n /**\n * When `true`, free spot USDC contributes to both `spendableBalance` and\n * `withdrawableBalance` in addition to `totalBalance` — appropriate for\n * venues where spot is automatically used as perps collateral (e.g.\n * HyperLiquid Unified/Portfolio mode, where `withdraw3` draws from the\n * unified ledger).\n *\n * When `false`, free spot contributes to `totalBalance` only; spendable\n * and withdrawable stay perps-only — appropriate for venues where spot\n * is a separate ledger the backend cannot auto-draw from (e.g. HL\n * Standard mode). The caller is responsible for translating\n * provider-specific state into this flag.\n *\n * Defaults to `true` for backward compatibility with call sites that\n * haven't yet been wired with provider-specific context.\n */\n foldIntoCollateral?: boolean;\n};\n\n/**\n * Add spot USDC to the AccountState contract. Caller decides whether the\n * spot balance counts as perps collateral via `options.foldIntoCollateral`\n * — the util stays provider-agnostic.\n *\n * @param accountState - Base AccountState produced by a provider adapter.\n * @param spotState - Raw spot clearinghouse response (HL-shaped); null or missing means no spot balance and the state is returned unchanged.\n * @param options - See {@link AddSpotBalanceOptions}.\n * @returns AccountState with spot folded into `totalBalance` always, and into spendable/withdrawable when `foldIntoCollateral` is true.\n */\nexport function addSpotBalanceToAccountState(\n accountState: AccountState,\n spotState?: SpotClearinghouseStateResponse | null,\n options?: AddSpotBalanceOptions,\n): AccountState {\n // Fail-closed default: align with `hyperLiquidModeFoldsSpot(null) → false`.\n // A caller that omits `options` should NOT silently fold spot — that would\n // over-report withdrawable funds for Standard / dexAbstraction users.\n const foldIntoCollateral = options?.foldIntoCollateral ?? false;\n\n const spotBalance = getSpotBalance(spotState);\n const spotHold = getSpotHold(spotState);\n const freeSpot = Math.max(0, spotBalance - spotHold);\n\n const currentTotal = parseFloat(accountState.totalBalance);\n const currentSpendable = parseFloat(accountState.spendableBalance);\n const currentWithdrawable = parseFloat(accountState.withdrawableBalance);\n\n // Preserve sentinel totals (e.g. PERPS_CONSTANTS.FallbackDataDisplay '--')\n // rather than coercing them to NaN.\n if (!Number.isFinite(currentTotal)) {\n return accountState;\n }\n\n if (spotBalance === 0) {\n // No spot wealth means no hold either in the HL payload shape, so the\n // later totalBalance adjustment would also be a no-op.\n return accountState;\n }\n\n // Folding is gated strictly on the resolved abstraction mode (see callers'\n // `foldIntoCollateral` argument). Standard / DEX-abstraction users keep\n // perps and spot independent, so spot must NOT surface as a perps-\n // withdrawable balance for them — withdraw3 only draws from the perps\n // ledger in those modes. Unified / portfolio-margin users get the fold;\n // live callers fail-CLOSED via `hyperLiquidModeFoldsSpot` when mode is\n // unresolved.\n const nextSpendable = resolveFoldedBalance(\n currentSpendable,\n accountState.spendableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n const nextWithdrawable = resolveFoldedBalance(\n currentWithdrawable,\n accountState.withdrawableBalance,\n freeSpot,\n foldIntoCollateral,\n );\n\n // Total always reflects combined wealth: subtract spotHold to avoid\n // double-counting on Unified/PM accounts where marginSummary.accountValue\n // already includes the margin that HL surfaces via spot.hold. Standard\n // mode has spotHold = 0 by construction, so the subtraction is a no-op.\n const nextTotal = currentTotal + spotBalance - spotHold;\n\n return {\n ...accountState,\n totalBalance: nextTotal.toString(),\n spendableBalance: nextSpendable,\n withdrawableBalance: nextWithdrawable,\n };\n}\n\nfunction resolveFoldedBalance(\n currentNumeric: number,\n currentRaw: string,\n freeSpot: number,\n foldIntoCollateral: boolean,\n): string {\n if (!foldIntoCollateral) {\n return currentRaw;\n }\n if (Number.isFinite(currentNumeric)) {\n return (currentNumeric + freeSpot).toString();\n }\n // Non-finite currentNumeric means the adapter passed a sentinel like\n // `PERPS_CONSTANTS.FallbackDataDisplay` (\"--\") during loading. Preserve\n // the sentinel rather than synthesising a numeric fold; the caller's\n // UI treats \"--\" as \"loading\" and would otherwise show a misleading\n // spot-only figure while the per-DEX perps fetch is still in flight.\n return currentRaw;\n}\n\n/**\n * Aggregate multiple per-DEX AccountState objects into one by summing numeric fields.\n * ROE is recalculated as (totalUnrealizedPnl / totalMarginUsed) * 100.\n *\n * @param states - The array of per-DEX account states to aggregate.\n * @returns The combined account state with summed balances and recalculated ROE.\n */\nexport function aggregateAccountStates(states: AccountState[]): AccountState {\n const fallback: AccountState = {\n spendableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n withdrawableBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n totalBalance: PERPS_CONSTANTS.FallbackDataDisplay,\n marginUsed: PERPS_CONSTANTS.FallbackDataDisplay,\n unrealizedPnl: PERPS_CONSTANTS.FallbackDataDisplay,\n returnOnEquity: PERPS_CONSTANTS.FallbackDataDisplay,\n };\n\n if (states.length === 0) {\n return fallback;\n }\n\n const aggregated = states.reduce<AccountState>((acc, state, index) => {\n if (index === 0) {\n return { ...state };\n }\n\n return {\n spendableBalance: (\n parseFloat(acc.spendableBalance) + parseFloat(state.spendableBalance)\n ).toString(),\n withdrawableBalance: (\n parseFloat(acc.withdrawableBalance) +\n parseFloat(state.withdrawableBalance)\n ).toString(),\n totalBalance: (\n parseFloat(acc.totalBalance) + parseFloat(state.totalBalance)\n ).toString(),\n marginUsed: (\n parseFloat(acc.marginUsed) + parseFloat(state.marginUsed)\n ).toString(),\n unrealizedPnl: (\n parseFloat(acc.unrealizedPnl) + parseFloat(state.unrealizedPnl)\n ).toString(),\n returnOnEquity: '0',\n };\n }, fallback);\n\n // Recalculate ROE across all DEXs\n const totalMarginUsed = parseFloat(aggregated.marginUsed);\n const totalUnrealizedPnl = parseFloat(aggregated.unrealizedPnl);\n if (totalMarginUsed > 0) {\n aggregated.returnOnEquity = (\n (totalUnrealizedPnl / totalMarginUsed) *\n 100\n ).toString();\n } else {\n aggregated.returnOnEquity = '0';\n }\n\n return aggregated;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensureError = exports.isKeyringLockedError = exports.isAbortError = void 0;
3
+ exports.isHyperLiquidUserNotFoundError = exports.ensureError = exports.isKeyringLockedError = exports.isAbortError = void 0;
4
4
  /**
5
5
  * Utility functions for error handling across Perps controller code.
6
6
  * Includes generic error helpers and Perps error classification helpers.
@@ -71,4 +71,18 @@ function ensureError(error, context) {
71
71
  : 'Unknown error');
72
72
  }
73
73
  exports.ensureError = ensureError;
74
+ /**
75
+ * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,
76
+ * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the
77
+ * wallet has never funded a Hyperliquid account. It is a benign pre-account
78
+ * state, not an error we should forward to Sentry.
79
+ *
80
+ * @param error - The caught error.
81
+ * @returns True if the error matches the Hyperliquid "user not on chain yet" rejection.
82
+ */
83
+ function isHyperLiquidUserNotFoundError(error) {
84
+ const lower = ensureError(error).message.toLowerCase();
85
+ return (lower.includes('user or api wallet') && lower.includes('does not exist'));
86
+ }
87
+ exports.isHyperLiquidUserNotFoundError = isHyperLiquidUserNotFoundError;
74
88
  //# sourceMappingURL=errorUtils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorUtils.cjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,2CAA8C;AAE9C,4DAAuD;AAEvD;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AATD,oCASC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,mCAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAfD,oDAeC;AAED;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,IAAA,mBAAW,EAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC;AAlBD,kCAkBC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n"]}
1
+ {"version":3,"file":"errorUtils.cjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,2CAA8C;AAE9C,4DAAuD;AAEvD;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AATD,oCASC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,mCAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAfD,oDAeC;AAED;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,IAAA,mBAAW,EAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC;AAlBD,kCAkBC;AAED;;;;;;;;GAQG;AACH,SAAgB,8BAA8B,CAAC,KAAc;IAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACzE,CAAC;AACJ,CAAC;AALD,wEAKC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n\n/**\n * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,\n * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the\n * wallet has never funded a Hyperliquid account. It is a benign pre-account\n * state, not an error we should forward to Sentry.\n *\n * @param error - The caught error.\n * @returns True if the error matches the Hyperliquid \"user not on chain yet\" rejection.\n */\nexport function isHyperLiquidUserNotFoundError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('user or api wallet') && lower.includes('does not exist')\n );\n}\n"]}
@@ -25,4 +25,14 @@ export declare function isKeyringLockedError(error: unknown): boolean;
25
25
  * @returns A proper Error instance
26
26
  */
27
27
  export declare function ensureError(error: unknown, context?: string): Error;
28
+ /**
29
+ * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,
30
+ * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the
31
+ * wallet has never funded a Hyperliquid account. It is a benign pre-account
32
+ * state, not an error we should forward to Sentry.
33
+ *
34
+ * @param error - The caught error.
35
+ * @returns True if the error matches the Hyperliquid "user not on chain yet" rejection.
36
+ */
37
+ export declare function isHyperLiquidUserNotFoundError(error: unknown): boolean;
28
38
  //# sourceMappingURL=errorUtils.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorUtils.d.cts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE"}
1
+ {"version":3,"file":"errorUtils.d.cts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKtE"}
@@ -25,4 +25,14 @@ export declare function isKeyringLockedError(error: unknown): boolean;
25
25
  * @returns A proper Error instance
26
26
  */
27
27
  export declare function ensureError(error: unknown, context?: string): Error;
28
+ /**
29
+ * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,
30
+ * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the
31
+ * wallet has never funded a Hyperliquid account. It is a benign pre-account
32
+ * state, not an error we should forward to Sentry.
33
+ *
34
+ * @param error - The caught error.
35
+ * @returns True if the error matches the Hyperliquid "user not on chain yet" rejection.
36
+ */
37
+ export declare function isHyperLiquidUserNotFoundError(error: unknown): boolean;
28
38
  //# sourceMappingURL=errorUtils.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorUtils.d.mts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE"}
1
+ {"version":3,"file":"errorUtils.d.mts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKtE"}
@@ -65,4 +65,17 @@ export function ensureError(error, context) {
65
65
  ? String(error.message)
66
66
  : 'Unknown error');
67
67
  }
68
+ /**
69
+ * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,
70
+ * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the
71
+ * wallet has never funded a Hyperliquid account. It is a benign pre-account
72
+ * state, not an error we should forward to Sentry.
73
+ *
74
+ * @param error - The caught error.
75
+ * @returns True if the error matches the Hyperliquid "user not on chain yet" rejection.
76
+ */
77
+ export function isHyperLiquidUserNotFoundError(error) {
78
+ const lower = ensureError(error).message.toLowerCase();
79
+ return (lower.includes('user or api wallet') && lower.includes('does not exist'));
80
+ }
68
81
  //# sourceMappingURL=errorUtils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorUtils.mjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAE9C,OAAO,EAAE,iBAAiB,EAAE,+BAA2B;AAEvD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,iBAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n"]}
1
+ {"version":3,"file":"errorUtils.mjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAE9C,OAAO,EAAE,iBAAiB,EAAE,+BAA2B;AAEvD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,iBAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,8BAA8B,CAAC,KAAc;IAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACzE,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n\n/**\n * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,\n * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the\n * wallet has never funded a Hyperliquid account. It is a benign pre-account\n * state, not an error we should forward to Sentry.\n *\n * @param error - The caught error.\n * @returns True if the error matches the Hyperliquid \"user not on chain yet\" rejection.\n */\nexport function isHyperLiquidUserNotFoundError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('user or api wallet') && lower.includes('does not exist')\n );\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildOrdersArray = exports.calculateOrderPriceAndSize = exports.calculateFinalPositionSize = exports.getMaxAllowedAmount = exports.calculateMarginRequired = exports.calculatePositionSize = void 0;
4
+ const hyperLiquidConfig_1 = require("../constants/hyperLiquidConfig.cjs");
4
5
  const perpsConfig_1 = require("../constants/perpsConfig.cjs");
5
6
  const perpsErrorCodes_1 = require("../perpsErrorCodes.cjs");
6
7
  const hyperLiquidAdapter_1 = require("./hyperLiquidAdapter.cjs");
@@ -169,12 +170,15 @@ exports.calculateFinalPositionSize = calculateFinalPositionSize;
169
170
  * @returns Formatted order price, size, and price string
170
171
  */
171
172
  function calculateOrderPriceAndSize(params) {
172
- const { orderType, isBuy, finalPositionSize, currentPrice, limitPrice, slippage, szDecimals, } = params;
173
+ const { orderType, isBuy, finalPositionSize, currentPrice, limitPrice, maxSlippageBps, szDecimals, } = params;
173
174
  let orderPrice;
174
175
  let formattedSize;
175
176
  if (orderType === 'market') {
176
- // Market orders: add slippage (3% conservative default)
177
- const slippageValue = slippage ?? perpsConfig_1.ORDER_SLIPPAGE_CONFIG.DefaultMarketSlippageBps / 10000;
177
+ // Market orders: apply slippage buffer to the live price so HyperLiquid
178
+ // receives a worst-case acceptable limit price. Falls back to the
179
+ // documented default if the caller does not provide one.
180
+ const effectiveBps = maxSlippageBps ?? perpsConfig_1.ORDER_SLIPPAGE_CONFIG.DefaultMarketSlippageBps;
181
+ const slippageValue = effectiveBps / hyperLiquidConfig_1.BASIS_POINTS_DIVISOR;
178
182
  orderPrice = isBuy
179
183
  ? currentPrice * (1 + slippageValue)
180
184
  : currentPrice * (1 - slippageValue);