@metamask-previews/perps-controller 6.2.0-preview-e43dfcb → 6.2.0-preview-c7c3c44

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":"DepositService.mjs","sourceRoot":"","sources":["../../src/services/DepositService.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,mCAAmC;AACnD,OAAO,EAAE,gBAAgB,EAAE,wBAAwB;AAGnD,OAAO,EAAE,cAAc,EAAE,2CAAuC;AAOhE,OAAO,EAAE,qBAAqB,EAAE,kCAA8B;AAC9D,OAAO,EAAE,iBAAiB,EAAE,6BAAyB;AACrD,OAAO,EAAE,yBAAyB,EAAE,kCAA8B;AAElE,qEAAqE;AACrE,MAAM,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAElE;;;;;;;;;GASG;AACH,MAAM,OAAO,cAAc;IAKzB;;;;;OAKG;IACH,YACE,IAA+B,EAC/B,SAAuC;QAZhC,uCAAiC;QAEjC,4CAAyC;QAYhD,uBAAA,IAAI,wBAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,6BAAc,SAAS,MAAA,CAAC;IAC9B,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,kBAAkB,CAAC,OAAoC;QAK3D,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAE7B,uBAAA,IAAI,4BAAM,CAAC,WAAW,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAE5E,2CAA2C;QAC3C,MAAM,gBAAgB,GAAG,iBAAiB,EAAE,CAAC;QAE7C,mCAAmC;QACnC,MAAM,aAAa,GAAG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,qBAAqB,GAAG,KAAK,CAAC,eAAe,CAAC;QAEpD,iFAAiF;QACjF,MAAM,YAAY,GAAG,yBAAyB,CAC5C,qBAAqB,EACrB,KAAK,CACN,CAAC;QAEF,4DAA4D;QAC5D,MAAM,UAAU,GAAG,qBAAqB,CACtC,uBAAA,IAAI,iCAAW,CAAC,IAAI,CAClB,2DAA2D,CAC5D,CACF,CAAC;QACF,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;QACJ,CAAC;QACD,MAAM,cAAc,GAAG,UAAU,CAAC,OAAc,CAAC;QAEjD,4DAA4D;QAC5D,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,MAAM,YAAY,GAAG,WAAW,CAAC,cAAqB,CAAC;QAEvD,yDAAyD;QACzD,MAAM,WAAW,GAA2B;YAC1C,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,YAAY;YAClB,GAAG,EAAE,iBAAiB;SACvB,CAAC;QAEF,uBAAA,IAAI,4BAAM,CAAC,WAAW,CAAC,GAAG,CAAC,8CAA8C,EAAE;YACzE,SAAS,EAAE,gBAAgB;YAC3B,YAAY;YACZ,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,YAAY;SACjB,CAAC,CAAC;QAEH,OAAO;YACL,WAAW;YACX,YAAY;YACZ,gBAAgB;SACjB,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { parseCaipAssetId } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { DEPOSIT_CONFIG } from '../constants/hyperLiquidConfig';\nimport type {\n PerpsProvider,\n PerpsPlatformDependencies,\n PerpsTransactionParams,\n} from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { getSelectedEvmAccount } from '../utils/accountUtils';\nimport { generateDepositId } from '../utils/idUtils';\nimport { generateERC20TransferData } from '../utils/transferData';\n\n// Temporary to avoid estimation failures due to insufficient balance\nconst DEPOSIT_GAS_LIMIT = toHex(DEPOSIT_CONFIG.EstimatedGasLimit);\n\n/**\n * DepositService\n *\n * Handles deposit transaction preparation and validation.\n * Stateless service that prepares transaction data for TransactionController.\n * Controller handles TransactionController integration and promise lifecycle.\n *\n * Instance-based service with constructor injection of platform dependencies\n * and messenger for inter-controller communication.\n */\nexport class DepositService {\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n /**\n * Create a new DepositService instance\n *\n * @param deps - Platform dependencies for logging, metrics, etc.\n * @param messenger - Controller messenger for cross-controller communication.\n */\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n }\n\n /**\n * Prepare deposit transaction for confirmation\n * Extracts transaction construction logic from controller\n *\n * @param options - Configuration object\n * @param options.provider - Active provider instance\n * @returns Transaction data ready for TransactionController.addTransaction\n */\n async prepareTransaction(options: { provider: PerpsProvider }): Promise<{\n transaction: PerpsTransactionParams;\n assetChainId: Hex;\n currentDepositId: string;\n }> {\n const { provider } = options;\n\n this.#deps.debugLogger.log('DepositService: Preparing deposit transaction');\n\n // Generate deposit request ID for tracking\n const currentDepositId = generateDepositId();\n\n // Get deposit routes from provider\n const depositRoutes = provider.getDepositRoutes({ isTestnet: false });\n const route = depositRoutes[0];\n const bridgeContractAddress = route.contractAddress;\n\n // Generate transfer data for ERC-20 token transfer (portable, no mobile imports)\n const transferData = generateERC20TransferData(\n bridgeContractAddress,\n '0x0',\n );\n\n // Get EVM account from selected account group via messenger\n const evmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n if (!evmAccount) {\n throw new Error(\n 'No EVM-compatible account found in selected account group',\n );\n }\n const accountAddress = evmAccount.address as Hex;\n\n // Parse CAIP asset ID to extract chain ID and token address\n const parsedAsset = parseCaipAssetId(route.assetId);\n const assetChainId = toHex(parsedAsset.chainId.split(':')[1]);\n const tokenAddress = parsedAsset.assetReference as Hex;\n\n // Build transaction parameters for TransactionController\n const transaction: PerpsTransactionParams = {\n from: accountAddress,\n to: tokenAddress,\n value: '0x0',\n data: transferData,\n gas: DEPOSIT_GAS_LIMIT,\n };\n\n this.#deps.debugLogger.log('DepositService: Deposit transaction prepared', {\n depositId: currentDepositId,\n assetChainId,\n from: accountAddress,\n to: tokenAddress,\n });\n\n return {\n transaction,\n assetChainId,\n currentDepositId,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"DepositService.mjs","sourceRoot":"","sources":["../../src/services/DepositService.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,mCAAmC;AACnD,OAAO,EAAE,gBAAgB,EAAE,wBAAwB;AAGnD,OAAO,EAAE,cAAc,EAAE,2CAAuC;AAOhE,OAAO,EAAE,kCAAkC,EAAE,kCAA8B;AAC3E,OAAO,EAAE,iBAAiB,EAAE,6BAAyB;AACrD,OAAO,EAAE,yBAAyB,EAAE,kCAA8B;AAElE,qEAAqE;AACrE,MAAM,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAElE;;;;;;;;;GASG;AACH,MAAM,OAAO,cAAc;IAKzB;;;;;OAKG;IACH,YACE,IAA+B,EAC/B,SAAuC;QAZhC,uCAAiC;QAEjC,4CAAyC;QAYhD,uBAAA,IAAI,wBAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,6BAAc,SAAS,MAAA,CAAC;IAC9B,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,kBAAkB,CAAC,OAAoC;QAK3D,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAE7B,uBAAA,IAAI,4BAAM,CAAC,WAAW,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAE5E,2CAA2C;QAC3C,MAAM,gBAAgB,GAAG,iBAAiB,EAAE,CAAC;QAE7C,mCAAmC;QACnC,MAAM,aAAa,GAAG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,qBAAqB,GAAG,KAAK,CAAC,eAAe,CAAC;QAEpD,iFAAiF;QACjF,MAAM,YAAY,GAAG,yBAAyB,CAC5C,qBAAqB,EACrB,KAAK,CACN,CAAC;QAEF,qFAAqF;QACrF,MAAM,UAAU,GAAG,kCAAkC,CAAC,uBAAA,IAAI,iCAAW,CAAC,CAAC;QACvE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;QACJ,CAAC;QACD,MAAM,cAAc,GAAG,UAAU,CAAC,OAAc,CAAC;QAEjD,4DAA4D;QAC5D,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,MAAM,YAAY,GAAG,WAAW,CAAC,cAAqB,CAAC;QAEvD,yDAAyD;QACzD,MAAM,WAAW,GAA2B;YAC1C,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,YAAY;YAClB,GAAG,EAAE,iBAAiB;SACvB,CAAC;QAEF,uBAAA,IAAI,4BAAM,CAAC,WAAW,CAAC,GAAG,CAAC,8CAA8C,EAAE;YACzE,SAAS,EAAE,gBAAgB;YAC3B,YAAY;YACZ,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,YAAY;SACjB,CAAC,CAAC;QAEH,OAAO;YACL,WAAW;YACX,YAAY;YACZ,gBAAgB;SACjB,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport { parseCaipAssetId } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { DEPOSIT_CONFIG } from '../constants/hyperLiquidConfig';\nimport type {\n PerpsProvider,\n PerpsPlatformDependencies,\n PerpsTransactionParams,\n} from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { getSelectedEvmAccountFromMessenger } from '../utils/accountUtils';\nimport { generateDepositId } from '../utils/idUtils';\nimport { generateERC20TransferData } from '../utils/transferData';\n\n// Temporary to avoid estimation failures due to insufficient balance\nconst DEPOSIT_GAS_LIMIT = toHex(DEPOSIT_CONFIG.EstimatedGasLimit);\n\n/**\n * DepositService\n *\n * Handles deposit transaction preparation and validation.\n * Stateless service that prepares transaction data for TransactionController.\n * Controller handles TransactionController integration and promise lifecycle.\n *\n * Instance-based service with constructor injection of platform dependencies\n * and messenger for inter-controller communication.\n */\nexport class DepositService {\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n /**\n * Create a new DepositService instance\n *\n * @param deps - Platform dependencies for logging, metrics, etc.\n * @param messenger - Controller messenger for cross-controller communication.\n */\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n }\n\n /**\n * Prepare deposit transaction for confirmation\n * Extracts transaction construction logic from controller\n *\n * @param options - Configuration object\n * @param options.provider - Active provider instance\n * @returns Transaction data ready for TransactionController.addTransaction\n */\n async prepareTransaction(options: { provider: PerpsProvider }): Promise<{\n transaction: PerpsTransactionParams;\n assetChainId: Hex;\n currentDepositId: string;\n }> {\n const { provider } = options;\n\n this.#deps.debugLogger.log('DepositService: Preparing deposit transaction');\n\n // Generate deposit request ID for tracking\n const currentDepositId = generateDepositId();\n\n // Get deposit routes from provider\n const depositRoutes = provider.getDepositRoutes({ isTestnet: false });\n const route = depositRoutes[0];\n const bridgeContractAddress = route.contractAddress;\n\n // Generate transfer data for ERC-20 token transfer (portable, no mobile imports)\n const transferData = generateERC20TransferData(\n bridgeContractAddress,\n '0x0',\n );\n\n // Get EVM account from selected account, falling back to the selected account group.\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n if (!evmAccount) {\n throw new Error(\n 'No EVM-compatible account found in selected account group',\n );\n }\n const accountAddress = evmAccount.address as Hex;\n\n // Parse CAIP asset ID to extract chain ID and token address\n const parsedAsset = parseCaipAssetId(route.assetId);\n const assetChainId = toHex(parsedAsset.chainId.split(':')[1]);\n const tokenAddress = parsedAsset.assetReference as Hex;\n\n // Build transaction parameters for TransactionController\n const transaction: PerpsTransactionParams = {\n from: accountAddress,\n to: tokenAddress,\n value: '0x0',\n data: transferData,\n gas: DEPOSIT_GAS_LIMIT,\n };\n\n this.#deps.debugLogger.log('DepositService: Deposit transaction prepared', {\n depositId: currentDepositId,\n assetChainId,\n from: accountAddress,\n to: tokenAddress,\n });\n\n return {\n transaction,\n assetChainId,\n currentDepositId,\n };\n }\n}\n"]}
@@ -55,7 +55,7 @@ class HyperLiquidWalletService {
55
55
  * @returns True for MetaMask hardware keyrings; false for software accounts.
56
56
  */
57
57
  isSelectedHardwareWallet() {
58
- const selectedEvmAccount = (0, accountUtils_1.findEvmAccount)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
58
+ const selectedEvmAccount = (0, accountUtils_1.getSelectedEvmAccountDetailsFromMessenger)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
59
59
  if (!selectedEvmAccount || !(0, utils_1.hasProperty)(selectedEvmAccount, 'metadata')) {
60
60
  return false;
61
61
  }
@@ -70,8 +70,8 @@ class HyperLiquidWalletService {
70
70
  * @returns The wallet adapter with address, signTypedData, and getChainId methods.
71
71
  */
72
72
  createWalletAdapter() {
73
- // Get current EVM account via DI accountTree
74
- const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
73
+ // Get current EVM account via DI messenger
74
+ const evmAccount = (0, accountUtils_1.getSelectedEvmAccountFromMessenger)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
75
75
  if (!evmAccount?.address) {
76
76
  throw new Error(perpsErrorCodes_1.PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
77
77
  }
@@ -81,7 +81,7 @@ class HyperLiquidWalletService {
81
81
  signTypedData: async (params) => {
82
82
  // Get FRESH account on every sign to handle account switches
83
83
  // This prevents race conditions where wallet adapter was created with old account
84
- const currentEvmAccount = (0, accountUtils_1.getSelectedEvmAccount)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
84
+ const currentEvmAccount = (0, accountUtils_1.getSelectedEvmAccountFromMessenger)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
85
85
  if (!currentEvmAccount?.address) {
86
86
  throw new Error(perpsErrorCodes_1.PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
87
87
  }
@@ -114,7 +114,7 @@ class HyperLiquidWalletService {
114
114
  * @returns The CAIP account ID for the current EVM account.
115
115
  */
116
116
  async getCurrentAccountId() {
117
- const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
117
+ const evmAccount = (0, accountUtils_1.getSelectedEvmAccountFromMessenger)(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
118
118
  if (!evmAccount?.address) {
119
119
  throw new Error(perpsErrorCodes_1.PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
120
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.cjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { findEvmAccount, getSelectedEvmAccount } from '../utils/accountUtils';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = findEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Create wallet adapter that implements AbstractViemJsonRpcAccount interface\n * Required by @nktkas/hyperliquid SDK for signing transactions\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): {\n address: Hex;\n signTypedData: (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n getChainId?: () => Promise<number>;\n } {\n // Get current EVM account via DI accountTree\n const evmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<Hex> => {\n // Get FRESH account on every sign to handle account switches\n // This prevents race conditions where wallet adapter was created with old account\n const currentEvmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n // Construct EIP-712 typed data\n const typedData = {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n };\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n // Use messenger to sign typed data\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: typedData,\n });\n\n return signature as Hex;\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
1
+ {"version":3,"file":"HyperLiquidWalletService.cjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport {\n getSelectedEvmAccountDetailsFromMessenger,\n getSelectedEvmAccountFromMessenger,\n} from '../utils/accountUtils';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = getSelectedEvmAccountDetailsFromMessenger(\n this.#messenger,\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Create wallet adapter that implements AbstractViemJsonRpcAccount interface\n * Required by @nktkas/hyperliquid SDK for signing transactions\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): {\n address: Hex;\n signTypedData: (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n getChainId?: () => Promise<number>;\n } {\n // Get current EVM account via DI messenger\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<Hex> => {\n // Get FRESH account on every sign to handle account switches\n // This prevents race conditions where wallet adapter was created with old account\n const currentEvmAccount = getSelectedEvmAccountFromMessenger(\n this.#messenger,\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n // Construct EIP-712 typed data\n const typedData = {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n };\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n // Use messenger to sign typed data\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: typedData,\n });\n\n return signature as Hex;\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.d.cts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAAiB;AAClB,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAavE;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAuC1C;;;;;OAKG;IACI,mBAAmB,IAAI;QAC5B,OAAO,EAAE,GAAG,CAAC;QACb,aAAa,EAAE,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,CAAC;gBAChB,iBAAiB,EAAE,GAAG,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,CAAC,GAAG,EAAE,MAAM,GAAG;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,MAAM,CAAA;iBAAE,EAAE,CAAC;aACjD,CAAC;YACF,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACpC;IAyED;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAiB1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
1
+ {"version":3,"file":"HyperLiquidWalletService.d.cts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAAiB;AAClB,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAgBvE;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAqC1C;;;;;OAKG;IACI,mBAAmB,IAAI;QAC5B,OAAO,EAAE,GAAG,CAAC;QACb,aAAa,EAAE,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,CAAC;gBAChB,iBAAiB,EAAE,GAAG,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,CAAC,GAAG,EAAE,MAAM,GAAG;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,MAAM,CAAA;iBAAE,EAAE,CAAC;aACjD,CAAC;YACF,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACpC;IAmED;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAa1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.d.mts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAAiB;AAClB,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAavE;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAuC1C;;;;;OAKG;IACI,mBAAmB,IAAI;QAC5B,OAAO,EAAE,GAAG,CAAC;QACb,aAAa,EAAE,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,CAAC;gBAChB,iBAAiB,EAAE,GAAG,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,CAAC,GAAG,EAAE,MAAM,GAAG;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,MAAM,CAAA;iBAAE,EAAE,CAAC;aACjD,CAAC;YACF,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACpC;IAyED;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAiB1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
1
+ {"version":3,"file":"HyperLiquidWalletService.d.mts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAAiB;AAClB,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAgBvE;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAqC1C;;;;;OAKG;IACI,mBAAmB,IAAI;QAC5B,OAAO,EAAE,GAAG,CAAC;QACb,aAAa,EAAE,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,CAAC;gBAChB,iBAAiB,EAAE,GAAG,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,CAAC,GAAG,EAAE,MAAM,GAAG;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,MAAM,CAAA;iBAAE,EAAE,CAAC;aACjD,CAAC;YACF,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACpC;IAmED;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAa1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
@@ -13,7 +13,7 @@ var _HyperLiquidWalletService_instances, _HyperLiquidWalletService_isTestnet, _H
13
13
  import { hasProperty, isValidHexAddress, parseCaipAccountId } from "@metamask/utils";
14
14
  import { getChainId } from "../constants/hyperLiquidConfig.mjs";
15
15
  import { PERPS_ERROR_CODES } from "../perpsErrorCodes.mjs";
16
- import { findEvmAccount, getSelectedEvmAccount } from "../utils/accountUtils.mjs";
16
+ import { getSelectedEvmAccountDetailsFromMessenger, getSelectedEvmAccountFromMessenger } from "../utils/accountUtils.mjs";
17
17
  // Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this
18
18
  // service portable between mobile and the core monorepo.
19
19
  const HARDWARE_KEYRING_TYPES = new Set([
@@ -52,7 +52,7 @@ export class HyperLiquidWalletService {
52
52
  * @returns True for MetaMask hardware keyrings; false for software accounts.
53
53
  */
54
54
  isSelectedHardwareWallet() {
55
- const selectedEvmAccount = findEvmAccount(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
55
+ const selectedEvmAccount = getSelectedEvmAccountDetailsFromMessenger(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
56
56
  if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {
57
57
  return false;
58
58
  }
@@ -67,8 +67,8 @@ export class HyperLiquidWalletService {
67
67
  * @returns The wallet adapter with address, signTypedData, and getChainId methods.
68
68
  */
69
69
  createWalletAdapter() {
70
- // Get current EVM account via DI accountTree
71
- const evmAccount = getSelectedEvmAccount(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
70
+ // Get current EVM account via DI messenger
71
+ const evmAccount = getSelectedEvmAccountFromMessenger(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
72
72
  if (!evmAccount?.address) {
73
73
  throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
74
74
  }
@@ -78,7 +78,7 @@ export class HyperLiquidWalletService {
78
78
  signTypedData: async (params) => {
79
79
  // Get FRESH account on every sign to handle account switches
80
80
  // This prevents race conditions where wallet adapter was created with old account
81
- const currentEvmAccount = getSelectedEvmAccount(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
81
+ const currentEvmAccount = getSelectedEvmAccountFromMessenger(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
82
82
  if (!currentEvmAccount?.address) {
83
83
  throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
84
84
  }
@@ -111,7 +111,7 @@ export class HyperLiquidWalletService {
111
111
  * @returns The CAIP account ID for the current EVM account.
112
112
  */
113
113
  async getCurrentAccountId() {
114
- const evmAccount = getSelectedEvmAccount(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
114
+ const evmAccount = getSelectedEvmAccountFromMessenger(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
115
115
  if (!evmAccount?.address) {
116
116
  throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
117
117
  }
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.mjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { findEvmAccount, getSelectedEvmAccount } from '../utils/accountUtils';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = findEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Create wallet adapter that implements AbstractViemJsonRpcAccount interface\n * Required by @nktkas/hyperliquid SDK for signing transactions\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): {\n address: Hex;\n signTypedData: (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n getChainId?: () => Promise<number>;\n } {\n // Get current EVM account via DI accountTree\n const evmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<Hex> => {\n // Get FRESH account on every sign to handle account switches\n // This prevents race conditions where wallet adapter was created with old account\n const currentEvmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n // Construct EIP-712 typed data\n const typedData = {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n };\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n // Use messenger to sign typed data\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: typedData,\n });\n\n return signature as Hex;\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
1
+ {"version":3,"file":"HyperLiquidWalletService.mjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport {\n getSelectedEvmAccountDetailsFromMessenger,\n getSelectedEvmAccountFromMessenger,\n} from '../utils/accountUtils';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = getSelectedEvmAccountDetailsFromMessenger(\n this.#messenger,\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Create wallet adapter that implements AbstractViemJsonRpcAccount interface\n * Required by @nktkas/hyperliquid SDK for signing transactions\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): {\n address: Hex;\n signTypedData: (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n getChainId?: () => Promise<number>;\n } {\n // Get current EVM account via DI messenger\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<Hex> => {\n // Get FRESH account on every sign to handle account switches\n // This prevents race conditions where wallet adapter was created with old account\n const currentEvmAccount = getSelectedEvmAccountFromMessenger(\n this.#messenger,\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n // Construct EIP-712 typed data\n const typedData = {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n };\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n // Use messenger to sign typed data\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: typedData,\n });\n\n return signature as Hex;\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
@@ -48,7 +48,7 @@ class RewardsIntegrationService {
48
48
  */
49
49
  async calculateUserFeeDiscount() {
50
50
  try {
51
- const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(__classPrivateFieldGet(this, _RewardsIntegrationService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
51
+ const evmAccount = (0, accountUtils_1.getSelectedEvmAccountFromMessenger)(__classPrivateFieldGet(this, _RewardsIntegrationService_messenger, "f"));
52
52
  if (!evmAccount) {
53
53
  __classPrivateFieldGet(this, _RewardsIntegrationService_deps, "f").debugLogger.log('RewardsIntegrationService: No EVM account found for fee discount');
54
54
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"RewardsIntegrationService.cjs","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BASIS_POINTS_DIVISOR,\n BUILDER_FEE_CONFIG,\n} from '../constants/hyperLiquidConfig';\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { PerpsPlatformDependencies } from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { getSelectedEvmAccount } from '../utils/accountUtils';\nimport { ensureError } from '../utils/errorUtils';\nimport { formatAccountToCaipAccountId } from '../utils/rewardsUtils';\n\n/**\n * RewardsIntegrationService\n *\n * Handles rewards-related operations and fee discount calculations.\n * Stateless service that coordinates with RewardsController and NetworkController.\n *\n * Instance-based service with constructor injection of platform dependencies.\n */\nexport class RewardsIntegrationService {\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n /**\n * Create a new RewardsIntegrationService instance\n *\n * @param deps - Platform dependencies for logging, metrics, etc.\n * @param messenger - Controller messenger for cross-controller communication.\n */\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n }\n\n /**\n * Get chain ID for a network client via DI network controller\n *\n * @param networkClientId - The network client identifier to look up.\n * @returns The chain ID string, or undefined if the network client is not found.\n */\n #getChainIdForNetwork(networkClientId: string): string | undefined {\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return networkClient.configuration.chainId;\n } catch {\n // Network client may not exist\n return undefined;\n }\n }\n\n /**\n * Calculate user fee discount from rewards\n * Returns discount in basis points (e.g., 6500 = 65% discount)\n *\n * @returns The fee discount in basis points, or undefined if unavailable.\n */\n async calculateUserFeeDiscount(): Promise<number | undefined> {\n try {\n const evmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!evmAccount) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: No EVM account found for fee discount',\n );\n return undefined;\n }\n\n // Get the chain ID via DI network controller\n const networkState = this.#messenger.call('NetworkController:getState');\n const { selectedNetworkClientId } = networkState;\n const chainId = this.#getChainIdForNetwork(selectedNetworkClientId);\n\n if (!chainId) {\n this.#deps.logger.error(\n new Error('Chain ID not found for fee discount calculation'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use pure utility function for CAIP formatting (pass logger for error reporting)\n const caipAccountId = formatAccountToCaipAccountId(\n evmAccount.address,\n chainId,\n this.#deps.logger,\n );\n\n if (!caipAccountId) {\n this.#deps.logger.error(\n new Error('Failed to format CAIP account ID for fee discount'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n address: evmAccount.address,\n chainId,\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use rewards via DI (no RewardsController in Core yet).\n // The rewards controller needs the perps MetaMask builder base fee in\n // bips to convert an absolute VIP fee into a discount fraction.\n const discountBips = await this.#deps.rewards.getPerpsDiscountForAccount(\n caipAccountId,\n BUILDER_FEE_CONFIG.MaxFeeDecimal * BASIS_POINTS_DIVISOR,\n );\n\n // null = subscription state not hydrated yet; surface as undefined so\n // callers don't treat it as a definitive \"no discount\" answer.\n if (discountBips === null) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount unavailable (subscription state not hydrated)',\n { address: evmAccount.address, caipAccountId },\n );\n return undefined;\n }\n\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount calculated',\n {\n address: evmAccount.address,\n caipAccountId,\n discountBips,\n discountPercentage: discountBips / 100,\n },\n );\n\n return discountBips;\n } catch (error) {\n this.#deps.logger.error(\n ensureError(\n error,\n 'RewardsIntegrationService.calculateUserFeeDiscount',\n ),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {},\n },\n },\n );\n return undefined;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"RewardsIntegrationService.cjs","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BASIS_POINTS_DIVISOR,\n BUILDER_FEE_CONFIG,\n} from '../constants/hyperLiquidConfig';\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { PerpsPlatformDependencies } from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { getSelectedEvmAccountFromMessenger } from '../utils/accountUtils';\nimport { ensureError } from '../utils/errorUtils';\nimport { formatAccountToCaipAccountId } from '../utils/rewardsUtils';\n\n/**\n * RewardsIntegrationService\n *\n * Handles rewards-related operations and fee discount calculations.\n * Stateless service that coordinates with RewardsController and NetworkController.\n *\n * Instance-based service with constructor injection of platform dependencies.\n */\nexport class RewardsIntegrationService {\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n /**\n * Create a new RewardsIntegrationService instance\n *\n * @param deps - Platform dependencies for logging, metrics, etc.\n * @param messenger - Controller messenger for cross-controller communication.\n */\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n }\n\n /**\n * Get chain ID for a network client via DI network controller\n *\n * @param networkClientId - The network client identifier to look up.\n * @returns The chain ID string, or undefined if the network client is not found.\n */\n #getChainIdForNetwork(networkClientId: string): string | undefined {\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return networkClient.configuration.chainId;\n } catch {\n // Network client may not exist\n return undefined;\n }\n }\n\n /**\n * Calculate user fee discount from rewards\n * Returns discount in basis points (e.g., 6500 = 65% discount)\n *\n * @returns The fee discount in basis points, or undefined if unavailable.\n */\n async calculateUserFeeDiscount(): Promise<number | undefined> {\n try {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: No EVM account found for fee discount',\n );\n return undefined;\n }\n\n // Get the chain ID via DI network controller\n const networkState = this.#messenger.call('NetworkController:getState');\n const { selectedNetworkClientId } = networkState;\n const chainId = this.#getChainIdForNetwork(selectedNetworkClientId);\n\n if (!chainId) {\n this.#deps.logger.error(\n new Error('Chain ID not found for fee discount calculation'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use pure utility function for CAIP formatting (pass logger for error reporting)\n const caipAccountId = formatAccountToCaipAccountId(\n evmAccount.address,\n chainId,\n this.#deps.logger,\n );\n\n if (!caipAccountId) {\n this.#deps.logger.error(\n new Error('Failed to format CAIP account ID for fee discount'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n address: evmAccount.address,\n chainId,\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use rewards via DI (no RewardsController in Core yet).\n // The rewards controller needs the perps MetaMask builder base fee in\n // bips to convert an absolute VIP fee into a discount fraction.\n const discountBips = await this.#deps.rewards.getPerpsDiscountForAccount(\n caipAccountId,\n BUILDER_FEE_CONFIG.MaxFeeDecimal * BASIS_POINTS_DIVISOR,\n );\n\n // null = subscription state not hydrated yet; surface as undefined so\n // callers don't treat it as a definitive \"no discount\" answer.\n if (discountBips === null) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount unavailable (subscription state not hydrated)',\n { address: evmAccount.address, caipAccountId },\n );\n return undefined;\n }\n\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount calculated',\n {\n address: evmAccount.address,\n caipAccountId,\n discountBips,\n discountPercentage: discountBips / 100,\n },\n );\n\n return discountBips;\n } catch (error) {\n this.#deps.logger.error(\n ensureError(\n error,\n 'RewardsIntegrationService.calculateUserFeeDiscount',\n ),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {},\n },\n },\n );\n return undefined;\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"RewardsIntegrationService.d.cts","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,yBAAyB,EAAE,2BAAiB;AAC1D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAKvE;;;;;;;GAOG;AACH,qBAAa,yBAAyB;;IAKpC;;;;;OAKG;gBAED,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B;IAyBzC;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CA2G9D"}
1
+ {"version":3,"file":"RewardsIntegrationService.d.cts","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,yBAAyB,EAAE,2BAAiB;AAC1D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAKvE;;;;;;;GAOG;AACH,qBAAa,yBAAyB;;IAKpC;;;;;OAKG;gBAED,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B;IAyBzC;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAuG9D"}
@@ -1 +1 @@
1
- {"version":3,"file":"RewardsIntegrationService.d.mts","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,yBAAyB,EAAE,2BAAiB;AAC1D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAKvE;;;;;;;GAOG;AACH,qBAAa,yBAAyB;;IAKpC;;;;;OAKG;gBAED,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B;IAyBzC;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CA2G9D"}
1
+ {"version":3,"file":"RewardsIntegrationService.d.mts","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,yBAAyB,EAAE,2BAAiB;AAC1D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA2B;AAKvE;;;;;;;GAOG;AACH,qBAAa,yBAAyB;;IAKpC;;;;;OAKG;gBAED,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B;IAyBzC;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAuG9D"}
@@ -12,7 +12,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
12
12
  var _RewardsIntegrationService_instances, _RewardsIntegrationService_deps, _RewardsIntegrationService_messenger, _RewardsIntegrationService_getChainIdForNetwork;
13
13
  import { BASIS_POINTS_DIVISOR, BUILDER_FEE_CONFIG } from "../constants/hyperLiquidConfig.mjs";
14
14
  import { PERPS_CONSTANTS } from "../constants/perpsConfig.mjs";
15
- import { getSelectedEvmAccount } from "../utils/accountUtils.mjs";
15
+ import { getSelectedEvmAccountFromMessenger } from "../utils/accountUtils.mjs";
16
16
  import { ensureError } from "../utils/errorUtils.mjs";
17
17
  import { formatAccountToCaipAccountId } from "../utils/rewardsUtils.mjs";
18
18
  /**
@@ -45,7 +45,7 @@ export class RewardsIntegrationService {
45
45
  */
46
46
  async calculateUserFeeDiscount() {
47
47
  try {
48
- const evmAccount = getSelectedEvmAccount(__classPrivateFieldGet(this, _RewardsIntegrationService_messenger, "f").call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
48
+ const evmAccount = getSelectedEvmAccountFromMessenger(__classPrivateFieldGet(this, _RewardsIntegrationService_messenger, "f"));
49
49
  if (!evmAccount) {
50
50
  __classPrivateFieldGet(this, _RewardsIntegrationService_deps, "f").debugLogger.log('RewardsIntegrationService: No EVM account found for fee discount');
51
51
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"RewardsIntegrationService.mjs","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BASIS_POINTS_DIVISOR,\n BUILDER_FEE_CONFIG,\n} from '../constants/hyperLiquidConfig';\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { PerpsPlatformDependencies } from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { getSelectedEvmAccount } from '../utils/accountUtils';\nimport { ensureError } from '../utils/errorUtils';\nimport { formatAccountToCaipAccountId } from '../utils/rewardsUtils';\n\n/**\n * RewardsIntegrationService\n *\n * Handles rewards-related operations and fee discount calculations.\n * Stateless service that coordinates with RewardsController and NetworkController.\n *\n * Instance-based service with constructor injection of platform dependencies.\n */\nexport class RewardsIntegrationService {\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n /**\n * Create a new RewardsIntegrationService instance\n *\n * @param deps - Platform dependencies for logging, metrics, etc.\n * @param messenger - Controller messenger for cross-controller communication.\n */\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n }\n\n /**\n * Get chain ID for a network client via DI network controller\n *\n * @param networkClientId - The network client identifier to look up.\n * @returns The chain ID string, or undefined if the network client is not found.\n */\n #getChainIdForNetwork(networkClientId: string): string | undefined {\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return networkClient.configuration.chainId;\n } catch {\n // Network client may not exist\n return undefined;\n }\n }\n\n /**\n * Calculate user fee discount from rewards\n * Returns discount in basis points (e.g., 6500 = 65% discount)\n *\n * @returns The fee discount in basis points, or undefined if unavailable.\n */\n async calculateUserFeeDiscount(): Promise<number | undefined> {\n try {\n const evmAccount = getSelectedEvmAccount(\n this.#messenger.call(\n 'AccountTreeController:getAccountsFromSelectedAccountGroup',\n ),\n );\n\n if (!evmAccount) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: No EVM account found for fee discount',\n );\n return undefined;\n }\n\n // Get the chain ID via DI network controller\n const networkState = this.#messenger.call('NetworkController:getState');\n const { selectedNetworkClientId } = networkState;\n const chainId = this.#getChainIdForNetwork(selectedNetworkClientId);\n\n if (!chainId) {\n this.#deps.logger.error(\n new Error('Chain ID not found for fee discount calculation'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use pure utility function for CAIP formatting (pass logger for error reporting)\n const caipAccountId = formatAccountToCaipAccountId(\n evmAccount.address,\n chainId,\n this.#deps.logger,\n );\n\n if (!caipAccountId) {\n this.#deps.logger.error(\n new Error('Failed to format CAIP account ID for fee discount'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n address: evmAccount.address,\n chainId,\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use rewards via DI (no RewardsController in Core yet).\n // The rewards controller needs the perps MetaMask builder base fee in\n // bips to convert an absolute VIP fee into a discount fraction.\n const discountBips = await this.#deps.rewards.getPerpsDiscountForAccount(\n caipAccountId,\n BUILDER_FEE_CONFIG.MaxFeeDecimal * BASIS_POINTS_DIVISOR,\n );\n\n // null = subscription state not hydrated yet; surface as undefined so\n // callers don't treat it as a definitive \"no discount\" answer.\n if (discountBips === null) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount unavailable (subscription state not hydrated)',\n { address: evmAccount.address, caipAccountId },\n );\n return undefined;\n }\n\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount calculated',\n {\n address: evmAccount.address,\n caipAccountId,\n discountBips,\n discountPercentage: discountBips / 100,\n },\n );\n\n return discountBips;\n } catch (error) {\n this.#deps.logger.error(\n ensureError(\n error,\n 'RewardsIntegrationService.calculateUserFeeDiscount',\n ),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {},\n },\n },\n );\n return undefined;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"RewardsIntegrationService.mjs","sourceRoot":"","sources":["../../src/services/RewardsIntegrationService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BASIS_POINTS_DIVISOR,\n BUILDER_FEE_CONFIG,\n} from '../constants/hyperLiquidConfig';\nimport { PERPS_CONSTANTS } from '../constants/perpsConfig';\nimport type { PerpsPlatformDependencies } from '../types';\nimport type { PerpsControllerMessengerBase } from '../types/messenger';\nimport { getSelectedEvmAccountFromMessenger } from '../utils/accountUtils';\nimport { ensureError } from '../utils/errorUtils';\nimport { formatAccountToCaipAccountId } from '../utils/rewardsUtils';\n\n/**\n * RewardsIntegrationService\n *\n * Handles rewards-related operations and fee discount calculations.\n * Stateless service that coordinates with RewardsController and NetworkController.\n *\n * Instance-based service with constructor injection of platform dependencies.\n */\nexport class RewardsIntegrationService {\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n /**\n * Create a new RewardsIntegrationService instance\n *\n * @param deps - Platform dependencies for logging, metrics, etc.\n * @param messenger - Controller messenger for cross-controller communication.\n */\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n }\n\n /**\n * Get chain ID for a network client via DI network controller\n *\n * @param networkClientId - The network client identifier to look up.\n * @returns The chain ID string, or undefined if the network client is not found.\n */\n #getChainIdForNetwork(networkClientId: string): string | undefined {\n try {\n const networkClient = this.#messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return networkClient.configuration.chainId;\n } catch {\n // Network client may not exist\n return undefined;\n }\n }\n\n /**\n * Calculate user fee discount from rewards\n * Returns discount in basis points (e.g., 6500 = 65% discount)\n *\n * @returns The fee discount in basis points, or undefined if unavailable.\n */\n async calculateUserFeeDiscount(): Promise<number | undefined> {\n try {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: No EVM account found for fee discount',\n );\n return undefined;\n }\n\n // Get the chain ID via DI network controller\n const networkState = this.#messenger.call('NetworkController:getState');\n const { selectedNetworkClientId } = networkState;\n const chainId = this.#getChainIdForNetwork(selectedNetworkClientId);\n\n if (!chainId) {\n this.#deps.logger.error(\n new Error('Chain ID not found for fee discount calculation'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use pure utility function for CAIP formatting (pass logger for error reporting)\n const caipAccountId = formatAccountToCaipAccountId(\n evmAccount.address,\n chainId,\n this.#deps.logger,\n );\n\n if (!caipAccountId) {\n this.#deps.logger.error(\n new Error('Failed to format CAIP account ID for fee discount'),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {\n address: evmAccount.address,\n chainId,\n selectedNetworkClientId,\n },\n },\n },\n );\n return undefined;\n }\n\n // Use rewards via DI (no RewardsController in Core yet).\n // The rewards controller needs the perps MetaMask builder base fee in\n // bips to convert an absolute VIP fee into a discount fraction.\n const discountBips = await this.#deps.rewards.getPerpsDiscountForAccount(\n caipAccountId,\n BUILDER_FEE_CONFIG.MaxFeeDecimal * BASIS_POINTS_DIVISOR,\n );\n\n // null = subscription state not hydrated yet; surface as undefined so\n // callers don't treat it as a definitive \"no discount\" answer.\n if (discountBips === null) {\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount unavailable (subscription state not hydrated)',\n { address: evmAccount.address, caipAccountId },\n );\n return undefined;\n }\n\n this.#deps.debugLogger.log(\n 'RewardsIntegrationService: Fee discount calculated',\n {\n address: evmAccount.address,\n caipAccountId,\n discountBips,\n discountPercentage: discountBips / 100,\n },\n );\n\n return discountBips;\n } catch (error) {\n this.#deps.logger.error(\n ensureError(\n error,\n 'RewardsIntegrationService.calculateUserFeeDiscount',\n ),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName },\n context: {\n name: 'RewardsIntegrationService.calculateUserFeeDiscount',\n data: {},\n },\n },\n );\n return undefined;\n }\n }\n}\n"]}
@@ -103,6 +103,7 @@ class PerpsSigningCacheManager {
103
103
  return {
104
104
  attempted: entry.unifiedAccount.attempted,
105
105
  enabled: entry.unifiedAccount.success,
106
+ reason: entry.unifiedAccount.reason,
106
107
  timestamp: entry.timestamp,
107
108
  };
108
109
  }
@@ -114,10 +115,15 @@ class PerpsSigningCacheManager {
114
115
  * @param data - The transaction data payload.
115
116
  * @param data.attempted - Whether the operation was attempted.
116
117
  * @param data.enabled - Whether the feature is enabled.
118
+ * @param data.reason - Optional discriminator explaining a non-success outcome.
117
119
  */
118
120
  set(network, userAddress, data) {
119
121
  const entry = __classPrivateFieldGet(this, _PerpsSigningCacheManager_instances, "m", _PerpsSigningCacheManager_getOrCreateEntry).call(this, network, userAddress);
120
- entry.unifiedAccount = { attempted: data.attempted, success: data.enabled };
122
+ entry.unifiedAccount = {
123
+ attempted: data.attempted,
124
+ success: data.enabled,
125
+ reason: data.reason,
126
+ };
121
127
  entry.timestamp = Date.now();
122
128
  }
123
129
  // ===== Builder Fee Methods =====
@@ -186,6 +192,38 @@ class PerpsSigningCacheManager {
186
192
  entry.timestamp = Date.now();
187
193
  }
188
194
  }
195
+ // ===== Wallet Registration Methods =====
196
+ /**
197
+ * Read the wallet's Hyperliquid registration signal.
198
+ *
199
+ * @param network - The network environment.
200
+ * @param userAddress - The user's wallet address.
201
+ * @returns The current signal, or undefined if no entry exists.
202
+ */
203
+ getWalletRegistered(network, userAddress) {
204
+ const key = __classPrivateFieldGet(this, _PerpsSigningCacheManager_instances, "m", _PerpsSigningCacheManager_getCacheKey).call(this, network, userAddress);
205
+ return __classPrivateFieldGet(this, _PerpsSigningCacheManager_cache, "f").get(key)?.walletRegistered;
206
+ }
207
+ /**
208
+ * Record whether the wallet has been observed on Hyperliquid. Once
209
+ * `registered=true` is set, it stays true for the session — the goal
210
+ * is to skip doomed exchange writes for unfunded wallets, not to
211
+ * gate them after they fund.
212
+ *
213
+ * @param network - The network environment.
214
+ * @param userAddress - The user's wallet address.
215
+ * @param registered - True once any evidence (clearinghouseState balance,
216
+ * userFills, successful deposit, ...) confirms the wallet exists on HL.
217
+ */
218
+ setWalletRegistered(network, userAddress, registered) {
219
+ const entry = __classPrivateFieldGet(this, _PerpsSigningCacheManager_instances, "m", _PerpsSigningCacheManager_getOrCreateEntry).call(this, network, userAddress);
220
+ if (entry.walletRegistered.registered && !registered) {
221
+ // Monotonic: once registered, never demote.
222
+ return;
223
+ }
224
+ entry.walletRegistered = { known: true, registered };
225
+ entry.timestamp = Date.now();
226
+ }
189
227
  /**
190
228
  * Clear only builder fee state for a specific network and user address
191
229
  * This preserves unified account and referral states
@@ -260,7 +298,8 @@ class PerpsSigningCacheManager {
260
298
  __classPrivateFieldGet(this, _PerpsSigningCacheManager_cache, "f").forEach((entry, key) => {
261
299
  entries.push(`${key}: unified=${entry.unifiedAccount.attempted}/${entry.unifiedAccount.success}, ` +
262
300
  `builder=${entry.builderFee.attempted}/${entry.builderFee.success}, ` +
263
- `referral=${entry.referral.attempted}/${entry.referral.success}`);
301
+ `referral=${entry.referral.attempted}/${entry.referral.success}, ` +
302
+ `walletRegistered=${entry.walletRegistered.known}/${entry.walletRegistered.registered}`);
264
303
  });
265
304
  return entries.join('\n') || '(empty)';
266
305
  }
@@ -275,6 +314,7 @@ _a = PerpsSigningCacheManager, _PerpsSigningCacheManager_cache = new WeakMap(),
275
314
  unifiedAccount: { attempted: false, success: false },
276
315
  builderFee: { attempted: false, success: false },
277
316
  referral: { attempted: false, success: false },
317
+ walletRegistered: { known: false, registered: false },
278
318
  timestamp: Date.now(),
279
319
  };
280
320
  __classPrivateFieldGet(this, _PerpsSigningCacheManager_cache, "f").set(key, entry);
@@ -1 +1 @@
1
- {"version":3,"file":"TradingReadinessCache.cjs","sourceRoot":"","sources":["../../src/services/TradingReadinessCache.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Global singleton cache for Perps signing operations\n *\n * This cache persists across provider reconnections to prevent repeated\n * signing requests for hardware wallets. Critical for preventing repeated\n * hardware wallet signing prompts.\n *\n * Cache is intentionally kept separate from provider instances because providers\n * are recreated on account/network changes, which would reset instance-level caches.\n *\n * Tracks three signing operations:\n * 1. Unified Account enablement (one-time, replaces deprecated DEX abstraction)\n * 2. Builder Fee approval (required for trading)\n * 3. Referral code setup (one-time per account)\n *\n * Cache Structure:\n * - Key: `network:userAddress` (e.g., \"mainnet:0x123...\")\n * - Value: { unifiedAccount, builderFee, referral, timestamp }\n *\n * Lifecycle:\n * - Cache persists throughout app session\n * - Individual entries can be cleared per user/network\n * - Full cache can be cleared on app restart or explicit user action\n */\n\ntype SigningOperationState = {\n attempted: boolean; // Whether we've attempted this operation\n success: boolean; // Whether it succeeded (only valid if attempted=true)\n};\n\ntype PerpsSigningCacheEntry = {\n unifiedAccount: SigningOperationState;\n builderFee: SigningOperationState;\n referral: SigningOperationState;\n timestamp: number; // When this entry was last updated\n};\n\n// Legacy interface for backward compatibility\ntype TradingReadinessCacheEntry = {\n attempted: boolean;\n enabled: boolean;\n timestamp: number;\n};\n\nclass PerpsSigningCacheManager {\n static #instance: PerpsSigningCacheManager;\n\n readonly #cache: Map<string, PerpsSigningCacheEntry> = new Map();\n\n // Global in-flight locks to prevent concurrent signing attempts across providers\n // Key: operationType:network:userAddress, Value: Promise that resolves when operation completes\n readonly #inFlightOperations: Map<string, Promise<void>> = new Map();\n\n // Singleton: use getInstance() instead of new\n protected constructor() {\n // Protected constructor for singleton\n }\n\n public static getInstance(): PerpsSigningCacheManager {\n PerpsSigningCacheManager.#instance ??= new PerpsSigningCacheManager();\n return PerpsSigningCacheManager.#instance;\n }\n\n // ===== In-Flight Lock Methods =====\n\n /**\n * Check if an operation is currently in-flight for this user/network\n *\n * @param operationType - The type of operation being performed.\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public isInFlight(\n operationType: 'unifiedAccount' | 'builderFee' | 'referral',\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): Promise<void> | undefined {\n const key = `${operationType}:${network}:${userAddress.toLowerCase()}`;\n return this.#inFlightOperations.get(key);\n }\n\n /**\n * Set an operation as in-flight\n * Returns a function to call when operation completes\n *\n * @param operationType - The type of operation being performed.\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public setInFlight(\n operationType: 'unifiedAccount' | 'builderFee' | 'referral',\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): () => void {\n const key = `${operationType}:${network}:${userAddress.toLowerCase()}`;\n let resolvePromise: () => void;\n const promise = new Promise<void>((resolve) => {\n resolvePromise = resolve;\n });\n this.#inFlightOperations.set(key, promise);\n return () => {\n this.#inFlightOperations.delete(key);\n resolvePromise();\n };\n }\n\n #getCacheKey(network: 'mainnet' | 'testnet', userAddress: string): string {\n return `${network}:${userAddress.toLowerCase()}`;\n }\n\n #getOrCreateEntry(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): PerpsSigningCacheEntry {\n const key = this.#getCacheKey(network, userAddress);\n let entry = this.#cache.get(key);\n if (!entry) {\n entry = {\n unifiedAccount: { attempted: false, success: false },\n builderFee: { attempted: false, success: false },\n referral: { attempted: false, success: false },\n timestamp: Date.now(),\n };\n this.#cache.set(key, entry);\n }\n return entry;\n }\n\n // ===== Unified Account Methods =====\n\n /**\n * Get unified account cache entry (legacy compatibility)\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public get(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): TradingReadinessCacheEntry | undefined {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (!entry) {\n return undefined;\n }\n return {\n attempted: entry.unifiedAccount.attempted,\n enabled: entry.unifiedAccount.success,\n timestamp: entry.timestamp,\n };\n }\n\n /**\n * Set unified account cache entry (legacy compatibility)\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @param data - The transaction data payload.\n * @param data.attempted - Whether the operation was attempted.\n * @param data.enabled - Whether the feature is enabled.\n */\n public set(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n data: { attempted: boolean; enabled: boolean },\n ): void {\n const entry = this.#getOrCreateEntry(network, userAddress);\n entry.unifiedAccount = { attempted: data.attempted, success: data.enabled };\n entry.timestamp = Date.now();\n }\n\n // ===== Builder Fee Methods =====\n\n /**\n * Check if builder fee approval was attempted\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public getBuilderFee(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): SigningOperationState | undefined {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n return entry?.builderFee;\n }\n\n /**\n * Set builder fee approval state\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @param state - The current state.\n */\n public setBuilderFee(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n state: SigningOperationState,\n ): void {\n const entry = this.#getOrCreateEntry(network, userAddress);\n entry.builderFee = state;\n entry.timestamp = Date.now();\n }\n\n // ===== Referral Methods =====\n\n /**\n * Check if referral setup was attempted\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public getReferral(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): SigningOperationState | undefined {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n return entry?.referral;\n }\n\n /**\n * Set referral setup state\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @param state - The current state.\n */\n public setReferral(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n state: SigningOperationState,\n ): void {\n const entry = this.#getOrCreateEntry(network, userAddress);\n entry.referral = state;\n entry.timestamp = Date.now();\n }\n\n // ===== General Methods =====\n\n /**\n * Clear only unified account state for a specific network and user address\n * This preserves builder fee and referral states\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clearUnifiedAccount(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): void {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (entry) {\n entry.unifiedAccount = { attempted: false, success: false };\n entry.timestamp = Date.now();\n }\n }\n\n /**\n * Clear only builder fee state for a specific network and user address\n * This preserves unified account and referral states\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clearBuilderFee(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): void {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (entry) {\n entry.builderFee = { attempted: false, success: false };\n entry.timestamp = Date.now();\n }\n }\n\n /**\n * Clear only referral state for a specific network and user address\n * This preserves unified account and builder fee states\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clearReferral(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): void {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (entry) {\n entry.referral = { attempted: false, success: false };\n entry.timestamp = Date.now();\n }\n }\n\n /**\n * Clear entire cache entry for a specific network and user address\n * WARNING: This clears ALL signing operation states (unifiedAccount, builderFee, referral)\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clear(network: 'mainnet' | 'testnet', userAddress: string): void {\n const key = this.#getCacheKey(network, userAddress);\n this.#cache.delete(key);\n }\n\n /**\n * Clear all cache entries\n * WARNING: This clears ALL signing operation states for ALL users\n */\n public clearAll(): void {\n this.#cache.clear();\n }\n\n /**\n * Get all cache entries (for debugging)\n *\n * @returns The result of the operation.\n */\n public getAll(): Map<string, PerpsSigningCacheEntry> {\n return new Map(this.#cache);\n }\n\n /**\n * Get cache size (for debugging)\n *\n * @returns The resulting numeric value.\n */\n public size(): number {\n return this.#cache.size;\n }\n\n /**\n * Get full cache state for debugging\n *\n * @returns The resulting string value.\n */\n public debugState(): string {\n const entries: string[] = [];\n this.#cache.forEach((entry, key) => {\n entries.push(\n `${key}: unified=${entry.unifiedAccount.attempted}/${entry.unifiedAccount.success}, ` +\n `builder=${entry.builderFee.attempted}/${entry.builderFee.success}, ` +\n `referral=${entry.referral.attempted}/${entry.referral.success}`,\n );\n });\n return entries.join('\\n') || '(empty)';\n }\n}\n\n// Export singleton instance with backward-compatible name\nexport const TradingReadinessCache = PerpsSigningCacheManager.getInstance();\n\n// Export with new name for clarity\nexport const PerpsSigningCache = PerpsSigningCacheManager.getInstance();\n"]}
1
+ {"version":3,"file":"TradingReadinessCache.cjs","sourceRoot":"","sources":["../../src/services/TradingReadinessCache.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Global singleton cache for Perps signing operations\n *\n * This cache persists across provider reconnections to prevent repeated\n * signing requests for hardware wallets. Critical for preventing repeated\n * hardware wallet signing prompts.\n *\n * Cache is intentionally kept separate from provider instances because providers\n * are recreated on account/network changes, which would reset instance-level caches.\n *\n * Tracks three signing operations:\n * 1. Unified Account enablement (one-time, replaces deprecated DEX abstraction)\n * 2. Builder Fee approval (required for trading)\n * 3. Referral code setup (one-time per account)\n *\n * Cache Structure:\n * - Key: `network:userAddress` (e.g., \"mainnet:0x123...\")\n * - Value: { unifiedAccount, builderFee, referral, timestamp }\n *\n * Lifecycle:\n * - Cache persists throughout app session\n * - Individual entries can be cleared per user/network\n * - Full cache can be cleared on app restart or explicit user action\n */\n\ntype SigningOperationState = {\n attempted: boolean; // Whether we've attempted this operation\n success: boolean; // Whether it succeeded (only valid if attempted=true)\n reason?: 'no_hl_account' | 'user_rejected' | 'transient'; // optional discriminator\n};\n\n// Tracks whether the wallet has ever been observed on Hyperliquid.\n// Hyperliquid accounts only come into existence on first USDC deposit.\n// Before then, user-scoped exchange writes (agentSetAbstraction,\n// userSetAbstraction, setReferrer, ...) reject with\n// \"User or API Wallet 0x... does not exist.\"\n// Used to skip those writes proactively rather than catching the rejection.\ntype WalletRegistrationState = {\n known: boolean; // Whether we have signal at all\n registered: boolean; // True once observed on Hyperliquid (monotonic)\n};\n\ntype PerpsSigningCacheEntry = {\n unifiedAccount: SigningOperationState;\n builderFee: SigningOperationState;\n referral: SigningOperationState;\n walletRegistered: WalletRegistrationState;\n timestamp: number; // When this entry was last updated\n};\n\n// Legacy interface for backward compatibility\ntype TradingReadinessCacheEntry = {\n attempted: boolean;\n enabled: boolean;\n reason?: 'no_hl_account' | 'user_rejected' | 'transient';\n timestamp: number;\n};\n\nclass PerpsSigningCacheManager {\n static #instance: PerpsSigningCacheManager;\n\n readonly #cache: Map<string, PerpsSigningCacheEntry> = new Map();\n\n // Global in-flight locks to prevent concurrent signing attempts across providers\n // Key: operationType:network:userAddress, Value: Promise that resolves when operation completes\n readonly #inFlightOperations: Map<string, Promise<void>> = new Map();\n\n // Singleton: use getInstance() instead of new\n protected constructor() {\n // Protected constructor for singleton\n }\n\n public static getInstance(): PerpsSigningCacheManager {\n PerpsSigningCacheManager.#instance ??= new PerpsSigningCacheManager();\n return PerpsSigningCacheManager.#instance;\n }\n\n // ===== In-Flight Lock Methods =====\n\n /**\n * Check if an operation is currently in-flight for this user/network\n *\n * @param operationType - The type of operation being performed.\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public isInFlight(\n operationType: 'unifiedAccount' | 'builderFee' | 'referral',\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): Promise<void> | undefined {\n const key = `${operationType}:${network}:${userAddress.toLowerCase()}`;\n return this.#inFlightOperations.get(key);\n }\n\n /**\n * Set an operation as in-flight\n * Returns a function to call when operation completes\n *\n * @param operationType - The type of operation being performed.\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public setInFlight(\n operationType: 'unifiedAccount' | 'builderFee' | 'referral',\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): () => void {\n const key = `${operationType}:${network}:${userAddress.toLowerCase()}`;\n let resolvePromise: () => void;\n const promise = new Promise<void>((resolve) => {\n resolvePromise = resolve;\n });\n this.#inFlightOperations.set(key, promise);\n return () => {\n this.#inFlightOperations.delete(key);\n resolvePromise();\n };\n }\n\n #getCacheKey(network: 'mainnet' | 'testnet', userAddress: string): string {\n return `${network}:${userAddress.toLowerCase()}`;\n }\n\n #getOrCreateEntry(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): PerpsSigningCacheEntry {\n const key = this.#getCacheKey(network, userAddress);\n let entry = this.#cache.get(key);\n if (!entry) {\n entry = {\n unifiedAccount: { attempted: false, success: false },\n builderFee: { attempted: false, success: false },\n referral: { attempted: false, success: false },\n walletRegistered: { known: false, registered: false },\n timestamp: Date.now(),\n };\n this.#cache.set(key, entry);\n }\n return entry;\n }\n\n // ===== Unified Account Methods =====\n\n /**\n * Get unified account cache entry (legacy compatibility)\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public get(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): TradingReadinessCacheEntry | undefined {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (!entry) {\n return undefined;\n }\n return {\n attempted: entry.unifiedAccount.attempted,\n enabled: entry.unifiedAccount.success,\n reason: entry.unifiedAccount.reason,\n timestamp: entry.timestamp,\n };\n }\n\n /**\n * Set unified account cache entry (legacy compatibility)\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @param data - The transaction data payload.\n * @param data.attempted - Whether the operation was attempted.\n * @param data.enabled - Whether the feature is enabled.\n * @param data.reason - Optional discriminator explaining a non-success outcome.\n */\n public set(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n data: {\n attempted: boolean;\n enabled: boolean;\n reason?: 'no_hl_account' | 'user_rejected' | 'transient';\n },\n ): void {\n const entry = this.#getOrCreateEntry(network, userAddress);\n entry.unifiedAccount = {\n attempted: data.attempted,\n success: data.enabled,\n reason: data.reason,\n };\n entry.timestamp = Date.now();\n }\n\n // ===== Builder Fee Methods =====\n\n /**\n * Check if builder fee approval was attempted\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public getBuilderFee(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): SigningOperationState | undefined {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n return entry?.builderFee;\n }\n\n /**\n * Set builder fee approval state\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @param state - The current state.\n */\n public setBuilderFee(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n state: SigningOperationState,\n ): void {\n const entry = this.#getOrCreateEntry(network, userAddress);\n entry.builderFee = state;\n entry.timestamp = Date.now();\n }\n\n // ===== Referral Methods =====\n\n /**\n * Check if referral setup was attempted\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The resulting string value.\n */\n public getReferral(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): SigningOperationState | undefined {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n return entry?.referral;\n }\n\n /**\n * Set referral setup state\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @param state - The current state.\n */\n public setReferral(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n state: SigningOperationState,\n ): void {\n const entry = this.#getOrCreateEntry(network, userAddress);\n entry.referral = state;\n entry.timestamp = Date.now();\n }\n\n // ===== General Methods =====\n\n /**\n * Clear only unified account state for a specific network and user address\n * This preserves builder fee and referral states\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clearUnifiedAccount(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): void {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (entry) {\n entry.unifiedAccount = { attempted: false, success: false };\n entry.timestamp = Date.now();\n }\n }\n\n // ===== Wallet Registration Methods =====\n\n /**\n * Read the wallet's Hyperliquid registration signal.\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @returns The current signal, or undefined if no entry exists.\n */\n public getWalletRegistered(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): WalletRegistrationState | undefined {\n const key = this.#getCacheKey(network, userAddress);\n return this.#cache.get(key)?.walletRegistered;\n }\n\n /**\n * Record whether the wallet has been observed on Hyperliquid. Once\n * `registered=true` is set, it stays true for the session — the goal\n * is to skip doomed exchange writes for unfunded wallets, not to\n * gate them after they fund.\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n * @param registered - True once any evidence (clearinghouseState balance,\n * userFills, successful deposit, ...) confirms the wallet exists on HL.\n */\n public setWalletRegistered(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n registered: boolean,\n ): void {\n const entry = this.#getOrCreateEntry(network, userAddress);\n if (entry.walletRegistered.registered && !registered) {\n // Monotonic: once registered, never demote.\n return;\n }\n entry.walletRegistered = { known: true, registered };\n entry.timestamp = Date.now();\n }\n\n /**\n * Clear only builder fee state for a specific network and user address\n * This preserves unified account and referral states\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clearBuilderFee(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): void {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (entry) {\n entry.builderFee = { attempted: false, success: false };\n entry.timestamp = Date.now();\n }\n }\n\n /**\n * Clear only referral state for a specific network and user address\n * This preserves unified account and builder fee states\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clearReferral(\n network: 'mainnet' | 'testnet',\n userAddress: string,\n ): void {\n const key = this.#getCacheKey(network, userAddress);\n const entry = this.#cache.get(key);\n if (entry) {\n entry.referral = { attempted: false, success: false };\n entry.timestamp = Date.now();\n }\n }\n\n /**\n * Clear entire cache entry for a specific network and user address\n * WARNING: This clears ALL signing operation states (unifiedAccount, builderFee, referral)\n *\n * @param network - The network environment.\n * @param userAddress - The user's wallet address.\n */\n public clear(network: 'mainnet' | 'testnet', userAddress: string): void {\n const key = this.#getCacheKey(network, userAddress);\n this.#cache.delete(key);\n }\n\n /**\n * Clear all cache entries\n * WARNING: This clears ALL signing operation states for ALL users\n */\n public clearAll(): void {\n this.#cache.clear();\n }\n\n /**\n * Get all cache entries (for debugging)\n *\n * @returns The result of the operation.\n */\n public getAll(): Map<string, PerpsSigningCacheEntry> {\n return new Map(this.#cache);\n }\n\n /**\n * Get cache size (for debugging)\n *\n * @returns The resulting numeric value.\n */\n public size(): number {\n return this.#cache.size;\n }\n\n /**\n * Get full cache state for debugging\n *\n * @returns The resulting string value.\n */\n public debugState(): string {\n const entries: string[] = [];\n this.#cache.forEach((entry, key) => {\n entries.push(\n `${key}: unified=${entry.unifiedAccount.attempted}/${entry.unifiedAccount.success}, ` +\n `builder=${entry.builderFee.attempted}/${entry.builderFee.success}, ` +\n `referral=${entry.referral.attempted}/${entry.referral.success}, ` +\n `walletRegistered=${entry.walletRegistered.known}/${entry.walletRegistered.registered}`,\n );\n });\n return entries.join('\\n') || '(empty)';\n }\n}\n\n// Export singleton instance with backward-compatible name\nexport const TradingReadinessCache = PerpsSigningCacheManager.getInstance();\n\n// Export with new name for clarity\nexport const PerpsSigningCache = PerpsSigningCacheManager.getInstance();\n"]}