@metamask-previews/perps-controller 0.0.0-preview-0eb28104d → 1.0.0-preview-968b2b4f4

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 (482) hide show
  1. package/CHANGELOG.md +30 -2
  2. package/dist/PerpsController.cjs +3077 -65
  3. package/dist/PerpsController.cjs.map +1 -1
  4. package/dist/PerpsController.d.cts +969 -82
  5. package/dist/PerpsController.d.cts.map +1 -1
  6. package/dist/PerpsController.d.mts +969 -82
  7. package/dist/PerpsController.d.mts.map +1 -1
  8. package/dist/PerpsController.mjs +3073 -62
  9. package/dist/PerpsController.mjs.map +1 -1
  10. package/dist/aggregation/SubscriptionMultiplexer.cjs +441 -0
  11. package/dist/aggregation/SubscriptionMultiplexer.cjs.map +1 -0
  12. package/dist/aggregation/SubscriptionMultiplexer.d.cts +171 -0
  13. package/dist/aggregation/SubscriptionMultiplexer.d.cts.map +1 -0
  14. package/dist/aggregation/SubscriptionMultiplexer.d.mts +171 -0
  15. package/dist/aggregation/SubscriptionMultiplexer.d.mts.map +1 -0
  16. package/dist/aggregation/SubscriptionMultiplexer.mjs +437 -0
  17. package/dist/aggregation/SubscriptionMultiplexer.mjs.map +1 -0
  18. package/dist/aggregation/index.cjs +9 -0
  19. package/dist/aggregation/index.cjs.map +1 -0
  20. package/dist/aggregation/index.d.cts +6 -0
  21. package/dist/aggregation/index.d.cts.map +1 -0
  22. package/dist/aggregation/index.d.mts +6 -0
  23. package/dist/aggregation/index.d.mts.map +1 -0
  24. package/dist/aggregation/index.mjs +5 -0
  25. package/dist/aggregation/index.mjs.map +1 -0
  26. package/dist/constants/chartConfig.cjs +227 -0
  27. package/dist/constants/chartConfig.cjs.map +1 -0
  28. package/dist/constants/chartConfig.d.cts +216 -0
  29. package/dist/constants/chartConfig.d.cts.map +1 -0
  30. package/dist/constants/chartConfig.d.mts +216 -0
  31. package/dist/constants/chartConfig.d.mts.map +1 -0
  32. package/dist/constants/chartConfig.mjs +221 -0
  33. package/dist/constants/chartConfig.mjs.map +1 -0
  34. package/dist/constants/eventNames.cjs +436 -0
  35. package/dist/constants/eventNames.cjs.map +1 -0
  36. package/dist/constants/eventNames.d.cts +387 -0
  37. package/dist/constants/eventNames.d.cts.map +1 -0
  38. package/dist/constants/eventNames.d.mts +387 -0
  39. package/dist/constants/eventNames.d.mts.map +1 -0
  40. package/dist/constants/eventNames.mjs +433 -0
  41. package/dist/constants/eventNames.mjs.map +1 -0
  42. package/dist/constants/hyperLiquidConfig.cjs +380 -0
  43. package/dist/constants/hyperLiquidConfig.cjs.map +1 -0
  44. package/dist/constants/hyperLiquidConfig.d.cts +236 -0
  45. package/dist/constants/hyperLiquidConfig.d.cts.map +1 -0
  46. package/dist/constants/hyperLiquidConfig.d.mts +236 -0
  47. package/dist/constants/hyperLiquidConfig.d.mts.map +1 -0
  48. package/dist/constants/hyperLiquidConfig.mjs +371 -0
  49. package/dist/constants/hyperLiquidConfig.mjs.map +1 -0
  50. package/dist/constants/index.cjs +28 -0
  51. package/dist/constants/index.cjs.map +1 -0
  52. package/dist/constants/index.d.cts +12 -0
  53. package/dist/constants/index.d.cts.map +1 -0
  54. package/dist/constants/index.d.mts +12 -0
  55. package/dist/constants/index.d.mts.map +1 -0
  56. package/dist/constants/index.mjs +12 -0
  57. package/dist/constants/index.mjs.map +1 -0
  58. package/dist/constants/myxConfig.cjs +229 -0
  59. package/dist/constants/myxConfig.cjs.map +1 -0
  60. package/dist/constants/myxConfig.d.cts +106 -0
  61. package/dist/constants/myxConfig.d.cts.map +1 -0
  62. package/dist/constants/myxConfig.d.mts +106 -0
  63. package/dist/constants/myxConfig.d.mts.map +1 -0
  64. package/dist/constants/myxConfig.mjs +219 -0
  65. package/dist/constants/myxConfig.mjs.map +1 -0
  66. package/dist/constants/orderTypes.cjs +31 -0
  67. package/dist/constants/orderTypes.cjs.map +1 -0
  68. package/dist/constants/orderTypes.d.cts +19 -0
  69. package/dist/constants/orderTypes.d.cts.map +1 -0
  70. package/dist/constants/orderTypes.d.mts +19 -0
  71. package/dist/constants/orderTypes.d.mts.map +1 -0
  72. package/dist/constants/orderTypes.mjs +27 -0
  73. package/dist/constants/orderTypes.mjs.map +1 -0
  74. package/dist/constants/performanceMetrics.cjs +63 -0
  75. package/dist/constants/performanceMetrics.cjs.map +1 -0
  76. package/dist/constants/performanceMetrics.d.cts +46 -0
  77. package/dist/constants/performanceMetrics.d.cts.map +1 -0
  78. package/dist/constants/performanceMetrics.d.mts +46 -0
  79. package/dist/constants/performanceMetrics.d.mts.map +1 -0
  80. package/dist/constants/performanceMetrics.mjs +60 -0
  81. package/dist/constants/performanceMetrics.mjs.map +1 -0
  82. package/dist/constants/perpsConfig.cjs +295 -0
  83. package/dist/constants/perpsConfig.cjs.map +1 -0
  84. package/dist/constants/perpsConfig.d.cts +221 -0
  85. package/dist/constants/perpsConfig.d.cts.map +1 -0
  86. package/dist/constants/perpsConfig.d.mts +221 -0
  87. package/dist/constants/perpsConfig.d.mts.map +1 -0
  88. package/dist/constants/perpsConfig.mjs +292 -0
  89. package/dist/constants/perpsConfig.mjs.map +1 -0
  90. package/dist/constants/transactionsHistoryConfig.cjs +19 -0
  91. package/dist/constants/transactionsHistoryConfig.cjs.map +1 -0
  92. package/dist/constants/transactionsHistoryConfig.d.cts +16 -0
  93. package/dist/constants/transactionsHistoryConfig.d.cts.map +1 -0
  94. package/dist/constants/transactionsHistoryConfig.d.mts +16 -0
  95. package/dist/constants/transactionsHistoryConfig.d.mts.map +1 -0
  96. package/dist/constants/transactionsHistoryConfig.mjs +16 -0
  97. package/dist/constants/transactionsHistoryConfig.mjs.map +1 -0
  98. package/dist/index.cjs +63 -1
  99. package/dist/index.cjs.map +1 -1
  100. package/dist/index.d.cts +38 -2
  101. package/dist/index.d.cts.map +1 -1
  102. package/dist/index.d.mts +38 -2
  103. package/dist/index.d.mts.map +1 -1
  104. package/dist/index.mjs +46 -1
  105. package/dist/index.mjs.map +1 -1
  106. package/dist/perpsErrorCodes.cjs +80 -0
  107. package/dist/perpsErrorCodes.cjs.map +1 -0
  108. package/dist/perpsErrorCodes.d.cts +65 -0
  109. package/dist/perpsErrorCodes.d.cts.map +1 -0
  110. package/dist/perpsErrorCodes.d.mts +65 -0
  111. package/dist/perpsErrorCodes.d.mts.map +1 -0
  112. package/dist/perpsErrorCodes.mjs +77 -0
  113. package/dist/perpsErrorCodes.mjs.map +1 -0
  114. package/dist/providers/AggregatedPerpsProvider.cjs +508 -0
  115. package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -0
  116. package/dist/providers/AggregatedPerpsProvider.d.cts +171 -0
  117. package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -0
  118. package/dist/providers/AggregatedPerpsProvider.d.mts +171 -0
  119. package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -0
  120. package/dist/providers/AggregatedPerpsProvider.mjs +504 -0
  121. package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -0
  122. package/dist/providers/HyperLiquidProvider.cjs +5679 -0
  123. package/dist/providers/HyperLiquidProvider.cjs.map +1 -0
  124. package/dist/providers/HyperLiquidProvider.d.cts +516 -0
  125. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -0
  126. package/dist/providers/HyperLiquidProvider.d.mts +516 -0
  127. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -0
  128. package/dist/providers/HyperLiquidProvider.mjs +5675 -0
  129. package/dist/providers/HyperLiquidProvider.mjs.map +1 -0
  130. package/dist/providers/MYXProvider.cjs +514 -0
  131. package/dist/providers/MYXProvider.cjs.map +1 -0
  132. package/dist/providers/MYXProvider.d.cts +105 -0
  133. package/dist/providers/MYXProvider.d.cts.map +1 -0
  134. package/dist/providers/MYXProvider.d.mts +105 -0
  135. package/dist/providers/MYXProvider.d.mts.map +1 -0
  136. package/dist/providers/MYXProvider.mjs +510 -0
  137. package/dist/providers/MYXProvider.mjs.map +1 -0
  138. package/dist/routing/ProviderRouter.cjs +154 -0
  139. package/dist/routing/ProviderRouter.cjs.map +1 -0
  140. package/dist/routing/ProviderRouter.d.cts +112 -0
  141. package/dist/routing/ProviderRouter.d.cts.map +1 -0
  142. package/dist/routing/ProviderRouter.d.mts +112 -0
  143. package/dist/routing/ProviderRouter.d.mts.map +1 -0
  144. package/dist/routing/ProviderRouter.mjs +150 -0
  145. package/dist/routing/ProviderRouter.mjs.map +1 -0
  146. package/dist/routing/index.cjs +9 -0
  147. package/dist/routing/index.cjs.map +1 -0
  148. package/dist/routing/index.d.cts +6 -0
  149. package/dist/routing/index.d.cts.map +1 -0
  150. package/dist/routing/index.d.mts +6 -0
  151. package/dist/routing/index.d.mts.map +1 -0
  152. package/dist/routing/index.mjs +5 -0
  153. package/dist/routing/index.mjs.map +1 -0
  154. package/dist/selectors.cjs +166 -0
  155. package/dist/selectors.cjs.map +1 -0
  156. package/dist/selectors.d.cts +362 -0
  157. package/dist/selectors.d.cts.map +1 -0
  158. package/dist/selectors.d.mts +362 -0
  159. package/dist/selectors.d.mts.map +1 -0
  160. package/dist/selectors.mjs +158 -0
  161. package/dist/selectors.mjs.map +1 -0
  162. package/dist/services/AccountService.cjs +324 -0
  163. package/dist/services/AccountService.cjs.map +1 -0
  164. package/dist/services/AccountService.d.cts +56 -0
  165. package/dist/services/AccountService.d.cts.map +1 -0
  166. package/dist/services/AccountService.d.mts +56 -0
  167. package/dist/services/AccountService.d.mts.map +1 -0
  168. package/dist/services/AccountService.mjs +320 -0
  169. package/dist/services/AccountService.mjs.map +1 -0
  170. package/dist/services/DataLakeService.cjs +233 -0
  171. package/dist/services/DataLakeService.cjs.map +1 -0
  172. package/dist/services/DataLakeService.d.cts +51 -0
  173. package/dist/services/DataLakeService.d.cts.map +1 -0
  174. package/dist/services/DataLakeService.d.mts +51 -0
  175. package/dist/services/DataLakeService.d.mts.map +1 -0
  176. package/dist/services/DataLakeService.mjs +229 -0
  177. package/dist/services/DataLakeService.mjs.map +1 -0
  178. package/dist/services/DepositService.cjs +98 -0
  179. package/dist/services/DepositService.cjs.map +1 -0
  180. package/dist/services/DepositService.d.cts +39 -0
  181. package/dist/services/DepositService.d.cts.map +1 -0
  182. package/dist/services/DepositService.d.mts +39 -0
  183. package/dist/services/DepositService.d.mts.map +1 -0
  184. package/dist/services/DepositService.mjs +94 -0
  185. package/dist/services/DepositService.mjs.map +1 -0
  186. package/dist/services/EligibilityService.cjs +173 -0
  187. package/dist/services/EligibilityService.cjs.map +1 -0
  188. package/dist/services/EligibilityService.d.cts +39 -0
  189. package/dist/services/EligibilityService.d.cts.map +1 -0
  190. package/dist/services/EligibilityService.d.mts +39 -0
  191. package/dist/services/EligibilityService.d.mts.map +1 -0
  192. package/dist/services/EligibilityService.mjs +169 -0
  193. package/dist/services/EligibilityService.mjs.map +1 -0
  194. package/dist/services/FeatureFlagConfigurationService.cjs +257 -0
  195. package/dist/services/FeatureFlagConfigurationService.cjs.map +1 -0
  196. package/dist/services/FeatureFlagConfigurationService.d.cts +73 -0
  197. package/dist/services/FeatureFlagConfigurationService.d.cts.map +1 -0
  198. package/dist/services/FeatureFlagConfigurationService.d.mts +73 -0
  199. package/dist/services/FeatureFlagConfigurationService.d.mts.map +1 -0
  200. package/dist/services/FeatureFlagConfigurationService.mjs +253 -0
  201. package/dist/services/FeatureFlagConfigurationService.mjs.map +1 -0
  202. package/dist/services/HyperLiquidClientService.cjs +867 -0
  203. package/dist/services/HyperLiquidClientService.cjs.map +1 -0
  204. package/dist/services/HyperLiquidClientService.d.cts +214 -0
  205. package/dist/services/HyperLiquidClientService.d.cts.map +1 -0
  206. package/dist/services/HyperLiquidClientService.d.mts +214 -0
  207. package/dist/services/HyperLiquidClientService.d.mts.map +1 -0
  208. package/dist/services/HyperLiquidClientService.mjs +862 -0
  209. package/dist/services/HyperLiquidClientService.mjs.map +1 -0
  210. package/dist/services/HyperLiquidSubscriptionService.cjs +2199 -0
  211. package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -0
  212. package/dist/services/HyperLiquidSubscriptionService.d.cts +187 -0
  213. package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -0
  214. package/dist/services/HyperLiquidSubscriptionService.d.mts +187 -0
  215. package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -0
  216. package/dist/services/HyperLiquidSubscriptionService.mjs +2195 -0
  217. package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -0
  218. package/dist/services/HyperLiquidWalletService.cjs +163 -0
  219. package/dist/services/HyperLiquidWalletService.cjs.map +1 -0
  220. package/dist/services/HyperLiquidWalletService.d.cts +78 -0
  221. package/dist/services/HyperLiquidWalletService.d.cts.map +1 -0
  222. package/dist/services/HyperLiquidWalletService.d.mts +78 -0
  223. package/dist/services/HyperLiquidWalletService.d.mts.map +1 -0
  224. package/dist/services/HyperLiquidWalletService.mjs +159 -0
  225. package/dist/services/HyperLiquidWalletService.mjs.map +1 -0
  226. package/dist/services/MYXClientService.cjs +304 -0
  227. package/dist/services/MYXClientService.cjs.map +1 -0
  228. package/dist/services/MYXClientService.d.cts +81 -0
  229. package/dist/services/MYXClientService.d.cts.map +1 -0
  230. package/dist/services/MYXClientService.d.mts +81 -0
  231. package/dist/services/MYXClientService.d.mts.map +1 -0
  232. package/dist/services/MYXClientService.mjs +300 -0
  233. package/dist/services/MYXClientService.mjs.map +1 -0
  234. package/dist/services/MarketDataService.cjs +848 -0
  235. package/dist/services/MarketDataService.cjs.map +1 -0
  236. package/dist/services/MarketDataService.d.cts +291 -0
  237. package/dist/services/MarketDataService.d.cts.map +1 -0
  238. package/dist/services/MarketDataService.d.mts +291 -0
  239. package/dist/services/MarketDataService.d.mts.map +1 -0
  240. package/dist/services/MarketDataService.mjs +844 -0
  241. package/dist/services/MarketDataService.mjs.map +1 -0
  242. package/dist/services/RewardsIntegrationService.cjs +120 -0
  243. package/dist/services/RewardsIntegrationService.cjs.map +1 -0
  244. package/dist/services/RewardsIntegrationService.d.cts +28 -0
  245. package/dist/services/RewardsIntegrationService.d.cts.map +1 -0
  246. package/dist/services/RewardsIntegrationService.d.mts +28 -0
  247. package/dist/services/RewardsIntegrationService.d.mts.map +1 -0
  248. package/dist/services/RewardsIntegrationService.mjs +116 -0
  249. package/dist/services/RewardsIntegrationService.mjs.map +1 -0
  250. package/dist/services/ServiceContext.cjs +3 -0
  251. package/dist/services/ServiceContext.cjs.map +1 -0
  252. package/dist/services/ServiceContext.d.cts +86 -0
  253. package/dist/services/ServiceContext.d.cts.map +1 -0
  254. package/dist/services/ServiceContext.d.mts +86 -0
  255. package/dist/services/ServiceContext.d.mts.map +1 -0
  256. package/dist/services/ServiceContext.mjs +2 -0
  257. package/dist/services/ServiceContext.mjs.map +1 -0
  258. package/dist/services/TradingReadinessCache.cjs +288 -0
  259. package/dist/services/TradingReadinessCache.cjs.map +1 -0
  260. package/dist/services/TradingReadinessCache.d.cts +174 -0
  261. package/dist/services/TradingReadinessCache.d.cts.map +1 -0
  262. package/dist/services/TradingReadinessCache.d.mts +174 -0
  263. package/dist/services/TradingReadinessCache.d.mts.map +1 -0
  264. package/dist/services/TradingReadinessCache.mjs +285 -0
  265. package/dist/services/TradingReadinessCache.mjs.map +1 -0
  266. package/dist/services/TradingService.cjs +1457 -0
  267. package/dist/services/TradingService.cjs.map +1 -0
  268. package/dist/services/TradingService.d.cts +195 -0
  269. package/dist/services/TradingService.d.cts.map +1 -0
  270. package/dist/services/TradingService.d.mts +195 -0
  271. package/dist/services/TradingService.d.mts.map +1 -0
  272. package/dist/services/TradingService.mjs +1453 -0
  273. package/dist/services/TradingService.mjs.map +1 -0
  274. package/dist/types/config.cjs +3 -0
  275. package/dist/types/config.cjs.map +1 -0
  276. package/dist/types/config.d.cts +49 -0
  277. package/dist/types/config.d.cts.map +1 -0
  278. package/dist/types/config.d.mts +49 -0
  279. package/dist/types/config.d.mts.map +1 -0
  280. package/dist/types/config.mjs +2 -0
  281. package/dist/types/config.mjs.map +1 -0
  282. package/dist/types/hyperliquid-types.cjs +3 -0
  283. package/dist/types/hyperliquid-types.cjs.map +1 -0
  284. package/dist/types/hyperliquid-types.d.cts +20 -0
  285. package/dist/types/hyperliquid-types.d.cts.map +1 -0
  286. package/dist/types/hyperliquid-types.d.mts +20 -0
  287. package/dist/types/hyperliquid-types.d.mts.map +1 -0
  288. package/dist/types/hyperliquid-types.mjs +2 -0
  289. package/dist/types/hyperliquid-types.mjs.map +1 -0
  290. package/dist/types/index.cjs +115 -0
  291. package/dist/types/index.cjs.map +1 -0
  292. package/dist/types/index.d.cts +1262 -0
  293. package/dist/types/index.d.cts.map +1 -0
  294. package/dist/types/index.d.mts +1262 -0
  295. package/dist/types/index.d.mts.map +1 -0
  296. package/dist/types/index.mjs +97 -0
  297. package/dist/types/index.mjs.map +1 -0
  298. package/dist/types/messenger.cjs +3 -0
  299. package/dist/types/messenger.cjs.map +1 -0
  300. package/dist/types/messenger.d.cts +27 -0
  301. package/dist/types/messenger.d.cts.map +1 -0
  302. package/dist/types/messenger.d.mts +27 -0
  303. package/dist/types/messenger.d.mts.map +1 -0
  304. package/dist/types/messenger.mjs +2 -0
  305. package/dist/types/messenger.mjs.map +1 -0
  306. package/dist/types/myx-types.cjs +25 -0
  307. package/dist/types/myx-types.cjs.map +1 -0
  308. package/dist/types/myx-types.d.cts +63 -0
  309. package/dist/types/myx-types.d.cts.map +1 -0
  310. package/dist/types/myx-types.d.mts +63 -0
  311. package/dist/types/myx-types.d.mts.map +1 -0
  312. package/dist/types/myx-types.mjs +22 -0
  313. package/dist/types/myx-types.mjs.map +1 -0
  314. package/dist/types/perps-types.cjs +4 -0
  315. package/dist/types/perps-types.cjs.map +1 -0
  316. package/dist/types/perps-types.d.cts +105 -0
  317. package/dist/types/perps-types.d.cts.map +1 -0
  318. package/dist/types/perps-types.d.mts +105 -0
  319. package/dist/types/perps-types.d.mts.map +1 -0
  320. package/dist/types/perps-types.mjs +2 -0
  321. package/dist/types/perps-types.mjs.map +1 -0
  322. package/dist/types/token.cjs +3 -0
  323. package/dist/types/token.cjs.map +1 -0
  324. package/dist/types/token.d.cts +25 -0
  325. package/dist/types/token.d.cts.map +1 -0
  326. package/dist/types/token.d.mts +25 -0
  327. package/dist/types/token.d.mts.map +1 -0
  328. package/dist/types/token.mjs +2 -0
  329. package/dist/types/token.mjs.map +1 -0
  330. package/dist/types/transactionTypes.cjs +28 -0
  331. package/dist/types/transactionTypes.cjs.map +1 -0
  332. package/dist/types/transactionTypes.d.cts +64 -0
  333. package/dist/types/transactionTypes.d.cts.map +1 -0
  334. package/dist/types/transactionTypes.d.mts +64 -0
  335. package/dist/types/transactionTypes.d.mts.map +1 -0
  336. package/dist/types/transactionTypes.mjs +23 -0
  337. package/dist/types/transactionTypes.mjs.map +1 -0
  338. package/dist/utils/accountUtils.cjs +100 -0
  339. package/dist/utils/accountUtils.cjs.map +1 -0
  340. package/dist/utils/accountUtils.d.cts +30 -0
  341. package/dist/utils/accountUtils.d.cts.map +1 -0
  342. package/dist/utils/accountUtils.d.mts +30 -0
  343. package/dist/utils/accountUtils.d.mts.map +1 -0
  344. package/dist/utils/accountUtils.mjs +92 -0
  345. package/dist/utils/accountUtils.mjs.map +1 -0
  346. package/dist/utils/errorUtils.cjs +35 -0
  347. package/dist/utils/errorUtils.cjs.map +1 -0
  348. package/dist/utils/errorUtils.d.cts +15 -0
  349. package/dist/utils/errorUtils.d.cts.map +1 -0
  350. package/dist/utils/errorUtils.d.mts +15 -0
  351. package/dist/utils/errorUtils.d.mts.map +1 -0
  352. package/dist/utils/errorUtils.mjs +31 -0
  353. package/dist/utils/errorUtils.mjs.map +1 -0
  354. package/dist/utils/hyperLiquidAdapter.cjs +331 -0
  355. package/dist/utils/hyperLiquidAdapter.cjs.map +1 -0
  356. package/dist/utils/hyperLiquidAdapter.d.cts +42 -0
  357. package/dist/utils/hyperLiquidAdapter.d.cts.map +1 -0
  358. package/dist/utils/hyperLiquidAdapter.d.mts +42 -0
  359. package/dist/utils/hyperLiquidAdapter.d.mts.map +1 -0
  360. package/dist/utils/hyperLiquidAdapter.mjs +316 -0
  361. package/dist/utils/hyperLiquidAdapter.mjs.map +1 -0
  362. package/dist/utils/hyperLiquidOrderBookProcessor.cjs +83 -0
  363. package/dist/utils/hyperLiquidOrderBookProcessor.cjs.map +1 -0
  364. package/dist/utils/hyperLiquidOrderBookProcessor.d.cts +55 -0
  365. package/dist/utils/hyperLiquidOrderBookProcessor.d.cts.map +1 -0
  366. package/dist/utils/hyperLiquidOrderBookProcessor.d.mts +55 -0
  367. package/dist/utils/hyperLiquidOrderBookProcessor.d.mts.map +1 -0
  368. package/dist/utils/hyperLiquidOrderBookProcessor.mjs +78 -0
  369. package/dist/utils/hyperLiquidOrderBookProcessor.mjs.map +1 -0
  370. package/dist/utils/hyperLiquidValidation.cjs +426 -0
  371. package/dist/utils/hyperLiquidValidation.cjs.map +1 -0
  372. package/dist/utils/hyperLiquidValidation.d.cts +143 -0
  373. package/dist/utils/hyperLiquidValidation.d.cts.map +1 -0
  374. package/dist/utils/hyperLiquidValidation.d.mts +143 -0
  375. package/dist/utils/hyperLiquidValidation.d.mts.map +1 -0
  376. package/dist/utils/hyperLiquidValidation.mjs +413 -0
  377. package/dist/utils/hyperLiquidValidation.mjs.map +1 -0
  378. package/dist/utils/idUtils.cjs +18 -0
  379. package/dist/utils/idUtils.cjs.map +1 -0
  380. package/dist/utils/idUtils.d.cts +6 -0
  381. package/dist/utils/idUtils.d.cts.map +1 -0
  382. package/dist/utils/idUtils.d.mts +6 -0
  383. package/dist/utils/idUtils.d.mts.map +1 -0
  384. package/dist/utils/idUtils.mjs +10 -0
  385. package/dist/utils/idUtils.mjs.map +1 -0
  386. package/dist/utils/index.cjs +59 -0
  387. package/dist/utils/index.cjs.map +1 -0
  388. package/dist/utils/index.d.cts +25 -0
  389. package/dist/utils/index.d.cts.map +1 -0
  390. package/dist/utils/index.d.mts +25 -0
  391. package/dist/utils/index.d.mts.map +1 -0
  392. package/dist/utils/index.mjs +30 -0
  393. package/dist/utils/index.mjs.map +1 -0
  394. package/dist/utils/marketDataTransform.cjs +211 -0
  395. package/dist/utils/marketDataTransform.cjs.map +1 -0
  396. package/dist/utils/marketDataTransform.d.cts +40 -0
  397. package/dist/utils/marketDataTransform.d.cts.map +1 -0
  398. package/dist/utils/marketDataTransform.d.mts +40 -0
  399. package/dist/utils/marketDataTransform.d.mts.map +1 -0
  400. package/dist/utils/marketDataTransform.mjs +205 -0
  401. package/dist/utils/marketDataTransform.mjs.map +1 -0
  402. package/dist/utils/marketUtils.cjs +151 -0
  403. package/dist/utils/marketUtils.cjs.map +1 -0
  404. package/dist/utils/marketUtils.d.cts +30 -0
  405. package/dist/utils/marketUtils.d.cts.map +1 -0
  406. package/dist/utils/marketUtils.d.mts +30 -0
  407. package/dist/utils/marketUtils.d.mts.map +1 -0
  408. package/dist/utils/marketUtils.mjs +138 -0
  409. package/dist/utils/marketUtils.mjs.map +1 -0
  410. package/dist/utils/myxAdapter.cjs +224 -0
  411. package/dist/utils/myxAdapter.cjs.map +1 -0
  412. package/dist/utils/myxAdapter.d.cts +81 -0
  413. package/dist/utils/myxAdapter.d.cts.map +1 -0
  414. package/dist/utils/myxAdapter.d.mts +81 -0
  415. package/dist/utils/myxAdapter.d.mts.map +1 -0
  416. package/dist/utils/myxAdapter.mjs +213 -0
  417. package/dist/utils/myxAdapter.mjs.map +1 -0
  418. package/dist/utils/orderCalculations.cjs +283 -0
  419. package/dist/utils/orderCalculations.cjs.map +1 -0
  420. package/dist/utils/orderCalculations.d.cts +107 -0
  421. package/dist/utils/orderCalculations.d.cts.map +1 -0
  422. package/dist/utils/orderCalculations.d.mts +107 -0
  423. package/dist/utils/orderCalculations.d.mts.map +1 -0
  424. package/dist/utils/orderCalculations.mjs +274 -0
  425. package/dist/utils/orderCalculations.mjs.map +1 -0
  426. package/dist/utils/rewardsUtils.cjs +98 -0
  427. package/dist/utils/rewardsUtils.cjs.map +1 -0
  428. package/dist/utils/rewardsUtils.d.cts +33 -0
  429. package/dist/utils/rewardsUtils.d.cts.map +1 -0
  430. package/dist/utils/rewardsUtils.d.mts +33 -0
  431. package/dist/utils/rewardsUtils.d.mts.map +1 -0
  432. package/dist/utils/rewardsUtils.mjs +92 -0
  433. package/dist/utils/rewardsUtils.mjs.map +1 -0
  434. package/dist/utils/significantFigures.cjs +88 -0
  435. package/dist/utils/significantFigures.cjs.map +1 -0
  436. package/dist/utils/significantFigures.d.cts +25 -0
  437. package/dist/utils/significantFigures.d.cts.map +1 -0
  438. package/dist/utils/significantFigures.d.mts +25 -0
  439. package/dist/utils/significantFigures.d.mts.map +1 -0
  440. package/dist/utils/significantFigures.mjs +82 -0
  441. package/dist/utils/significantFigures.mjs.map +1 -0
  442. package/dist/utils/sortMarkets.cjs +93 -0
  443. package/dist/utils/sortMarkets.cjs.map +1 -0
  444. package/dist/utils/sortMarkets.d.cts +27 -0
  445. package/dist/utils/sortMarkets.d.cts.map +1 -0
  446. package/dist/utils/sortMarkets.d.mts +27 -0
  447. package/dist/utils/sortMarkets.d.mts.map +1 -0
  448. package/dist/utils/sortMarkets.mjs +88 -0
  449. package/dist/utils/sortMarkets.mjs.map +1 -0
  450. package/dist/utils/standaloneInfoClient.cjs +70 -0
  451. package/dist/utils/standaloneInfoClient.cjs.map +1 -0
  452. package/dist/utils/standaloneInfoClient.d.cts +37 -0
  453. package/dist/utils/standaloneInfoClient.d.cts.map +1 -0
  454. package/dist/utils/standaloneInfoClient.d.mts +37 -0
  455. package/dist/utils/standaloneInfoClient.d.mts.map +1 -0
  456. package/dist/utils/standaloneInfoClient.mjs +64 -0
  457. package/dist/utils/standaloneInfoClient.mjs.map +1 -0
  458. package/dist/utils/stringParseUtils.cjs +18 -0
  459. package/dist/utils/stringParseUtils.cjs.map +1 -0
  460. package/dist/utils/stringParseUtils.d.cts +3 -0
  461. package/dist/utils/stringParseUtils.d.cts.map +1 -0
  462. package/dist/utils/stringParseUtils.d.mts +3 -0
  463. package/dist/utils/stringParseUtils.d.mts.map +1 -0
  464. package/dist/utils/stringParseUtils.mjs +13 -0
  465. package/dist/utils/stringParseUtils.mjs.map +1 -0
  466. package/dist/utils/transferData.cjs +33 -0
  467. package/dist/utils/transferData.cjs.map +1 -0
  468. package/dist/utils/transferData.d.cts +9 -0
  469. package/dist/utils/transferData.d.cts.map +1 -0
  470. package/dist/utils/transferData.d.mts +9 -0
  471. package/dist/utils/transferData.d.mts.map +1 -0
  472. package/dist/utils/transferData.mjs +29 -0
  473. package/dist/utils/transferData.mjs.map +1 -0
  474. package/dist/utils/wait.cjs +6 -0
  475. package/dist/utils/wait.cjs.map +1 -0
  476. package/dist/utils/wait.d.cts +2 -0
  477. package/dist/utils/wait.d.cts.map +1 -0
  478. package/dist/utils/wait.d.mts +2 -0
  479. package/dist/utils/wait.d.mts.map +1 -0
  480. package/dist/utils/wait.mjs +2 -0
  481. package/dist/utils/wait.mjs.map +1 -0
  482. package/package.json +16 -2
@@ -1,88 +1,3100 @@
1
1
  "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_blockedRegionListVersion, _PerpsController_hip3Enabled, _PerpsController_hip3AllowlistMarkets, _PerpsController_hip3BlocklistMarkets, _PerpsController_hip3ConfigSource, _PerpsController_isMYXProviderEnabled, _PerpsController_standaloneProvider, _PerpsController_standaloneProviderIsTestnet, _PerpsController_standaloneProviderHip3Version, _PerpsController_options, _PerpsController_tradingService, _PerpsController_marketDataService, _PerpsController_accountService, _PerpsController_eligibilityService, _PerpsController_dataLakeService, _PerpsController_depositService, _PerpsController_featureFlagConfigurationService, _PerpsController_rewardsIntegrationService, _PerpsController_logError, _PerpsController_debugLog, _PerpsController_getOrCreateStandaloneProvider, _PerpsController_cleanupStandaloneProvider, _PerpsController_getMetrics, _PerpsController_findNetworkClientIdForChain, _PerpsController_submitTransaction, _PerpsController_migrateRequestsIfNeeded, _PerpsController_withStreamPause, _PerpsController_performInitialization, _PerpsController_getErrorContext, _PerpsController_getControllerState, _PerpsController_createServiceContext, _PerpsController_ensureTradingServiceDeps, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_isPreloading, _PerpsController_isPreloadingUserData, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload;
2
14
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PerpsController = exports.getDefaultPerpsControllerState = exports.controllerName = void 0;
15
+ exports.PerpsController = exports.getDefaultPerpsControllerState = exports.InitializationState = exports.PERPS_ERROR_CODES = void 0;
4
16
  const base_controller_1 = require("@metamask/base-controller");
17
+ const controller_utils_1 = require("@metamask/controller-utils");
18
+ const uuid_1 = require("uuid");
19
+ const chartConfig_1 = require("./constants/chartConfig.cjs");
20
+ const eventNames_1 = require("./constants/eventNames.cjs");
21
+ const hyperLiquidConfig_1 = require("./constants/hyperLiquidConfig.cjs");
22
+ const performanceMetrics_1 = require("./constants/performanceMetrics.cjs");
23
+ const perpsConfig_1 = require("./constants/perpsConfig.cjs");
24
+ const perpsErrorCodes_1 = require("./perpsErrorCodes.cjs");
25
+ const AggregatedPerpsProvider_1 = require("./providers/AggregatedPerpsProvider.cjs");
26
+ const HyperLiquidProvider_1 = require("./providers/HyperLiquidProvider.cjs");
27
+ const MYXProvider_1 = require("./providers/MYXProvider.cjs");
28
+ const AccountService_1 = require("./services/AccountService.cjs");
29
+ const DataLakeService_1 = require("./services/DataLakeService.cjs");
30
+ const DepositService_1 = require("./services/DepositService.cjs");
31
+ const EligibilityService_1 = require("./services/EligibilityService.cjs");
32
+ const FeatureFlagConfigurationService_1 = require("./services/FeatureFlagConfigurationService.cjs");
33
+ const MarketDataService_1 = require("./services/MarketDataService.cjs");
34
+ const RewardsIntegrationService_1 = require("./services/RewardsIntegrationService.cjs");
35
+ const TradingService_1 = require("./services/TradingService.cjs");
36
+ // PerpsStreamChannelKey removed: using string for channel keys (PerpsStreamManager.pauseChannel takes string)
37
+ const types_1 = require("./types/index.cjs");
38
+ const accountUtils_1 = require("./utils/accountUtils.cjs");
39
+ const errorUtils_1 = require("./utils/errorUtils.cjs");
40
+ const wait_1 = require("./utils/wait.cjs");
41
+ // Re-export error codes from separate file to avoid circular dependencies
42
+ var perpsErrorCodes_2 = require("./perpsErrorCodes.cjs");
43
+ Object.defineProperty(exports, "PERPS_ERROR_CODES", { enumerable: true, get: function () { return perpsErrorCodes_2.PERPS_ERROR_CODES; } });
5
44
  /**
6
- * The name of the {@link PerpsController}, used to namespace the
7
- * controller's actions and events and to namespace the controller's state data
8
- * when composed with other controllers.
45
+ * Initialization state enum for state machine tracking
9
46
  */
10
- exports.controllerName = 'PerpsController';
47
+ var InitializationState;
48
+ (function (InitializationState) {
49
+ InitializationState["Uninitialized"] = "uninitialized";
50
+ InitializationState["Initializing"] = "initializing";
51
+ InitializationState["Initialized"] = "initialized";
52
+ InitializationState["Failed"] = "failed";
53
+ })(InitializationState || (exports.InitializationState = InitializationState = {}));
11
54
  /**
12
- * The metadata for each property in {@link PerpsControllerState}.
55
+ * Get default PerpsController state
56
+ *
57
+ * To change the active provider, modify the `activeProvider` value below:
58
+ * - 'hyperliquid': HyperLiquid provider (default, production)
59
+ * - 'aggregated': Multi-provider aggregation mode
60
+ * - 'myx': MYX provider (future implementation)
61
+ *
62
+ * @returns The default perps controller state.
63
+ */
64
+ const getDefaultPerpsControllerState = () => ({
65
+ activeProvider: 'hyperliquid',
66
+ isTestnet: false, // Default to mainnet
67
+ initializationState: InitializationState.Uninitialized,
68
+ initializationError: null,
69
+ initializationAttempts: 0,
70
+ accountState: null,
71
+ perpsBalances: {},
72
+ depositInProgress: false,
73
+ lastDepositResult: null,
74
+ withdrawInProgress: false,
75
+ lastDepositTransactionId: null,
76
+ lastWithdrawResult: null,
77
+ withdrawalRequests: [],
78
+ withdrawalProgress: {
79
+ progress: 0,
80
+ lastUpdated: 0,
81
+ activeWithdrawalId: null,
82
+ },
83
+ depositRequests: [],
84
+ lastError: null,
85
+ lastUpdateTimestamp: 0,
86
+ isEligible: false,
87
+ isFirstTimeUser: {
88
+ testnet: true,
89
+ mainnet: true,
90
+ },
91
+ hasPlacedFirstOrder: {
92
+ testnet: false,
93
+ mainnet: false,
94
+ },
95
+ watchlistMarkets: {
96
+ testnet: [],
97
+ mainnet: [],
98
+ },
99
+ tradeConfigurations: {
100
+ testnet: {},
101
+ mainnet: {},
102
+ },
103
+ marketFilterPreferences: {
104
+ optionId: perpsConfig_1.MARKET_SORTING_CONFIG.DefaultSortOptionId,
105
+ direction: perpsConfig_1.MARKET_SORTING_CONFIG.DefaultDirection,
106
+ },
107
+ hip3ConfigVersion: 0,
108
+ selectedPaymentToken: null,
109
+ cachedMarketData: null,
110
+ cachedMarketDataTimestamp: 0,
111
+ cachedPositions: null,
112
+ cachedOrders: null,
113
+ cachedAccountState: null,
114
+ cachedUserDataTimestamp: 0,
115
+ cachedUserDataAddress: null,
116
+ });
117
+ exports.getDefaultPerpsControllerState = getDefaultPerpsControllerState;
118
+ /**
119
+ * State metadata for the PerpsController
13
120
  */
14
- const perpsControllerMetadata = {};
121
+ const metadata = {
122
+ accountState: {
123
+ includeInStateLogs: true,
124
+ persist: true,
125
+ includeInDebugSnapshot: false,
126
+ usedInUi: true,
127
+ },
128
+ perpsBalances: {
129
+ includeInStateLogs: true,
130
+ persist: true,
131
+ includeInDebugSnapshot: false,
132
+ usedInUi: true,
133
+ },
134
+ isTestnet: {
135
+ includeInStateLogs: true,
136
+ persist: true,
137
+ includeInDebugSnapshot: false,
138
+ usedInUi: true,
139
+ },
140
+ activeProvider: {
141
+ includeInStateLogs: true,
142
+ persist: true,
143
+ includeInDebugSnapshot: false,
144
+ usedInUi: true,
145
+ },
146
+ initializationState: {
147
+ includeInStateLogs: true,
148
+ persist: false,
149
+ includeInDebugSnapshot: false,
150
+ usedInUi: true,
151
+ },
152
+ initializationError: {
153
+ includeInStateLogs: true,
154
+ persist: false,
155
+ includeInDebugSnapshot: false,
156
+ usedInUi: true,
157
+ },
158
+ initializationAttempts: {
159
+ includeInStateLogs: true,
160
+ persist: false,
161
+ includeInDebugSnapshot: false,
162
+ usedInUi: false,
163
+ },
164
+ depositInProgress: {
165
+ includeInStateLogs: true,
166
+ persist: false,
167
+ includeInDebugSnapshot: false,
168
+ usedInUi: true,
169
+ },
170
+ lastDepositTransactionId: {
171
+ includeInStateLogs: true,
172
+ persist: false,
173
+ includeInDebugSnapshot: false,
174
+ usedInUi: true,
175
+ },
176
+ lastDepositResult: {
177
+ includeInStateLogs: true,
178
+ persist: false,
179
+ includeInDebugSnapshot: false,
180
+ usedInUi: true,
181
+ },
182
+ withdrawInProgress: {
183
+ includeInStateLogs: true,
184
+ persist: false,
185
+ includeInDebugSnapshot: false,
186
+ usedInUi: true,
187
+ },
188
+ lastWithdrawResult: {
189
+ includeInStateLogs: true,
190
+ persist: false,
191
+ includeInDebugSnapshot: false,
192
+ usedInUi: true,
193
+ },
194
+ withdrawalRequests: {
195
+ includeInStateLogs: true,
196
+ persist: true,
197
+ includeInDebugSnapshot: false,
198
+ usedInUi: true,
199
+ },
200
+ withdrawalProgress: {
201
+ includeInStateLogs: true,
202
+ persist: true,
203
+ includeInDebugSnapshot: false,
204
+ usedInUi: true,
205
+ },
206
+ depositRequests: {
207
+ includeInStateLogs: true,
208
+ persist: true,
209
+ includeInDebugSnapshot: false,
210
+ usedInUi: true,
211
+ },
212
+ lastError: {
213
+ includeInStateLogs: false,
214
+ persist: false,
215
+ includeInDebugSnapshot: false,
216
+ usedInUi: false,
217
+ },
218
+ lastUpdateTimestamp: {
219
+ includeInStateLogs: true,
220
+ persist: false,
221
+ includeInDebugSnapshot: false,
222
+ usedInUi: false,
223
+ },
224
+ isEligible: {
225
+ includeInStateLogs: true,
226
+ persist: false,
227
+ includeInDebugSnapshot: false,
228
+ usedInUi: true,
229
+ },
230
+ isFirstTimeUser: {
231
+ includeInStateLogs: true,
232
+ persist: true,
233
+ includeInDebugSnapshot: false,
234
+ usedInUi: true,
235
+ },
236
+ hasPlacedFirstOrder: {
237
+ includeInStateLogs: true,
238
+ persist: true,
239
+ includeInDebugSnapshot: false,
240
+ usedInUi: true,
241
+ },
242
+ watchlistMarkets: {
243
+ includeInStateLogs: true,
244
+ persist: true,
245
+ includeInDebugSnapshot: false,
246
+ usedInUi: true,
247
+ },
248
+ tradeConfigurations: {
249
+ includeInStateLogs: true,
250
+ persist: true,
251
+ includeInDebugSnapshot: false,
252
+ usedInUi: true,
253
+ },
254
+ marketFilterPreferences: {
255
+ includeInStateLogs: true,
256
+ persist: true,
257
+ includeInDebugSnapshot: false,
258
+ usedInUi: true,
259
+ },
260
+ hip3ConfigVersion: {
261
+ includeInStateLogs: true,
262
+ persist: true,
263
+ includeInDebugSnapshot: false,
264
+ usedInUi: false,
265
+ },
266
+ selectedPaymentToken: {
267
+ includeInStateLogs: false,
268
+ persist: false,
269
+ includeInDebugSnapshot: false,
270
+ usedInUi: true,
271
+ },
272
+ cachedMarketData: {
273
+ includeInStateLogs: false,
274
+ persist: false,
275
+ includeInDebugSnapshot: false,
276
+ usedInUi: true,
277
+ },
278
+ cachedMarketDataTimestamp: {
279
+ includeInStateLogs: false,
280
+ persist: false,
281
+ includeInDebugSnapshot: false,
282
+ usedInUi: false,
283
+ },
284
+ cachedPositions: {
285
+ includeInStateLogs: false,
286
+ persist: false,
287
+ includeInDebugSnapshot: false,
288
+ usedInUi: true,
289
+ },
290
+ cachedOrders: {
291
+ includeInStateLogs: false,
292
+ persist: false,
293
+ includeInDebugSnapshot: false,
294
+ usedInUi: true,
295
+ },
296
+ cachedAccountState: {
297
+ includeInStateLogs: false,
298
+ persist: false,
299
+ includeInDebugSnapshot: false,
300
+ usedInUi: true,
301
+ },
302
+ cachedUserDataTimestamp: {
303
+ includeInStateLogs: false,
304
+ persist: false,
305
+ includeInDebugSnapshot: false,
306
+ usedInUi: false,
307
+ },
308
+ cachedUserDataAddress: {
309
+ includeInStateLogs: false,
310
+ persist: false,
311
+ includeInDebugSnapshot: false,
312
+ usedInUi: false,
313
+ },
314
+ };
315
+ const MESSENGER_EXPOSED_METHODS = [
316
+ 'placeOrder',
317
+ 'editOrder',
318
+ 'cancelOrder',
319
+ 'cancelOrders',
320
+ 'closePosition',
321
+ 'closePositions',
322
+ 'withdraw',
323
+ 'getPositions',
324
+ 'getOrderFills',
325
+ 'getOrders',
326
+ 'getOpenOrders',
327
+ 'getFunding',
328
+ 'getAccountState',
329
+ 'getMarkets',
330
+ 'refreshEligibility',
331
+ 'toggleTestnet',
332
+ 'disconnect',
333
+ 'calculateFees',
334
+ 'markTutorialCompleted',
335
+ 'markFirstOrderCompleted',
336
+ 'getHistoricalPortfolio',
337
+ 'resetFirstTimeUserState',
338
+ 'clearPendingTransactionRequests',
339
+ 'saveTradeConfiguration',
340
+ 'getTradeConfiguration',
341
+ 'saveMarketFilterPreferences',
342
+ 'getMarketFilterPreferences',
343
+ 'savePendingTradeConfiguration',
344
+ 'getPendingTradeConfiguration',
345
+ 'clearPendingTradeConfiguration',
346
+ 'getOrderBookGrouping',
347
+ 'saveOrderBookGrouping',
348
+ 'setSelectedPaymentToken',
349
+ 'resetSelectedPaymentToken',
350
+ ];
15
351
  /**
16
- * Constructs the default {@link PerpsController} state. This allows
17
- * consumers to provide a partial state object when initializing the controller
18
- * and also helps in constructing complete state objects for this controller in
19
- * tests.
352
+ * PerpsController - Protocol-agnostic perpetuals trading controller
20
353
  *
21
- * @returns The default {@link PerpsController} state.
354
+ * Provides a unified interface for perpetual futures trading across multiple protocols.
355
+ * Features dual data flow architecture:
356
+ * - Trading actions use Redux for persistence and optimistic updates
357
+ * - Live data uses direct callbacks for maximum performance
22
358
  */
23
- function getDefaultPerpsControllerState() {
24
- return {};
359
+ class PerpsController extends base_controller_1.BaseController {
360
+ constructor({ messenger, state = {}, clientConfig = {}, infrastructure, }) {
361
+ super({
362
+ name: 'PerpsController',
363
+ metadata,
364
+ messenger,
365
+ state: { ...(0, exports.getDefaultPerpsControllerState)(), ...state },
366
+ });
367
+ _PerpsController_instances.add(this);
368
+ this.isInitialized = false;
369
+ _PerpsController_initializationPromise.set(this, null);
370
+ _PerpsController_isReinitializing.set(this, false);
371
+ this.blockedRegionList = {
372
+ list: [],
373
+ source: 'fallback',
374
+ };
375
+ /**
376
+ * Version counter for blocked region list.
377
+ * Used to prevent race conditions where stale eligibility checks
378
+ * (started with fallback config) overwrite results from newer checks
379
+ * (started with remote config).
380
+ */
381
+ _PerpsController_blockedRegionListVersion.set(this, 0);
382
+ // Store HIP-3 configuration (mutable for runtime updates from remote flags)
383
+ _PerpsController_hip3Enabled.set(this, void 0);
384
+ _PerpsController_hip3AllowlistMarkets.set(this, void 0);
385
+ _PerpsController_hip3BlocklistMarkets.set(this, void 0);
386
+ _PerpsController_hip3ConfigSource.set(this, 'fallback');
387
+ /**
388
+ * Active provider instance for routing operations.
389
+ * When activeProvider is 'hyperliquid' or 'myx': points to specific provider directly
390
+ * When activeProvider is 'aggregated': points to AggregatedPerpsProvider wrapper
391
+ */
392
+ this.activeProviderInstance = null;
393
+ /**
394
+ * Cached standalone provider for pre-initialization discovery queries.
395
+ * Avoids creating a new HyperLiquidProvider (and potentially leaking WebSocket
396
+ * connections) on every standalone call from the preload cycle.
397
+ */
398
+ _PerpsController_standaloneProvider.set(this, null);
399
+ _PerpsController_standaloneProviderIsTestnet.set(this, null);
400
+ _PerpsController_standaloneProviderHip3Version.set(this, null);
401
+ // Store options for dependency injection (allows core package to inject platform-specific services)
402
+ _PerpsController_options.set(this, void 0);
403
+ // Service instances (instantiated with platform dependencies)
404
+ _PerpsController_tradingService.set(this, void 0);
405
+ _PerpsController_marketDataService.set(this, void 0);
406
+ _PerpsController_accountService.set(this, void 0);
407
+ _PerpsController_eligibilityService.set(this, void 0);
408
+ _PerpsController_dataLakeService.set(this, void 0);
409
+ _PerpsController_depositService.set(this, void 0);
410
+ _PerpsController_featureFlagConfigurationService.set(this, void 0);
411
+ _PerpsController_rewardsIntegrationService.set(this, void 0);
412
+ _PerpsController_preloadTimer.set(this, null);
413
+ _PerpsController_isPreloading.set(this, false);
414
+ _PerpsController_isPreloadingUserData.set(this, false);
415
+ _PerpsController_preloadStateUnsubscribe.set(this, null);
416
+ _PerpsController_accountChangeUnsubscribe.set(this, null);
417
+ _PerpsController_previousIsTestnet.set(this, null);
418
+ _PerpsController_previousHip3ConfigVersion.set(this, null);
419
+ // Store options for dependency injection
420
+ __classPrivateFieldSet(this, _PerpsController_options, {
421
+ messenger,
422
+ state,
423
+ clientConfig,
424
+ infrastructure,
425
+ }, "f");
426
+ // Instantiate services with platform dependencies
427
+ // Services that need cross-controller access receive the messenger
428
+ __classPrivateFieldSet(this, _PerpsController_tradingService, new TradingService_1.TradingService(infrastructure), "f");
429
+ __classPrivateFieldSet(this, _PerpsController_marketDataService, new MarketDataService_1.MarketDataService(infrastructure), "f");
430
+ __classPrivateFieldSet(this, _PerpsController_accountService, new AccountService_1.AccountService(infrastructure, messenger), "f");
431
+ __classPrivateFieldSet(this, _PerpsController_eligibilityService, new EligibilityService_1.EligibilityService(infrastructure), "f");
432
+ __classPrivateFieldSet(this, _PerpsController_dataLakeService, new DataLakeService_1.DataLakeService(infrastructure, messenger), "f");
433
+ __classPrivateFieldSet(this, _PerpsController_depositService, new DepositService_1.DepositService(infrastructure, messenger), "f");
434
+ __classPrivateFieldSet(this, _PerpsController_featureFlagConfigurationService, new FeatureFlagConfigurationService_1.FeatureFlagConfigurationService(infrastructure), "f");
435
+ __classPrivateFieldSet(this, _PerpsController_rewardsIntegrationService, new RewardsIntegrationService_1.RewardsIntegrationService(infrastructure, messenger), "f");
436
+ // Set HIP-3 fallback configuration from client (will be updated if remote flags available)
437
+ __classPrivateFieldSet(this, _PerpsController_hip3Enabled, clientConfig.fallbackHip3Enabled ?? false, "f");
438
+ __classPrivateFieldSet(this, _PerpsController_hip3AllowlistMarkets, [
439
+ ...(clientConfig.fallbackHip3AllowlistMarkets ?? []),
440
+ ], "f");
441
+ __classPrivateFieldSet(this, _PerpsController_hip3BlocklistMarkets, [
442
+ ...(clientConfig.fallbackHip3BlocklistMarkets ?? []),
443
+ ], "f");
444
+ // Immediately set the fallback region list since RemoteFeatureFlagController is empty by default and takes a moment to populate.
445
+ this.setBlockedRegionList(clientConfig.fallbackBlockedRegions ?? [], 'fallback');
446
+ /**
447
+ * Immediately read current state to catch any flags already loaded
448
+ * This is necessary to avoid race conditions where the RemoteFeatureFlagController fetches flags
449
+ * before the PerpsController initializes its RemoteFeatureFlagController subscription.
450
+ *
451
+ * We still subscribe in case the RemoteFeatureFlagController is not yet populated and updates later.
452
+ */
453
+ try {
454
+ const currentRemoteFeatureFlagState = this.messenger.call('RemoteFeatureFlagController:getState');
455
+ this.refreshEligibilityOnFeatureFlagChange(currentRemoteFeatureFlagState);
456
+ }
457
+ catch (error) {
458
+ // If we can't read the remote feature flags at construction time, we'll rely on:
459
+ // 1. The fallback blocked regions already set above
460
+ // 2. The subscription to catch updates when RemoteFeatureFlagController is ready
461
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.constructor'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'constructor', {
462
+ operation: 'readRemoteFeatureFlags',
463
+ }));
464
+ }
465
+ // Subscribe for the full controller lifetime — intentionally not stored;
466
+ // geo-blocking and HIP-3 flag propagation must remain active across
467
+ // disconnect → reconnect cycles and must never be torn down.
468
+ this.messenger.subscribe('RemoteFeatureFlagController:stateChange', this.refreshEligibilityOnFeatureFlagChange.bind(this));
469
+ this.providers = new Map();
470
+ // Migrate old persisted data without accountAddress
471
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_migrateRequestsIfNeeded).call(this);
472
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
473
+ }
474
+ /**
475
+ * Test-observable accessor for whether a standalone provider is cached.
476
+ *
477
+ * @returns True if a standalone provider instance exists.
478
+ */
479
+ hasStandaloneProvider() {
480
+ return __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f") !== null;
481
+ }
482
+ setBlockedRegionList(list, source) {
483
+ __classPrivateFieldGet(this, _PerpsController_featureFlagConfigurationService, "f").setBlockedRegions({
484
+ list,
485
+ source,
486
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'setBlockedRegionList', {
487
+ getBlockedRegionList: () => this.blockedRegionList,
488
+ setBlockedRegionList: (newList, newSource) => {
489
+ this.blockedRegionList = { list: newList, source: newSource };
490
+ __classPrivateFieldSet(this, _PerpsController_blockedRegionListVersion, __classPrivateFieldGet(this, _PerpsController_blockedRegionListVersion, "f") + 1, "f");
491
+ },
492
+ refreshEligibility: () => this.refreshEligibility(),
493
+ }),
494
+ });
495
+ }
496
+ /**
497
+ * Respond to RemoteFeatureFlagController state changes
498
+ * Refreshes user eligibility based on geo-blocked regions defined in remote feature flag.
499
+ * Uses fallback configuration when remote feature flag is undefined.
500
+ * Note: Initial eligibility is set in the constructor if fallback regions are provided.
501
+ *
502
+ * @param remoteFeatureFlagControllerState - State from RemoteFeatureFlagController.
503
+ */
504
+ refreshEligibilityOnFeatureFlagChange(remoteFeatureFlagControllerState) {
505
+ __classPrivateFieldGet(this, _PerpsController_featureFlagConfigurationService, "f").refreshEligibility({
506
+ remoteFeatureFlagControllerState,
507
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'refreshEligibilityOnFeatureFlagChange', {
508
+ getBlockedRegionList: () => this.blockedRegionList,
509
+ setBlockedRegionList: (list, source) => {
510
+ this.blockedRegionList = { list, source };
511
+ __classPrivateFieldSet(this, _PerpsController_blockedRegionListVersion, __classPrivateFieldGet(this, _PerpsController_blockedRegionListVersion, "f") + 1, "f");
512
+ },
513
+ refreshEligibility: () => this.refreshEligibility(),
514
+ getHip3Config: () => ({
515
+ enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
516
+ allowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
517
+ blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
518
+ source: __classPrivateFieldGet(this, _PerpsController_hip3ConfigSource, "f"),
519
+ }),
520
+ setHip3Config: (config) => {
521
+ if (config.enabled !== undefined) {
522
+ __classPrivateFieldSet(this, _PerpsController_hip3Enabled, config.enabled, "f");
523
+ }
524
+ if (config.allowlistMarkets !== undefined) {
525
+ __classPrivateFieldSet(this, _PerpsController_hip3AllowlistMarkets, [...config.allowlistMarkets], "f");
526
+ }
527
+ if (config.blocklistMarkets !== undefined) {
528
+ __classPrivateFieldSet(this, _PerpsController_hip3BlocklistMarkets, [...config.blocklistMarkets], "f");
529
+ }
530
+ if (config.source !== undefined) {
531
+ __classPrivateFieldSet(this, _PerpsController_hip3ConfigSource, config.source, "f");
532
+ }
533
+ },
534
+ incrementHip3ConfigVersion: () => {
535
+ const newVersion = (this.state.hip3ConfigVersion || 0) + 1;
536
+ this.update((state) => {
537
+ state.hip3ConfigVersion = newVersion;
538
+ });
539
+ return newVersion;
540
+ },
541
+ }),
542
+ });
543
+ }
544
+ /**
545
+ * Initialize the PerpsController providers
546
+ * Must be called before using any other methods
547
+ * Prevents double initialization with promise caching
548
+ *
549
+ * @returns A promise that resolves when the operation completes.
550
+ */
551
+ async init() {
552
+ if (this.isInitialized) {
553
+ return undefined;
554
+ }
555
+ if (__classPrivateFieldGet(this, _PerpsController_initializationPromise, "f")) {
556
+ return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
557
+ }
558
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performInitialization).call(this), "f");
559
+ return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
560
+ }
561
+ /**
562
+ * Get the currently active provider.
563
+ * In aggregated mode, returns AggregatedPerpsProvider which routes to underlying providers.
564
+ * In single provider mode, returns HyperLiquidProvider directly.
565
+ *
566
+ * @returns The active provider (aggregated wrapper or direct provider based on mode)
567
+ * @throws Error if provider is not initialized or reinitializing
568
+ */
569
+ getActiveProvider() {
570
+ // Check if we're in the middle of reinitializing
571
+ if (this.isCurrentlyReinitializing()) {
572
+ this.update((state) => {
573
+ state.lastError = perpsErrorCodes_1.PERPS_ERROR_CODES.CLIENT_REINITIALIZING;
574
+ state.lastUpdateTimestamp = Date.now();
575
+ });
576
+ throw new Error(perpsErrorCodes_1.PERPS_ERROR_CODES.CLIENT_REINITIALIZING);
577
+ }
578
+ // Check if not initialized
579
+ if (this.state.initializationState !== InitializationState.Initialized ||
580
+ !this.isInitialized) {
581
+ const errorMessage = this.state.initializationState === InitializationState.Failed
582
+ ? `${perpsErrorCodes_1.PERPS_ERROR_CODES.CLIENT_NOT_INITIALIZED}: ${this.state.initializationError ?? 'Initialization failed'}`
583
+ : perpsErrorCodes_1.PERPS_ERROR_CODES.CLIENT_NOT_INITIALIZED;
584
+ this.update((state) => {
585
+ state.lastError = errorMessage;
586
+ state.lastUpdateTimestamp = Date.now();
587
+ });
588
+ throw new Error(errorMessage);
589
+ }
590
+ // Return the active provider instance (set during initialization based on providerMode)
591
+ if (!this.activeProviderInstance) {
592
+ this.update((state) => {
593
+ state.lastError = perpsErrorCodes_1.PERPS_ERROR_CODES.PROVIDER_NOT_AVAILABLE;
594
+ state.lastUpdateTimestamp = Date.now();
595
+ });
596
+ throw new Error(perpsErrorCodes_1.PERPS_ERROR_CODES.PROVIDER_NOT_AVAILABLE);
597
+ }
598
+ return this.activeProviderInstance;
599
+ }
600
+ /**
601
+ * Get the currently active provider, returning null if not available
602
+ * Use this method when the caller can gracefully handle a missing provider
603
+ * (e.g., UI components during initialization or reconnection)
604
+ *
605
+ * @returns The active provider, or null if not initialized/reinitializing
606
+ */
607
+ getActiveProviderOrNull() {
608
+ // Return null during reinitialization
609
+ if (this.isCurrentlyReinitializing()) {
610
+ return null;
611
+ }
612
+ // Return null if not initialized
613
+ if (this.state.initializationState !== InitializationState.Initialized ||
614
+ !this.isInitialized) {
615
+ return null;
616
+ }
617
+ // Return the active provider instance or null if not found
618
+ return this.activeProviderInstance ?? null;
619
+ }
620
+ /**
621
+ * Place a new order
622
+ * Thin delegation to TradingService
623
+ *
624
+ * @param params - The operation parameters.
625
+ * @returns The order result with order ID and status.
626
+ */
627
+ async placeOrder(params) {
628
+ const provider = this.getActiveProvider();
629
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
630
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").placeOrder({
631
+ provider,
632
+ params,
633
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'placeOrder', {
634
+ saveTradeConfiguration: (symbol, leverage) => this.saveTradeConfiguration(symbol, leverage),
635
+ }),
636
+ reportOrderToDataLake: (dataLakeParams) => this.reportOrderToDataLake(dataLakeParams),
637
+ });
638
+ }
639
+ /**
640
+ * Edit an existing order
641
+ * Thin delegation to TradingService
642
+ *
643
+ * @param params - The operation parameters.
644
+ * @returns The updated order result with order ID and status.
645
+ */
646
+ async editOrder(params) {
647
+ const provider = this.getActiveProvider();
648
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
649
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").editOrder({
650
+ provider,
651
+ params,
652
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'editOrder'),
653
+ });
654
+ }
655
+ /**
656
+ * Cancel an existing order
657
+ *
658
+ * @param params - The operation parameters.
659
+ * @returns The cancellation result with status.
660
+ */
661
+ async cancelOrder(params) {
662
+ const provider = this.getActiveProvider();
663
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").cancelOrder({
664
+ provider,
665
+ params,
666
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'cancelOrder'),
667
+ });
668
+ }
669
+ /**
670
+ * Cancel multiple orders in parallel
671
+ * Batch version of cancelOrder() that cancels multiple orders simultaneously
672
+ *
673
+ * @param params - The operation parameters.
674
+ * @returns The batch cancellation results for each order.
675
+ */
676
+ async cancelOrders(params) {
677
+ const provider = this.getActiveProvider();
678
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").cancelOrders({
679
+ provider,
680
+ params,
681
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'cancelOrders', {
682
+ getOpenOrders: () => this.getOpenOrders(),
683
+ }),
684
+ withStreamPause: (operation, channels) => __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_withStreamPause).call(this, operation, channels),
685
+ });
686
+ }
687
+ /**
688
+ * Close a position (partial or full)
689
+ * Thin delegation to TradingService
690
+ *
691
+ * @param params - The operation parameters.
692
+ * @returns The order result from the close position request.
693
+ */
694
+ async closePosition(params) {
695
+ const provider = this.getActiveProvider();
696
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
697
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").closePosition({
698
+ provider,
699
+ params,
700
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'closePosition', {
701
+ getPositions: () => this.getPositions(),
702
+ }),
703
+ reportOrderToDataLake: (dataLakeParams) => this.reportOrderToDataLake(dataLakeParams),
704
+ });
705
+ }
706
+ /**
707
+ * Close multiple positions in parallel
708
+ * Batch version of closePosition() that closes multiple positions simultaneously
709
+ *
710
+ * @param params - The operation parameters.
711
+ * @returns The batch close results for each position.
712
+ */
713
+ async closePositions(params) {
714
+ const provider = this.getActiveProvider();
715
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
716
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").closePositions({
717
+ provider,
718
+ params,
719
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'closePositions', {
720
+ getPositions: () => this.getPositions(),
721
+ }),
722
+ });
723
+ }
724
+ /**
725
+ * Update TP/SL for an existing position
726
+ *
727
+ * @param params - The operation parameters.
728
+ * @returns The order result from the TP/SL update.
729
+ */
730
+ async updatePositionTPSL(params) {
731
+ const provider = this.getActiveProvider();
732
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
733
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").updatePositionTPSL({
734
+ provider,
735
+ params,
736
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'updatePositionTPSL'),
737
+ });
738
+ }
739
+ /**
740
+ * Update margin for an existing position (add or remove)
741
+ *
742
+ * @param params - The operation parameters.
743
+ * @returns The margin update result.
744
+ */
745
+ async updateMargin(params) {
746
+ const provider = this.getActiveProvider();
747
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
748
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").updateMargin({
749
+ provider,
750
+ symbol: params.symbol,
751
+ amount: params.amount,
752
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'updateMargin'),
753
+ });
754
+ }
755
+ /**
756
+ * Flip position (reverse direction while keeping size and leverage)
757
+ *
758
+ * @param params - The operation parameters.
759
+ * @returns The order result from the position flip.
760
+ */
761
+ async flipPosition(params) {
762
+ const provider = this.getActiveProvider();
763
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
764
+ return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").flipPosition({
765
+ provider,
766
+ position: params.position,
767
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'flipPosition'),
768
+ });
769
+ }
770
+ /**
771
+ * Simplified deposit method that prepares transaction for confirmation screen
772
+ * No complex state tracking - just sets a loading flag
773
+ *
774
+ * @param params - Parameters for the deposit flow
775
+ * @param params.amount - Optional deposit amount
776
+ * @param params.placeOrder - If true, uses addTransaction instead of submit to avoid navigation
777
+ * @returns An object containing a promise that resolves to the transaction hash.
778
+ */
779
+ async depositWithConfirmation(params = {}) {
780
+ const { amount, placeOrder } = params;
781
+ let currentDepositId;
782
+ try {
783
+ // Clear any stale results when starting a new deposit flow
784
+ // Don't set depositInProgress yet - wait until user confirms
785
+ // Prepare deposit transaction using DepositService
786
+ const provider = this.getActiveProvider();
787
+ const { transaction, assetChainId, currentDepositId: depositId, } = await __classPrivateFieldGet(this, _PerpsController_depositService, "f").prepareTransaction({ provider });
788
+ currentDepositId = depositId;
789
+ // Get current account address via messenger (outside of update() for proper typing)
790
+ const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
791
+ const accountAddress = evmAccount?.address ?? 'unknown';
792
+ this.update((state) => {
793
+ state.lastDepositResult = null;
794
+ // Add deposit request to tracking
795
+ const depositRequest = {
796
+ id: currentDepositId ?? (0, uuid_1.v4)(),
797
+ timestamp: Date.now(),
798
+ amount: amount ?? '0', // Use provided amount or default to '0'
799
+ asset: hyperLiquidConfig_1.USDC_SYMBOL,
800
+ accountAddress, // Track which account initiated deposit
801
+ success: false, // Will be updated when transaction completes
802
+ txHash: undefined,
803
+ status: 'pending',
804
+ source: undefined,
805
+ transactionId: undefined, // Will be set to depositId when available
806
+ };
807
+ state.depositRequests.unshift(depositRequest); // Add to beginning of array
808
+ });
809
+ const networkClientId = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_findNetworkClientIdForChain).call(this, assetChainId);
810
+ if (!networkClientId) {
811
+ throw new Error(`No network client found for chain ${assetChainId}. Please add the network first.`);
812
+ }
813
+ let result;
814
+ let transactionMeta;
815
+ let depositOrderResult = null;
816
+ const defaultTransactionOptions = {
817
+ networkClientId,
818
+ origin: controller_utils_1.ORIGIN_METAMASK,
819
+ skipInitialGasEstimate: true,
820
+ };
821
+ if (placeOrder) {
822
+ // Use addTransaction to create transaction without navigating to confirmation screen
823
+ const addResult = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_submitTransaction).call(this, transaction, {
824
+ ...defaultTransactionOptions,
825
+ type: 'perpsDepositAndOrder',
826
+ });
827
+ transactionMeta = addResult.transactionMeta;
828
+ // Return transaction ID immediately (fire-and-forget for caller)
829
+ result = Promise.resolve(transactionMeta.id);
830
+ // Track deposit request lifecycle via the real transaction result
831
+ depositOrderResult = addResult.result;
832
+ }
833
+ else {
834
+ // submit shows the confirmation screen and returns a promise
835
+ // The promise will resolve when transaction completes or reject if cancelled/failed
836
+ const submitResult = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_submitTransaction).call(this, transaction, {
837
+ ...defaultTransactionOptions,
838
+ type: 'perpsDeposit',
839
+ });
840
+ result = submitResult.result;
841
+ transactionMeta = submitResult.transactionMeta;
842
+ }
843
+ // Store the transaction ID and try to get amount from transaction
844
+ this.update((state) => {
845
+ state.lastDepositTransactionId = transactionMeta.id;
846
+ });
847
+ // Track the transaction lifecycle only when using submit (deposit-only flow)
848
+ if (!placeOrder) {
849
+ // At this point, the confirmation modal is shown to the user
850
+ // The result promise will resolve/reject based on user action and transaction outcome
851
+ // Track the transaction lifecycle
852
+ // The result promise will resolve/reject based on user action and transaction outcome
853
+ // Note: We intentionally don't set depositInProgress immediately to avoid
854
+ // showing toasts before the user confirms the transaction
855
+ // TODO: @abretonc7s Find a better way to trigger our custom toast notification then having to toggle the state
856
+ // How to replace the system notifications?
857
+ result
858
+ .then((actualTxHash) => {
859
+ // Transaction was successfully completed
860
+ // Set depositInProgress to true temporarily to show success
861
+ this.update((state) => {
862
+ state.depositInProgress = true;
863
+ state.lastDepositResult = {
864
+ success: true,
865
+ txHash: actualTxHash,
866
+ amount: amount ?? '0',
867
+ asset: hyperLiquidConfig_1.USDC_SYMBOL, // Default asset for deposits
868
+ timestamp: Date.now(),
869
+ error: '',
870
+ };
871
+ // Update the deposit request by request ID to avoid race conditions
872
+ if (state.depositRequests.length > 0) {
873
+ const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
874
+ if (requestToUpdate) {
875
+ // For deposits, we have a txHash immediately, so mark as completed
876
+ // (the transaction hash means the deposit was successful)
877
+ requestToUpdate.status = 'completed';
878
+ requestToUpdate.success = true;
879
+ requestToUpdate.txHash = actualTxHash;
880
+ }
881
+ }
882
+ });
883
+ // Clear depositInProgress after a short delay
884
+ setTimeout(() => {
885
+ this.update((state) => {
886
+ state.depositInProgress = false;
887
+ state.lastDepositTransactionId = null;
888
+ });
889
+ }, 100);
890
+ return undefined;
891
+ })
892
+ .catch((error) => {
893
+ // Check if user denied/cancelled the transaction
894
+ const errorMessage = (0, errorUtils_1.ensureError)(error, 'PerpsController.initiateDeposit').message;
895
+ const userCancelled = errorMessage.includes('User denied') ||
896
+ errorMessage.includes('User rejected') ||
897
+ errorMessage.includes('User cancelled') ||
898
+ errorMessage.includes('User canceled');
899
+ if (userCancelled) {
900
+ // User cancelled - clear any state, no toast
901
+ this.update((state) => {
902
+ state.depositInProgress = false;
903
+ state.lastDepositTransactionId = null;
904
+ // Don't set lastDepositResult - no toast needed
905
+ // Mark deposit request as cancelled
906
+ const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
907
+ if (requestToUpdate) {
908
+ requestToUpdate.status = 'cancelled';
909
+ requestToUpdate.success = false;
910
+ }
911
+ });
912
+ }
913
+ else {
914
+ // Transaction failed after confirmation - show error toast
915
+ this.update((state) => {
916
+ state.depositInProgress = false;
917
+ state.lastDepositTransactionId = null;
918
+ state.lastDepositResult = {
919
+ success: false,
920
+ error: errorMessage,
921
+ amount: amount ?? '0',
922
+ asset: hyperLiquidConfig_1.USDC_SYMBOL, // Default asset for deposits
923
+ timestamp: Date.now(),
924
+ txHash: '',
925
+ };
926
+ // Update the deposit request by request ID to avoid race conditions
927
+ if (state.depositRequests.length > 0) {
928
+ const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
929
+ if (requestToUpdate) {
930
+ requestToUpdate.status = 'failed';
931
+ requestToUpdate.success = false;
932
+ }
933
+ }
934
+ });
935
+ }
936
+ });
937
+ }
938
+ else if (depositOrderResult) {
939
+ // Track deposit request lifecycle for deposit+order flow
940
+ depositOrderResult
941
+ .then((actualTxHash) => {
942
+ this.update((state) => {
943
+ const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
944
+ if (requestToUpdate) {
945
+ requestToUpdate.status = 'completed';
946
+ requestToUpdate.success = true;
947
+ requestToUpdate.txHash = actualTxHash;
948
+ }
949
+ });
950
+ return undefined;
951
+ })
952
+ .catch((error) => {
953
+ const errorMessage = (0, errorUtils_1.ensureError)(error, 'PerpsController.depositWithOrder').message;
954
+ const isCancellation = errorMessage.includes('User denied') ||
955
+ errorMessage.includes('User rejected') ||
956
+ errorMessage.includes('cancelled') ||
957
+ errorMessage.includes('canceled');
958
+ this.update((state) => {
959
+ const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
960
+ if (requestToUpdate) {
961
+ requestToUpdate.status = (isCancellation ? 'cancelled' : 'failed');
962
+ requestToUpdate.success = false;
963
+ }
964
+ });
965
+ });
966
+ }
967
+ return {
968
+ result,
969
+ };
970
+ }
971
+ catch (error) {
972
+ // Check if user denied/cancelled the transaction
973
+ const errorMessage = (0, errorUtils_1.ensureError)(error, 'PerpsController.initiateDeposit').message;
974
+ const userCancelled = errorMessage.includes('User denied') ||
975
+ errorMessage.includes('User rejected') ||
976
+ errorMessage.includes('User cancelled') ||
977
+ errorMessage.includes('User canceled');
978
+ if (!userCancelled) {
979
+ // Only track actual errors, not user cancellations
980
+ this.update((state) => {
981
+ state.lastDepositTransactionId = null;
982
+ // Note: lastDepositResult is already set in the catch block above
983
+ // Mark deposit request as failed if one was created
984
+ if (currentDepositId) {
985
+ const request = state.depositRequests.find((req) => req.id === currentDepositId);
986
+ if (request) {
987
+ request.status = 'failed';
988
+ request.success = false;
989
+ }
990
+ }
991
+ });
992
+ }
993
+ throw error;
994
+ }
995
+ }
996
+ /**
997
+ * Same as depositWithConfirmation - prepares transaction for confirmation screen.
998
+ *
999
+ * @returns A promise that resolves to the string result.
1000
+ */
1001
+ async depositWithOrder() {
1002
+ return this.depositWithConfirmation({ placeOrder: true });
1003
+ }
1004
+ /**
1005
+ * Clear the last deposit result after it has been shown to the user
1006
+ */
1007
+ clearDepositResult() {
1008
+ this.update((state) => {
1009
+ state.lastDepositResult = null;
1010
+ });
1011
+ }
1012
+ clearWithdrawResult() {
1013
+ this.update((state) => {
1014
+ state.lastWithdrawResult = null;
1015
+ });
1016
+ }
1017
+ /**
1018
+ * Update withdrawal request status when it completes
1019
+ * This is called when a withdrawal is matched with a completed withdrawal from the API
1020
+ *
1021
+ * @param withdrawalId - The withdrawal transaction ID.
1022
+ * @param status - The current status.
1023
+ * @param txHash - The transaction hash.
1024
+ */
1025
+ updateWithdrawalStatus(withdrawalId, status, txHash) {
1026
+ let withdrawalAmount;
1027
+ let shouldTrack = false;
1028
+ let found = false;
1029
+ this.update((state) => {
1030
+ const withdrawalIndex = state.withdrawalRequests.findIndex((request) => request.id === withdrawalId);
1031
+ if (withdrawalIndex >= 0) {
1032
+ found = true;
1033
+ const request = state.withdrawalRequests[withdrawalIndex];
1034
+ withdrawalAmount = request.amount;
1035
+ shouldTrack =
1036
+ withdrawalAmount !== undefined && request.status !== status;
1037
+ request.status = status;
1038
+ request.success = status === 'completed';
1039
+ if (txHash) {
1040
+ request.txHash = txHash;
1041
+ }
1042
+ // Clear withdrawal progress when withdrawal completes
1043
+ if (status === 'completed' || status === 'failed') {
1044
+ state.withdrawalProgress = {
1045
+ progress: 0,
1046
+ lastUpdated: Date.now(),
1047
+ activeWithdrawalId: null,
1048
+ };
1049
+ }
1050
+ }
1051
+ });
1052
+ if (shouldTrack && withdrawalAmount !== undefined) {
1053
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getMetrics).call(this).trackPerpsEvent(types_1.PerpsAnalyticsEvent.WithdrawalTransaction, {
1054
+ [eventNames_1.PERPS_EVENT_PROPERTY.STATUS]: status === 'completed'
1055
+ ? eventNames_1.PERPS_EVENT_VALUE.STATUS.COMPLETED
1056
+ : eventNames_1.PERPS_EVENT_VALUE.STATUS.FAILED,
1057
+ [eventNames_1.PERPS_EVENT_PROPERTY.WITHDRAWAL_AMOUNT]: Number.parseFloat(withdrawalAmount),
1058
+ });
1059
+ }
1060
+ if (found) {
1061
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Updated withdrawal status', {
1062
+ withdrawalId,
1063
+ status,
1064
+ txHash,
1065
+ });
1066
+ }
1067
+ }
1068
+ /**
1069
+ * Update withdrawal progress (persistent across navigation)
1070
+ *
1071
+ * @param progress - The progress indicator.
1072
+ * @param activeWithdrawalId - The active withdrawal ID.
1073
+ */
1074
+ updateWithdrawalProgress(progress, activeWithdrawalId = null) {
1075
+ this.update((state) => {
1076
+ state.withdrawalProgress = {
1077
+ progress,
1078
+ lastUpdated: Date.now(),
1079
+ activeWithdrawalId,
1080
+ };
1081
+ });
1082
+ }
1083
+ /**
1084
+ * Get current withdrawal progress
1085
+ *
1086
+ * @returns The withdrawal progress, last update timestamp, and active withdrawal ID.
1087
+ */
1088
+ getWithdrawalProgress() {
1089
+ return this.state.withdrawalProgress;
1090
+ }
1091
+ /**
1092
+ * Withdraw funds from trading account
1093
+ *
1094
+ * The withdrawal process varies by provider and may involve:
1095
+ * - Direct on-chain transfers
1096
+ * - Bridge operations
1097
+ * - Multi-step validation processes
1098
+ *
1099
+ * Check the specific provider documentation for detailed withdrawal flows.
1100
+ *
1101
+ * @param params Withdrawal parameters
1102
+ * @returns WithdrawResult with withdrawal ID and tracking info
1103
+ */
1104
+ async withdraw(params) {
1105
+ const provider = this.getActiveProvider();
1106
+ return __classPrivateFieldGet(this, _PerpsController_accountService, "f").withdraw({
1107
+ provider,
1108
+ params,
1109
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'withdraw'),
1110
+ refreshAccountState: async () => {
1111
+ await this.getAccountState({ source: 'post_withdrawal' });
1112
+ },
1113
+ });
1114
+ }
1115
+ /**
1116
+ * Get current positions
1117
+ * Thin delegation to MarketDataService
1118
+ *
1119
+ * For standalone mode, bypasses getActiveProvider() to allow position queries
1120
+ * without full perps initialization (e.g., for showing positions on token details page)
1121
+ *
1122
+ * @param params - The operation parameters.
1123
+ * @returns Array of open positions for the active provider.
1124
+ */
1125
+ async getPositions(params) {
1126
+ // For standalone mode, access provider directly without initialization check
1127
+ // This allows discovery use cases (checking if user has positions) without full perps setup
1128
+ if (params?.standalone && params.userAddress) {
1129
+ // Use activeProviderInstance if available (respects provider abstraction)
1130
+ // Fallback to cached standalone provider for pre-initialization discovery
1131
+ // TODO: When adding new providers (MYX), consider a provider factory pattern
1132
+ const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
1133
+ return provider.getPositions(params);
1134
+ }
1135
+ const provider = this.getActiveProvider();
1136
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getPositions({
1137
+ provider,
1138
+ params,
1139
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getPositions'),
1140
+ });
1141
+ }
1142
+ /**
1143
+ * Get historical user fills (trade executions)
1144
+ * Thin delegation to MarketDataService
1145
+ *
1146
+ * @param params - The operation parameters.
1147
+ * @returns Array of historical trade executions (fills).
1148
+ */
1149
+ async getOrderFills(params) {
1150
+ const provider = this.getActiveProvider();
1151
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getOrderFills({
1152
+ provider,
1153
+ params,
1154
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getOrderFills'),
1155
+ });
1156
+ }
1157
+ /**
1158
+ * Get historical user orders (order lifecycle)
1159
+ * Thin delegation to MarketDataService
1160
+ *
1161
+ * @param params - The operation parameters.
1162
+ * @returns Array of historical orders.
1163
+ */
1164
+ async getOrders(params) {
1165
+ const provider = this.getActiveProvider();
1166
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getOrders({
1167
+ provider,
1168
+ params,
1169
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getOrders'),
1170
+ });
1171
+ }
1172
+ /**
1173
+ * Get currently open orders (real-time status)
1174
+ * Thin delegation to MarketDataService
1175
+ *
1176
+ * For standalone mode, bypasses getActiveProvider() to allow open order queries
1177
+ * without full perps initialization (e.g., for background preloading)
1178
+ *
1179
+ * @param params - The operation parameters.
1180
+ * @returns A promise that resolves to the result.
1181
+ */
1182
+ async getOpenOrders(params) {
1183
+ // For standalone mode, access provider directly without initialization check
1184
+ if (params?.standalone && params.userAddress) {
1185
+ const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
1186
+ return provider.getOpenOrders(params);
1187
+ }
1188
+ const provider = this.getActiveProvider();
1189
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getOpenOrders({
1190
+ provider,
1191
+ params,
1192
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getOpenOrders'),
1193
+ });
1194
+ }
1195
+ /**
1196
+ * Get historical user funding history (funding payments)
1197
+ * Thin delegation to MarketDataService
1198
+ *
1199
+ * @param params - The operation parameters.
1200
+ * @returns Array of historical funding payments.
1201
+ */
1202
+ async getFunding(params) {
1203
+ const provider = this.getActiveProvider();
1204
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getFunding({
1205
+ provider,
1206
+ params,
1207
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getFunding'),
1208
+ });
1209
+ }
1210
+ /**
1211
+ * Get account state (balances, etc.)
1212
+ * Thin delegation to MarketDataService
1213
+ *
1214
+ * For standalone mode, bypasses getActiveProvider() to allow account state queries
1215
+ * without full perps initialization (e.g., for checking if user has perps funds)
1216
+ *
1217
+ * @param params - The operation parameters.
1218
+ * @returns A promise that resolves to the result.
1219
+ */
1220
+ async getAccountState(params) {
1221
+ // For standalone mode, access provider directly without initialization check
1222
+ // This allows discovery use cases (checking if user has perps funds) without full perps setup
1223
+ if (params?.standalone && params.userAddress) {
1224
+ // Use activeProviderInstance if available (respects provider abstraction)
1225
+ // Fallback to cached standalone provider for pre-initialization discovery
1226
+ const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
1227
+ return provider.getAccountState(params);
1228
+ }
1229
+ const provider = this.getActiveProvider();
1230
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getAccountState({
1231
+ provider,
1232
+ params,
1233
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getAccountState'),
1234
+ });
1235
+ }
1236
+ /**
1237
+ * Get historical portfolio data
1238
+ * Thin delegation to MarketDataService
1239
+ *
1240
+ * @param params - The operation parameters.
1241
+ * @returns The historical portfolio data points.
1242
+ */
1243
+ async getHistoricalPortfolio(params) {
1244
+ const provider = this.getActiveProvider();
1245
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getHistoricalPortfolio({
1246
+ provider,
1247
+ params,
1248
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getHistoricalPortfolio'),
1249
+ });
1250
+ }
1251
+ /**
1252
+ * Get available markets with optional filtering
1253
+ * Thin delegation to MarketDataService
1254
+ *
1255
+ * For standalone mode, bypasses getActiveProvider() to allow market discovery
1256
+ * without full perps initialization (e.g., for discovery banners on spot screens)
1257
+ *
1258
+ * @param params - The operation parameters.
1259
+ * @returns Array of available markets matching the filter criteria.
1260
+ */
1261
+ async getMarkets(params) {
1262
+ // For standalone mode, access provider directly without initialization check
1263
+ // This allows discovery use cases (checking if market exists) without full perps setup
1264
+ if (params?.standalone) {
1265
+ // Use activeProviderInstance if available (respects provider abstraction)
1266
+ // Fallback to cached standalone provider for pre-initialization discovery
1267
+ const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
1268
+ return provider.getMarkets(params);
1269
+ }
1270
+ const provider = this.getActiveProvider();
1271
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarkets({
1272
+ provider,
1273
+ params,
1274
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getMarkets'),
1275
+ });
1276
+ }
1277
+ /**
1278
+ * Get market data with prices (includes price, volume, 24h change)
1279
+ *
1280
+ * For standalone mode, bypasses getActiveProvider() to allow market data queries
1281
+ * without full perps initialization (e.g., for background preloading on app start)
1282
+ *
1283
+ * @param params - The operation parameters.
1284
+ * @param params.standalone - Whether to use standalone mode.
1285
+ * @returns A promise that resolves to the market data.
1286
+ */
1287
+ async getMarketDataWithPrices(params) {
1288
+ if (params?.standalone) {
1289
+ // Use activeProviderInstance if available (respects provider abstraction)
1290
+ // Fallback to cached standalone provider for pre-initialization discovery
1291
+ const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
1292
+ return provider.getMarketDataWithPrices();
1293
+ }
1294
+ const provider = this.getActiveProvider();
1295
+ return provider.getMarketDataWithPrices();
1296
+ }
1297
+ /**
1298
+ * Start background market data preloading.
1299
+ * Fetches market data immediately and refreshes every 5 minutes.
1300
+ * Watches for isTestnet and hip3ConfigVersion changes to re-preload.
1301
+ */
1302
+ startMarketDataPreload() {
1303
+ if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
1304
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Preload already started, skipping');
1305
+ return;
1306
+ }
1307
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Starting market data preload');
1308
+ // Track current values for change detection
1309
+ __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, this.state.isTestnet, "f");
1310
+ __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, this.state.hip3ConfigVersion, "f");
1311
+ // Immediate preload
1312
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1313
+ /* fire-and-forget */
1314
+ });
1315
+ // Periodic refresh
1316
+ __classPrivateFieldSet(this, _PerpsController_preloadTimer, setInterval(() => {
1317
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1318
+ /* fire-and-forget */
1319
+ });
1320
+ }, __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadRefreshMs)), "f");
1321
+ // Watch for isTestnet / hip3ConfigVersion / cachedUserDataAddress changes
1322
+ const handler = (_state, patches) => {
1323
+ // Early-return when no watched field changed (skips ~46 unrelated updates)
1324
+ const hasRelevantChange = patches.some((patch) => typeof patch.path[0] === 'string' &&
1325
+ __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadWatchedPaths).has(patch.path[0]));
1326
+ if (!hasRelevantChange) {
1327
+ return;
1328
+ }
1329
+ const currentIsTestnet = this.state.isTestnet;
1330
+ const currentHip3Version = this.state.hip3ConfigVersion;
1331
+ const testnetChanged = currentIsTestnet !== __classPrivateFieldGet(this, _PerpsController_previousIsTestnet, "f");
1332
+ const hip3Changed = currentHip3Version !== __classPrivateFieldGet(this, _PerpsController_previousHip3ConfigVersion, "f");
1333
+ if (testnetChanged || hip3Changed) {
1334
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Network/config changed, re-preloading', {
1335
+ testnetChanged,
1336
+ hip3Changed,
1337
+ isTestnet: currentIsTestnet,
1338
+ hip3ConfigVersion: currentHip3Version,
1339
+ });
1340
+ __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, currentIsTestnet, "f");
1341
+ __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, currentHip3Version, "f");
1342
+ // Clear stale cache (market + user data)
1343
+ this.update((state) => {
1344
+ state.cachedMarketData = null;
1345
+ state.cachedMarketDataTimestamp = 0;
1346
+ state.cachedPositions = null;
1347
+ state.cachedOrders = null;
1348
+ state.cachedAccountState = null;
1349
+ state.cachedUserDataTimestamp = 0;
1350
+ state.cachedUserDataAddress = null;
1351
+ });
1352
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1353
+ /* fire-and-forget */
1354
+ });
1355
+ }
1356
+ };
1357
+ this.messenger.subscribe('PerpsController:stateChange', handler);
1358
+ __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, () => {
1359
+ this.messenger.unsubscribe('PerpsController:stateChange', handler);
1360
+ }, "f");
1361
+ // Watch for account changes via AccountTreeController
1362
+ const accountChangeHandler = () => {
1363
+ const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
1364
+ const currentAddress = evmAccount?.address ?? null;
1365
+ // If there's cached data from a different account (or no EVM account now), clear it
1366
+ if (this.state.cachedUserDataAddress !== null &&
1367
+ currentAddress !== this.state.cachedUserDataAddress) {
1368
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Account changed, clearing user data cache');
1369
+ this.update((state) => {
1370
+ state.cachedPositions = null;
1371
+ state.cachedOrders = null;
1372
+ state.cachedAccountState = null;
1373
+ state.cachedUserDataTimestamp = 0;
1374
+ state.cachedUserDataAddress = null;
1375
+ });
1376
+ // Only preload if the new account is an EVM account
1377
+ if (currentAddress) {
1378
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
1379
+ /* fire-and-forget */
1380
+ });
1381
+ }
1382
+ }
1383
+ };
1384
+ this.messenger.subscribe('AccountTreeController:selectedAccountGroupChange', accountChangeHandler);
1385
+ __classPrivateFieldSet(this, _PerpsController_accountChangeUnsubscribe, () => {
1386
+ this.messenger.unsubscribe('AccountTreeController:selectedAccountGroupChange', accountChangeHandler);
1387
+ }, "f");
1388
+ }
1389
+ /**
1390
+ * Stop background market data preloading.
1391
+ */
1392
+ stopMarketDataPreload() {
1393
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Stopping market data preload');
1394
+ if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
1395
+ clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
1396
+ __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
1397
+ }
1398
+ if (__classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f")) {
1399
+ __classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f").call(this);
1400
+ __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, null, "f");
1401
+ }
1402
+ if (__classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f")) {
1403
+ __classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f").call(this);
1404
+ __classPrivateFieldSet(this, _PerpsController_accountChangeUnsubscribe, null, "f");
1405
+ }
1406
+ __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
1407
+ __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
1408
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this).catch(() => {
1409
+ /* fire-and-forget to preserve sync signature */
1410
+ });
1411
+ }
1412
+ /**
1413
+ * Get list of available HIP-3 builder-deployed DEXs
1414
+ *
1415
+ * @param params - Optional parameters for filtering
1416
+ * @returns Array of DEX names
1417
+ */
1418
+ async getAvailableDexs(params) {
1419
+ const provider = this.getActiveProvider();
1420
+ const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getAvailableDexs');
1421
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getAvailableDexs({
1422
+ provider,
1423
+ params,
1424
+ context,
1425
+ });
1426
+ }
1427
+ /**
1428
+ * Fetch historical candle data
1429
+ * Thin delegation to MarketDataService
1430
+ *
1431
+ * @param options - The configuration options.
1432
+ * @param options.symbol - The trading pair symbol.
1433
+ * @param options.interval - The candle interval period.
1434
+ * @param options.limit - Maximum number of items to fetch.
1435
+ * @param options.endTime - End timestamp in milliseconds.
1436
+ * @returns The historical candle data for the requested symbol and interval.
1437
+ */
1438
+ async fetchHistoricalCandles(options) {
1439
+ const { symbol, interval, limit = 100, endTime } = options;
1440
+ const provider = this.getActiveProvider();
1441
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").fetchHistoricalCandles({
1442
+ provider,
1443
+ symbol,
1444
+ interval,
1445
+ limit,
1446
+ endTime,
1447
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'fetchHistoricalCandles'),
1448
+ });
1449
+ }
1450
+ /**
1451
+ * Calculate liquidation price for a position
1452
+ * Uses provider-specific formulas based on protocol rules
1453
+ *
1454
+ * @param params - The operation parameters.
1455
+ * @returns A promise that resolves to the string result.
1456
+ */
1457
+ async calculateLiquidationPrice(params) {
1458
+ const provider = this.getActiveProvider();
1459
+ const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'calculateLiquidationPrice');
1460
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").calculateLiquidationPrice({
1461
+ provider,
1462
+ params,
1463
+ context,
1464
+ });
1465
+ }
1466
+ /**
1467
+ * Calculate maintenance margin for a specific asset
1468
+ * Returns a percentage (e.g., 0.0125 for 1.25%)
1469
+ *
1470
+ * @param params - The operation parameters.
1471
+ * @returns A promise that resolves to the numeric result.
1472
+ */
1473
+ async calculateMaintenanceMargin(params) {
1474
+ const provider = this.getActiveProvider();
1475
+ const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'calculateMaintenanceMargin');
1476
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").calculateMaintenanceMargin({
1477
+ provider,
1478
+ params,
1479
+ context,
1480
+ });
1481
+ }
1482
+ /**
1483
+ * Get maximum leverage allowed for an asset
1484
+ *
1485
+ * @param asset - The asset identifier.
1486
+ * @returns A promise that resolves to the numeric result.
1487
+ */
1488
+ async getMaxLeverage(asset) {
1489
+ const provider = this.getActiveProvider();
1490
+ const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getMaxLeverage');
1491
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMaxLeverage({ provider, asset, context });
1492
+ }
1493
+ /**
1494
+ * Validate order parameters according to protocol-specific rules
1495
+ *
1496
+ * @param params - The operation parameters.
1497
+ * @returns True if the condition is met.
1498
+ */
1499
+ async validateOrder(params) {
1500
+ const provider = this.getActiveProvider();
1501
+ const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'validateOrder');
1502
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").validateOrder({ provider, params, context });
1503
+ }
1504
+ /**
1505
+ * Validate close position parameters according to protocol-specific rules
1506
+ *
1507
+ * @param params - The operation parameters.
1508
+ * @returns A promise that resolves to the result.
1509
+ */
1510
+ async validateClosePosition(params) {
1511
+ const provider = this.getActiveProvider();
1512
+ const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'validateClosePosition');
1513
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").validateClosePosition({
1514
+ provider,
1515
+ params,
1516
+ context,
1517
+ });
1518
+ }
1519
+ /**
1520
+ * Validate withdrawal parameters according to protocol-specific rules
1521
+ *
1522
+ * @param params - The operation parameters.
1523
+ * @returns True if the condition is met.
1524
+ */
1525
+ async validateWithdrawal(params) {
1526
+ const provider = this.getActiveProvider();
1527
+ return __classPrivateFieldGet(this, _PerpsController_accountService, "f").validateWithdrawal({ provider, params });
1528
+ }
1529
+ /**
1530
+ * Get supported withdrawal routes - returns complete asset and routing information
1531
+ *
1532
+ * @returns Array of supported asset routes for withdrawals.
1533
+ */
1534
+ getWithdrawalRoutes() {
1535
+ try {
1536
+ const provider = this.getActiveProvider();
1537
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getWithdrawalRoutes({ provider });
1538
+ }
1539
+ catch (error) {
1540
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.getWithdrawalRoutes'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'getWithdrawalRoutes'));
1541
+ // Return empty array if provider is not available
1542
+ return [];
1543
+ }
1544
+ }
1545
+ /**
1546
+ * Toggle between testnet and mainnet
1547
+ *
1548
+ * @returns The toggle result with success status and current network mode.
1549
+ */
1550
+ async toggleTestnet() {
1551
+ // Prevent concurrent reinitializations
1552
+ if (this.isCurrentlyReinitializing()) {
1553
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Already reinitializing, skipping toggle', {
1554
+ timestamp: new Date().toISOString(),
1555
+ });
1556
+ return {
1557
+ success: false,
1558
+ isTestnet: this.state.isTestnet,
1559
+ error: perpsErrorCodes_1.PERPS_ERROR_CODES.CLIENT_REINITIALIZING,
1560
+ };
1561
+ }
1562
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
1563
+ // Store previous isTestnet for rollback on failure
1564
+ const previousIsTestnet = this.state.isTestnet;
1565
+ try {
1566
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
1567
+ const previousNetwork = previousIsTestnet ? 'testnet' : 'mainnet';
1568
+ this.update((state) => {
1569
+ state.isTestnet = !state.isTestnet;
1570
+ });
1571
+ const newNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
1572
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Network toggle initiated', {
1573
+ from: previousNetwork,
1574
+ to: newNetwork,
1575
+ timestamp: new Date().toISOString(),
1576
+ });
1577
+ // Reset initialization state and reinitialize provider with new testnet setting
1578
+ this.isInitialized = false;
1579
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
1580
+ await this.init();
1581
+ // Check if initialization actually succeeded — performInitialization()
1582
+ // does not throw on failure, it sets state to Failed and resolves.
1583
+ if (this.state.initializationState === InitializationState.Failed) {
1584
+ throw new Error(this.state.initializationError ??
1585
+ 'Network toggle initialization failed');
1586
+ }
1587
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Network toggle completed', {
1588
+ newNetwork,
1589
+ isTestnet: this.state.isTestnet,
1590
+ timestamp: new Date().toISOString(),
1591
+ });
1592
+ return { success: true, isTestnet: this.state.isTestnet };
1593
+ }
1594
+ catch (error) {
1595
+ // Rollback isTestnet to previous value
1596
+ this.update((state) => {
1597
+ state.isTestnet = previousIsTestnet;
1598
+ });
1599
+ return {
1600
+ success: false,
1601
+ isTestnet: this.state.isTestnet,
1602
+ error: (0, errorUtils_1.ensureError)(error, 'PerpsController.toggleTestnet').message,
1603
+ };
1604
+ }
1605
+ finally {
1606
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
1607
+ }
1608
+ }
1609
+ /**
1610
+ * Switch to a different provider
1611
+ * Uses a full reinit approach: disconnect() → update state → init()
1612
+ * This ensures complete state reset including WebSocket connections and caches.
1613
+ *
1614
+ * @param providerId - The provider identifier.
1615
+ * @returns The switch result with success status and active provider.
1616
+ */
1617
+ async switchProvider(providerId) {
1618
+ // No-op if already on this provider (regardless of init state)
1619
+ if (this.state.activeProvider === providerId) {
1620
+ return { success: true, providerId };
1621
+ }
1622
+ // Validate provider is available
1623
+ // 'aggregated' is always valid, individual providers must exist in the map
1624
+ const isValidProvider = providerId === 'aggregated' || this.providers.has(providerId);
1625
+ if (!isValidProvider) {
1626
+ return {
1627
+ success: false,
1628
+ providerId: this.state.activeProvider,
1629
+ error: `Provider ${providerId} not available`,
1630
+ };
1631
+ }
1632
+ // Prevent concurrent switches
1633
+ if (this.isCurrentlyReinitializing()) {
1634
+ return {
1635
+ success: false,
1636
+ providerId: this.state.activeProvider,
1637
+ error: perpsErrorCodes_1.PERPS_ERROR_CODES.CLIENT_REINITIALIZING,
1638
+ };
1639
+ }
1640
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
1641
+ // Store previous provider for rollback on failure
1642
+ const previousProvider = this.state.activeProvider;
1643
+ try {
1644
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
1645
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Provider switch initiated', {
1646
+ from: previousProvider,
1647
+ to: providerId,
1648
+ timestamp: new Date().toISOString(),
1649
+ });
1650
+ // Provider disconnect is handled by performInitialization() during
1651
+ // reinitialization. The disconnect() method skips provider teardown
1652
+ // when isReinitializing is true to prevent double-disconnect.
1653
+ // Update state with new provider
1654
+ this.update((state) => {
1655
+ state.activeProvider = providerId;
1656
+ state.accountState = null;
1657
+ state.initializationState = InitializationState.Uninitialized;
1658
+ });
1659
+ // Reset initialization state and reinitialize
1660
+ this.isInitialized = false;
1661
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
1662
+ await this.init();
1663
+ // Check if initialization actually succeeded — performInitialization()
1664
+ // does not throw on failure, it sets state to Failed and resolves.
1665
+ if (this.state.initializationState === InitializationState.Failed) {
1666
+ throw new Error(this.state.initializationError ?? 'Provider initialization failed');
1667
+ }
1668
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Provider switch completed', {
1669
+ providerId,
1670
+ timestamp: new Date().toISOString(),
1671
+ });
1672
+ return { success: true, providerId };
1673
+ }
1674
+ catch (error) {
1675
+ // Rollback state to previous provider
1676
+ this.update((state) => {
1677
+ state.activeProvider = previousProvider;
1678
+ });
1679
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.switchProvider'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'switchProvider', { providerId }));
1680
+ // Attempt to reinitialize the previous provider via init(),
1681
+ // which handles all provider modes including 'aggregated'.
1682
+ try {
1683
+ this.isInitialized = false;
1684
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
1685
+ await this.init();
1686
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Rollback to previous provider succeeded', {
1687
+ previousProvider,
1688
+ timestamp: new Date().toISOString(),
1689
+ });
1690
+ }
1691
+ catch (reinitError) {
1692
+ // Reinit also failed — mark as failed
1693
+ this.update((state) => {
1694
+ state.initializationState = InitializationState.Failed;
1695
+ });
1696
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(reinitError, 'PerpsController.switchProvider.rollback'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'switchProvider.rollback', {
1697
+ previousProvider,
1698
+ }));
1699
+ }
1700
+ return {
1701
+ success: false,
1702
+ providerId: previousProvider,
1703
+ error: error instanceof Error
1704
+ ? error.message
1705
+ : perpsErrorCodes_1.PERPS_ERROR_CODES.UNKNOWN_ERROR,
1706
+ };
1707
+ }
1708
+ finally {
1709
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
1710
+ }
1711
+ }
1712
+ /**
1713
+ * Get current network (mainnet/testnet)
1714
+ *
1715
+ * @returns Either 'mainnet' or 'testnet' based on the current configuration.
1716
+ */
1717
+ getCurrentNetwork() {
1718
+ return this.state.isTestnet ? 'testnet' : 'mainnet';
1719
+ }
1720
+ /**
1721
+ * Get the current WebSocket connection state from the active provider.
1722
+ * Used by the UI to monitor connection health and show notifications.
1723
+ *
1724
+ * @returns The current WebSocket connection state, or DISCONNECTED if not supported
1725
+ */
1726
+ getWebSocketConnectionState() {
1727
+ try {
1728
+ const provider = this.getActiveProvider();
1729
+ if (provider.getWebSocketConnectionState) {
1730
+ return provider.getWebSocketConnectionState();
1731
+ }
1732
+ // Fallback for providers that don't support this method
1733
+ return types_1.WebSocketConnectionState.Disconnected;
1734
+ }
1735
+ catch {
1736
+ // If no provider is active, return disconnected
1737
+ return types_1.WebSocketConnectionState.Disconnected;
1738
+ }
1739
+ }
1740
+ /**
1741
+ * Subscribe to WebSocket connection state changes from the active provider.
1742
+ * The listener will be called immediately with the current state and whenever the state changes.
1743
+ *
1744
+ * @param listener - Callback function that receives the new connection state and reconnection attempt
1745
+ * @returns Unsubscribe function to remove the listener, or no-op if not supported
1746
+ */
1747
+ subscribeToConnectionState(listener) {
1748
+ try {
1749
+ const provider = this.getActiveProvider();
1750
+ if (provider.subscribeToConnectionState) {
1751
+ return provider.subscribeToConnectionState(listener);
1752
+ }
1753
+ // Fallback: immediately call with current state and return no-op unsubscribe
1754
+ listener(this.getWebSocketConnectionState(), 0);
1755
+ return () => {
1756
+ // No-op
1757
+ };
1758
+ }
1759
+ catch {
1760
+ // If no provider is active, call with disconnected and return no-op
1761
+ listener(types_1.WebSocketConnectionState.Disconnected, 0);
1762
+ return () => {
1763
+ // No-op
1764
+ };
1765
+ }
1766
+ }
1767
+ /**
1768
+ * Manually trigger a WebSocket reconnection attempt.
1769
+ * Used by the UI retry button when connection is lost.
1770
+ */
1771
+ async reconnect() {
1772
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, '[PerpsController] reconnect() called');
1773
+ try {
1774
+ const provider = this.getActiveProvider();
1775
+ if (provider.reconnect) {
1776
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, '[PerpsController] Delegating to provider.reconnect()');
1777
+ await provider.reconnect();
1778
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, '[PerpsController] provider.reconnect() completed');
1779
+ }
1780
+ else {
1781
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, '[PerpsController] Provider does not support reconnect()');
1782
+ }
1783
+ }
1784
+ catch (error) {
1785
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.reconnect'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'reconnect', {
1786
+ operation: 'websocket_reconnect',
1787
+ }));
1788
+ }
1789
+ }
1790
+ // Live data delegation (NO Redux) - delegates to active provider
1791
+ /**
1792
+ * Subscribe to live price updates
1793
+ *
1794
+ * @param params - The operation parameters.
1795
+ * @returns A cleanup function to remove the subscription.
1796
+ */
1797
+ subscribeToPrices(params) {
1798
+ const provider = this.getActiveProviderOrNull();
1799
+ if (!provider) {
1800
+ return () => {
1801
+ // No-op: Provider not initialized
1802
+ };
1803
+ }
1804
+ try {
1805
+ return provider.subscribeToPrices(params);
1806
+ }
1807
+ catch (error) {
1808
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToPrices'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToPrices', {
1809
+ symbols: params.symbols?.join(','),
1810
+ }));
1811
+ return () => {
1812
+ // No-op
1813
+ };
1814
+ }
1815
+ }
1816
+ /**
1817
+ * Subscribe to live position updates
1818
+ *
1819
+ * @param params - The operation parameters.
1820
+ * @returns A cleanup function to remove the subscription.
1821
+ */
1822
+ subscribeToPositions(params) {
1823
+ const provider = this.getActiveProviderOrNull();
1824
+ if (!provider) {
1825
+ return () => {
1826
+ // No-op: Provider not initialized
1827
+ };
1828
+ }
1829
+ try {
1830
+ return provider.subscribeToPositions(params);
1831
+ }
1832
+ catch (error) {
1833
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToPositions'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToPositions', {
1834
+ accountId: params.accountId,
1835
+ }));
1836
+ return () => {
1837
+ // No-op
1838
+ };
1839
+ }
1840
+ }
1841
+ /**
1842
+ * Subscribe to live order fill updates
1843
+ *
1844
+ * @param params - The operation parameters.
1845
+ * @returns A cleanup function to remove the subscription.
1846
+ */
1847
+ subscribeToOrderFills(params) {
1848
+ const provider = this.getActiveProviderOrNull();
1849
+ if (!provider) {
1850
+ return () => {
1851
+ // No-op: Provider not initialized
1852
+ };
1853
+ }
1854
+ try {
1855
+ return provider.subscribeToOrderFills(params);
1856
+ }
1857
+ catch (error) {
1858
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToOrderFills'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToOrderFills', {
1859
+ accountId: params.accountId,
1860
+ }));
1861
+ return () => {
1862
+ // No-op
1863
+ };
1864
+ }
1865
+ }
1866
+ /**
1867
+ * Subscribe to live order updates
1868
+ *
1869
+ * @param params - The operation parameters.
1870
+ * @returns A cleanup function to remove the subscription.
1871
+ */
1872
+ subscribeToOrders(params) {
1873
+ const provider = this.getActiveProviderOrNull();
1874
+ if (!provider) {
1875
+ return () => {
1876
+ // No-op: Provider not initialized
1877
+ };
1878
+ }
1879
+ try {
1880
+ return provider.subscribeToOrders(params);
1881
+ }
1882
+ catch (error) {
1883
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToOrders'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToOrders', {
1884
+ accountId: params.accountId,
1885
+ }));
1886
+ return () => {
1887
+ // No-op
1888
+ };
1889
+ }
1890
+ }
1891
+ /**
1892
+ * Subscribe to live account updates.
1893
+ * Updates controller state (Redux) when new account data arrives so consumers
1894
+ * like usePerpsBalanceTokenFilter (PayWithModal) see the latest balance.
1895
+ *
1896
+ * @param params - The operation parameters.
1897
+ * @returns A cleanup function to remove the subscription.
1898
+ */
1899
+ subscribeToAccount(params) {
1900
+ const provider = this.getActiveProviderOrNull();
1901
+ if (!provider) {
1902
+ return () => {
1903
+ // No-op: Provider not initialized
1904
+ };
1905
+ }
1906
+ try {
1907
+ const originalCallback = params.callback;
1908
+ return provider.subscribeToAccount({
1909
+ ...params,
1910
+ callback: (account) => {
1911
+ if (account) {
1912
+ this.update((state) => {
1913
+ state.accountState = account;
1914
+ state.lastUpdateTimestamp = Date.now();
1915
+ state.lastError = null;
1916
+ });
1917
+ }
1918
+ originalCallback(account);
1919
+ },
1920
+ });
1921
+ }
1922
+ catch (error) {
1923
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToAccount'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToAccount', {
1924
+ accountId: params.accountId,
1925
+ }));
1926
+ return () => {
1927
+ // No-op
1928
+ };
1929
+ }
1930
+ }
1931
+ /**
1932
+ * Subscribe to full order book updates with multiple depth levels
1933
+ * Creates a dedicated L2Book subscription for real-time order book data
1934
+ *
1935
+ * @param params - The operation parameters.
1936
+ * @returns A cleanup function to remove the subscription.
1937
+ */
1938
+ subscribeToOrderBook(params) {
1939
+ const provider = this.getActiveProviderOrNull();
1940
+ if (!provider) {
1941
+ return () => {
1942
+ // No-op: Provider not initialized
1943
+ };
1944
+ }
1945
+ try {
1946
+ return provider.subscribeToOrderBook(params);
1947
+ }
1948
+ catch (error) {
1949
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToOrderBook'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToOrderBook', {
1950
+ symbol: params.symbol,
1951
+ levels: params.levels,
1952
+ }));
1953
+ return () => {
1954
+ // No-op
1955
+ };
1956
+ }
1957
+ }
1958
+ /**
1959
+ * Subscribe to live candle updates
1960
+ *
1961
+ * @param params - The operation parameters.
1962
+ * @returns A cleanup function to remove the subscription.
1963
+ */
1964
+ subscribeToCandles(params) {
1965
+ const provider = this.getActiveProviderOrNull();
1966
+ if (!provider) {
1967
+ return () => {
1968
+ // No-op: Provider not initialized
1969
+ };
1970
+ }
1971
+ try {
1972
+ return provider.subscribeToCandles(params);
1973
+ }
1974
+ catch (error) {
1975
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToCandles'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToCandles', {
1976
+ symbol: params.symbol,
1977
+ interval: params.interval,
1978
+ duration: params.duration,
1979
+ }));
1980
+ return () => {
1981
+ // No-op
1982
+ };
1983
+ }
1984
+ }
1985
+ /**
1986
+ * Subscribe to open interest cap updates
1987
+ * Zero additional network overhead - data comes from existing webData3 subscription
1988
+ *
1989
+ * @param params - The operation parameters.
1990
+ * @returns A cleanup function to remove the subscription.
1991
+ */
1992
+ subscribeToOICaps(params) {
1993
+ const provider = this.getActiveProviderOrNull();
1994
+ if (!provider) {
1995
+ return () => {
1996
+ // No-op: Provider not initialized
1997
+ };
1998
+ }
1999
+ try {
2000
+ return provider.subscribeToOICaps(params);
2001
+ }
2002
+ catch (error) {
2003
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.subscribeToOICaps'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'subscribeToOICaps', {
2004
+ accountId: params.accountId,
2005
+ }));
2006
+ return () => {
2007
+ // No-op
2008
+ };
2009
+ }
2010
+ }
2011
+ /**
2012
+ * Configure live data throttling
2013
+ *
2014
+ * @param config - The configuration object.
2015
+ */
2016
+ setLiveDataConfig(config) {
2017
+ try {
2018
+ const provider = this.getActiveProvider();
2019
+ provider.setLiveDataConfig(config);
2020
+ }
2021
+ catch (error) {
2022
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.setLiveDataConfig'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'setLiveDataConfig'));
2023
+ }
2024
+ }
2025
+ /**
2026
+ * Calculate trading fees for the active provider
2027
+ * Each provider implements its own fee structure
2028
+ *
2029
+ * @param params - The operation parameters.
2030
+ * @returns The fee calculation result for the trade.
2031
+ */
2032
+ async calculateFees(params) {
2033
+ const provider = this.getActiveProvider();
2034
+ const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'calculateFees');
2035
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").calculateFees({ provider, params, context });
2036
+ }
2037
+ /**
2038
+ * Disconnect provider and cleanup subscriptions
2039
+ * Call this when navigating away from Perps screens to prevent battery drain
2040
+ */
2041
+ async disconnect() {
2042
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnecting provider to cleanup subscriptions', {
2043
+ timestamp: new Date().toISOString(),
2044
+ });
2045
+ // Stop preload interval and messenger subscriptions first,
2046
+ // so no background work fires while we tear down providers.
2047
+ if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
2048
+ clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
2049
+ __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
2050
+ }
2051
+ if (__classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f")) {
2052
+ __classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f").call(this);
2053
+ __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, null, "f");
2054
+ }
2055
+ if (__classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f")) {
2056
+ __classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f").call(this);
2057
+ __classPrivateFieldSet(this, _PerpsController_accountChangeUnsubscribe, null, "f");
2058
+ }
2059
+ __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
2060
+ __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
2061
+ // Only disconnect the provider if we're initialized
2062
+ if (this.isInitialized && !this.isCurrentlyReinitializing()) {
2063
+ try {
2064
+ const provider = this.getActiveProvider();
2065
+ await provider.disconnect();
2066
+ }
2067
+ catch (error) {
2068
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.disconnect'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'disconnect'));
2069
+ }
2070
+ }
2071
+ // Clear stale reference so standalone reads don't route through old provider
2072
+ this.activeProviderInstance = null;
2073
+ // Cleanup cached standalone provider (if any) — awaited to prevent races
2074
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2075
+ // Note: Feature-flag subscription is NOT cleaned up here.
2076
+ // It is a controller-lifetime concern (set once in the constructor),
2077
+ // not a session-lifetime concern. Unsubscribing here would break
2078
+ // geo-blocking / HIP-3 flag propagation after disconnect → reconnect.
2079
+ // Reset initialization state to ensure proper reconnection
2080
+ this.isInitialized = false;
2081
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2082
+ }
2083
+ /**
2084
+ * Eligibility (Geo-Blocking)
2085
+ */
2086
+ /**
2087
+ * Fetch geo location
2088
+ *
2089
+ * Returned in Country or Country-Region format
2090
+ * Example: FR, DE, US-MI, CA-ON
2091
+ */
2092
+ /**
2093
+ * Refresh eligibility status
2094
+ */
2095
+ async refreshEligibility() {
2096
+ // Capture the current version before starting the async operation.
2097
+ // This prevents race conditions where stale eligibility checks
2098
+ // (started with fallback config) overwrite results from newer checks
2099
+ // (started with remote config after it was fetched).
2100
+ const versionAtStart = __classPrivateFieldGet(this, _PerpsController_blockedRegionListVersion, "f");
2101
+ try {
2102
+ // TODO: It would be good to have this location before we call this async function to avoid the race condition
2103
+ const isEligible = await __classPrivateFieldGet(this, _PerpsController_eligibilityService, "f").checkEligibility({
2104
+ blockedRegions: this.blockedRegionList.list,
2105
+ });
2106
+ // Only update state if the blocked region list hasn't changed while we were awaiting.
2107
+ // This prevents stale fallback-based eligibility checks from overwriting
2108
+ // results from remote-based checks.
2109
+ if (__classPrivateFieldGet(this, _PerpsController_blockedRegionListVersion, "f") !== versionAtStart) {
2110
+ return;
2111
+ }
2112
+ this.update((state) => {
2113
+ state.isEligible = isEligible;
2114
+ });
2115
+ }
2116
+ catch (error) {
2117
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.refreshEligibility'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'refreshEligibility'));
2118
+ // Only update on error if version is still current
2119
+ if (__classPrivateFieldGet(this, _PerpsController_blockedRegionListVersion, "f") === versionAtStart) {
2120
+ // Default to eligible on error
2121
+ this.update((state) => {
2122
+ state.isEligible = true;
2123
+ });
2124
+ }
2125
+ }
2126
+ }
2127
+ /**
2128
+ * Get block explorer URL for an address or just the base URL
2129
+ *
2130
+ * @param address - Optional address to append to the base URL
2131
+ * @returns Block explorer URL
2132
+ */
2133
+ getBlockExplorerUrl(address) {
2134
+ const provider = this.getActiveProvider();
2135
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getBlockExplorerUrl({ provider, address });
2136
+ }
2137
+ /**
2138
+ * Check if user is first-time for the current network
2139
+ *
2140
+ * @returns True if the condition is met.
2141
+ */
2142
+ isFirstTimeUserOnCurrentNetwork() {
2143
+ const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2144
+ return this.state.isFirstTimeUser[currentNetwork];
2145
+ }
2146
+ /**
2147
+ * Mark that the user has completed the tutorial/onboarding
2148
+ * This prevents the tutorial from showing again
2149
+ */
2150
+ markTutorialCompleted() {
2151
+ const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2152
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Marking tutorial as completed', {
2153
+ timestamp: new Date().toISOString(),
2154
+ network: currentNetwork,
2155
+ });
2156
+ this.update((state) => {
2157
+ state.isFirstTimeUser[currentNetwork] = false;
2158
+ });
2159
+ }
2160
+ /*
2161
+ * Mark that user has placed their first successful order
2162
+ * This prevents the notification tooltip from showing again
2163
+ */
2164
+ markFirstOrderCompleted() {
2165
+ const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2166
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Marking first order completed', {
2167
+ timestamp: new Date().toISOString(),
2168
+ network: currentNetwork,
2169
+ });
2170
+ this.update((state) => {
2171
+ state.hasPlacedFirstOrder[currentNetwork] = true;
2172
+ });
2173
+ }
2174
+ /**
2175
+ * Reset first-time user state for both networks
2176
+ * This is useful for testing the tutorial flow
2177
+ * Called by Reset Account feature in settings
2178
+ */
2179
+ resetFirstTimeUserState() {
2180
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Resetting first-time user state', {
2181
+ timestamp: new Date().toISOString(),
2182
+ previousState: this.state.isFirstTimeUser,
2183
+ });
2184
+ this.update((state) => {
2185
+ state.isFirstTimeUser = {
2186
+ testnet: true,
2187
+ mainnet: true,
2188
+ };
2189
+ state.hasPlacedFirstOrder = {
2190
+ testnet: false,
2191
+ mainnet: false,
2192
+ };
2193
+ });
2194
+ }
2195
+ /**
2196
+ * Clear pending/bridging withdrawal and deposit requests
2197
+ * This is useful when users want to clear stuck pending indicators
2198
+ * Called by Reset Account feature in settings
2199
+ */
2200
+ clearPendingTransactionRequests() {
2201
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Clearing pending transaction requests', {
2202
+ timestamp: new Date().toISOString(),
2203
+ });
2204
+ this.update((state) => {
2205
+ // Filter out pending/bridging withdrawals, keep completed/failed for history
2206
+ state.withdrawalRequests = state.withdrawalRequests.filter((req) => req.status !== 'pending' && req.status !== 'bridging');
2207
+ // Filter out pending deposits, keep completed/failed for history
2208
+ state.depositRequests = state.depositRequests.filter((req) => req.status !== 'pending' && req.status !== 'bridging');
2209
+ // Reset withdrawal progress
2210
+ state.withdrawalProgress = {
2211
+ progress: 0,
2212
+ lastUpdated: Date.now(),
2213
+ activeWithdrawalId: null,
2214
+ };
2215
+ });
2216
+ }
2217
+ /**
2218
+ * Get saved trade configuration for a market
2219
+ *
2220
+ * @param symbol - The trading pair symbol.
2221
+ * @returns The resulting string value.
2222
+ */
2223
+ getTradeConfiguration(symbol) {
2224
+ const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2225
+ const config = this.state.tradeConfigurations[network]?.[symbol];
2226
+ if (!config?.leverage) {
2227
+ return undefined;
2228
+ }
2229
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Retrieved trade config', {
2230
+ symbol,
2231
+ network,
2232
+ leverage: config.leverage,
2233
+ });
2234
+ return { leverage: config.leverage };
2235
+ }
2236
+ /**
2237
+ * Save trade configuration for a market
2238
+ *
2239
+ * @param symbol - Market symbol
2240
+ * @param leverage - Leverage value
2241
+ */
2242
+ saveTradeConfiguration(symbol, leverage) {
2243
+ const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2244
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Saving trade configuration', {
2245
+ symbol,
2246
+ network,
2247
+ leverage,
2248
+ timestamp: new Date().toISOString(),
2249
+ });
2250
+ this.update((state) => {
2251
+ if (!state.tradeConfigurations[network]) {
2252
+ state.tradeConfigurations[network] = {};
2253
+ }
2254
+ const existingConfig = state.tradeConfigurations[network][symbol] || {};
2255
+ state.tradeConfigurations[network][symbol] = {
2256
+ ...existingConfig,
2257
+ leverage,
2258
+ };
2259
+ });
2260
+ }
2261
+ /**
2262
+ * Save pending trade configuration for a market
2263
+ * This is a temporary configuration that expires after 5 minutes
2264
+ *
2265
+ * @param symbol - Market symbol
2266
+ * @param config - Pending trade configuration (includes optional selected payment token from Pay row)
2267
+ * @param config.amount - The amount value.
2268
+ * @param config.leverage - The leverage multiplier.
2269
+ * @param config.takeProfitPrice - The take profit price.
2270
+ * @param config.stopLossPrice - The stop loss price.
2271
+ * @param config.limitPrice - The limit price.
2272
+ * @param config.orderType - The order type.
2273
+ * @param config.selectedPaymentToken - The selected payment token.
2274
+ */
2275
+ savePendingTradeConfiguration(symbol, config) {
2276
+ const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2277
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Saving pending trade configuration', {
2278
+ symbol,
2279
+ network,
2280
+ config,
2281
+ timestamp: new Date().toISOString(),
2282
+ });
2283
+ this.update((state) => {
2284
+ if (!state.tradeConfigurations[network]) {
2285
+ state.tradeConfigurations[network] = {};
2286
+ }
2287
+ const existingConfig = state.tradeConfigurations[network][symbol] || {};
2288
+ state.tradeConfigurations[network][symbol] = {
2289
+ ...existingConfig,
2290
+ pendingConfig: {
2291
+ ...config,
2292
+ timestamp: Date.now(),
2293
+ },
2294
+ };
2295
+ });
2296
+ }
2297
+ /**
2298
+ * Get pending trade configuration for a market
2299
+ * Returns undefined if config doesn't exist or has expired (more than 5 minutes old)
2300
+ *
2301
+ * @param symbol - Market symbol
2302
+ * @returns Pending trade configuration or undefined
2303
+ */
2304
+ getPendingTradeConfiguration(symbol) {
2305
+ const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2306
+ const config = this.state.tradeConfigurations[network]?.[symbol]?.pendingConfig;
2307
+ if (!config) {
2308
+ return undefined;
2309
+ }
2310
+ // Check if config has expired (5 minutes = 300,000 milliseconds)
2311
+ const FIVE_MINUTES_MS = 5 * 60 * 1000;
2312
+ const now = Date.now();
2313
+ const age = now - config.timestamp;
2314
+ if (age > FIVE_MINUTES_MS) {
2315
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Pending trade config expired', {
2316
+ symbol,
2317
+ network,
2318
+ age,
2319
+ timestamp: config.timestamp,
2320
+ });
2321
+ // Clear expired config
2322
+ this.update((state) => {
2323
+ if (state.tradeConfigurations[network]?.[symbol]?.pendingConfig) {
2324
+ delete state.tradeConfigurations[network][symbol].pendingConfig;
2325
+ }
2326
+ });
2327
+ return undefined;
2328
+ }
2329
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Retrieved pending trade config', {
2330
+ symbol,
2331
+ network,
2332
+ config,
2333
+ age,
2334
+ });
2335
+ // Return config without timestamp
2336
+ const { timestamp, ...configWithoutTimestamp } = config;
2337
+ return configWithoutTimestamp;
2338
+ }
2339
+ /**
2340
+ * Clear pending trade configuration for a market
2341
+ *
2342
+ * @param symbol - Market symbol
2343
+ */
2344
+ clearPendingTradeConfiguration(symbol) {
2345
+ const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2346
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Clearing pending trade configuration', {
2347
+ symbol,
2348
+ network,
2349
+ timestamp: new Date().toISOString(),
2350
+ });
2351
+ this.update((state) => {
2352
+ if (state.tradeConfigurations[network]?.[symbol]?.pendingConfig) {
2353
+ delete state.tradeConfigurations[network][symbol].pendingConfig;
2354
+ }
2355
+ });
2356
+ }
2357
+ /**
2358
+ * Get saved market filter preferences
2359
+ * Handles backward compatibility with legacy string format
2360
+ *
2361
+ * @returns The saved sort option ID and direction.
2362
+ */
2363
+ getMarketFilterPreferences() {
2364
+ const pref = this.state.marketFilterPreferences;
2365
+ // Handle legacy string format (backward compatibility)
2366
+ if (typeof pref === 'string') {
2367
+ // Map legacy compound IDs to new format
2368
+ // Old format: 'priceChange-desc' or 'priceChange-asc'
2369
+ // New format: { optionId: 'priceChange', direction: 'desc'/'asc' }
2370
+ if (pref === 'priceChange-desc') {
2371
+ return {
2372
+ optionId: 'priceChange',
2373
+ direction: 'desc',
2374
+ };
2375
+ }
2376
+ if (pref === 'priceChange-asc') {
2377
+ return {
2378
+ optionId: 'priceChange',
2379
+ direction: 'asc',
2380
+ };
2381
+ }
2382
+ // Handle other simple legacy strings (e.g., 'volume', 'openInterest', etc.)
2383
+ return {
2384
+ optionId: pref,
2385
+ direction: perpsConfig_1.MARKET_SORTING_CONFIG.DefaultDirection,
2386
+ };
2387
+ }
2388
+ // Return new object format or default
2389
+ return (pref ?? {
2390
+ optionId: perpsConfig_1.MARKET_SORTING_CONFIG.DefaultSortOptionId,
2391
+ direction: perpsConfig_1.MARKET_SORTING_CONFIG.DefaultDirection,
2392
+ });
2393
+ }
2394
+ /**
2395
+ * Save market filter preferences
2396
+ *
2397
+ * @param optionId - Sort/filter option ID
2398
+ * @param direction - Sort direction ('asc' or 'desc')
2399
+ */
2400
+ saveMarketFilterPreferences(optionId, direction) {
2401
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Saving market filter preferences', {
2402
+ optionId,
2403
+ direction,
2404
+ timestamp: new Date().toISOString(),
2405
+ });
2406
+ this.update((state) => {
2407
+ state.marketFilterPreferences = { optionId, direction };
2408
+ });
2409
+ }
2410
+ /**
2411
+ * Set the selected payment token for the Perps order/deposit flow.
2412
+ * Pass null or a token with description PERPS_CONSTANTS.PerpsBalanceTokenDescription to select Perps balance.
2413
+ * Only required fields (address, chainId) are stored in state; description and symbol are optional.
2414
+ *
2415
+ * @param token - The token identifier.
2416
+ */
2417
+ setSelectedPaymentToken(token) {
2418
+ let normalized = null;
2419
+ if (token !== null &&
2420
+ token.description !== perpsConfig_1.PERPS_CONSTANTS.PerpsBalanceTokenDescription) {
2421
+ normalized = token;
2422
+ }
2423
+ const current = this.state.selectedPaymentToken;
2424
+ const initialPaymentMethod = current === null ||
2425
+ current === undefined ||
2426
+ current?.description === perpsConfig_1.PERPS_CONSTANTS.PerpsBalanceTokenDescription
2427
+ ? 'perps_balance'
2428
+ : (current?.symbol ?? 'unknown');
2429
+ const newPaymentMethod = token === null ||
2430
+ token.description === perpsConfig_1.PERPS_CONSTANTS.PerpsBalanceTokenDescription
2431
+ ? 'perps_balance'
2432
+ : (token.symbol ?? 'unknown');
2433
+ if (initialPaymentMethod !== newPaymentMethod) {
2434
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getMetrics).call(this).trackPerpsEvent(types_1.PerpsAnalyticsEvent.UiInteraction, {
2435
+ [eventNames_1.PERPS_EVENT_PROPERTY.INTERACTION_TYPE]: eventNames_1.PERPS_EVENT_VALUE.INTERACTION_TYPE.PAYMENT_METHOD_CHANGED,
2436
+ [eventNames_1.PERPS_EVENT_PROPERTY.INITIAL_PAYMENT_METHOD]: initialPaymentMethod,
2437
+ [eventNames_1.PERPS_EVENT_PROPERTY.NEW_PAYMENT_METHOD]: newPaymentMethod,
2438
+ });
2439
+ }
2440
+ let snapshot = null;
2441
+ if (normalized !== null) {
2442
+ snapshot = {
2443
+ ...(normalized.description !== undefined && {
2444
+ description: normalized.description,
2445
+ }),
2446
+ address: normalized.address,
2447
+ chainId: normalized.chainId,
2448
+ symbol: normalized.symbol,
2449
+ };
2450
+ }
2451
+ this.update((state) => {
2452
+ state.selectedPaymentToken = snapshot;
2453
+ });
2454
+ }
2455
+ /**
2456
+ * Reset the selected payment token to Perps balance (null).
2457
+ * Call when leaving the Perps order view so the next visit defaults to Perps balance.
2458
+ */
2459
+ resetSelectedPaymentToken() {
2460
+ this.update((state) => {
2461
+ state.selectedPaymentToken = null;
2462
+ });
2463
+ }
2464
+ /**
2465
+ * Get saved order book grouping for a market
2466
+ *
2467
+ * @param symbol - Market symbol
2468
+ * @returns The saved grouping value or undefined if not set
2469
+ */
2470
+ getOrderBookGrouping(symbol) {
2471
+ const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2472
+ const grouping = this.state.tradeConfigurations[network]?.[symbol]?.orderBookGrouping;
2473
+ if (grouping !== undefined) {
2474
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Retrieved order book grouping', {
2475
+ symbol,
2476
+ network,
2477
+ grouping,
2478
+ });
2479
+ }
2480
+ return grouping;
2481
+ }
2482
+ /**
2483
+ * Save order book grouping for a market
2484
+ *
2485
+ * @param symbol - Market symbol
2486
+ * @param grouping - Price grouping value
2487
+ */
2488
+ saveOrderBookGrouping(symbol, grouping) {
2489
+ const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2490
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Saving order book grouping', {
2491
+ symbol,
2492
+ network,
2493
+ grouping,
2494
+ timestamp: new Date().toISOString(),
2495
+ });
2496
+ this.update((state) => {
2497
+ if (!state.tradeConfigurations[network]) {
2498
+ state.tradeConfigurations[network] = {};
2499
+ }
2500
+ const existingConfig = state.tradeConfigurations[network][symbol] || {};
2501
+ state.tradeConfigurations[network][symbol] = {
2502
+ ...existingConfig,
2503
+ orderBookGrouping: grouping,
2504
+ };
2505
+ });
2506
+ }
2507
+ /**
2508
+ * Toggle watchlist status for a market
2509
+ * Watchlist markets are stored per network (testnet/mainnet)
2510
+ *
2511
+ * @param symbol - The trading pair symbol.
2512
+ */
2513
+ toggleWatchlistMarket(symbol) {
2514
+ const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2515
+ const currentWatchlist = this.state.watchlistMarkets[currentNetwork];
2516
+ const isWatchlisted = currentWatchlist.includes(symbol);
2517
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Toggling watchlist market', {
2518
+ timestamp: new Date().toISOString(),
2519
+ network: currentNetwork,
2520
+ symbol,
2521
+ action: isWatchlisted ? 'remove' : 'add',
2522
+ });
2523
+ this.update((state) => {
2524
+ if (isWatchlisted) {
2525
+ // Remove from watchlist
2526
+ state.watchlistMarkets[currentNetwork] = currentWatchlist.filter((marketSymbol) => marketSymbol !== symbol);
2527
+ }
2528
+ else {
2529
+ // Add to watchlist
2530
+ state.watchlistMarkets[currentNetwork] = [...currentWatchlist, symbol];
2531
+ }
2532
+ });
2533
+ }
2534
+ /**
2535
+ * Check if a market is in the watchlist on the current network
2536
+ *
2537
+ * @param symbol - The trading pair symbol.
2538
+ * @returns True if the condition is met.
2539
+ */
2540
+ isWatchlistMarket(symbol) {
2541
+ const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2542
+ return this.state.watchlistMarkets[currentNetwork].includes(symbol);
2543
+ }
2544
+ /**
2545
+ * Get all watchlist markets for the current network
2546
+ *
2547
+ * @returns The resulting string value.
2548
+ */
2549
+ getWatchlistMarkets() {
2550
+ const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2551
+ return this.state.watchlistMarkets[currentNetwork];
2552
+ }
2553
+ /**
2554
+ * Report order events to data lake API with retry (non-blocking)
2555
+ * Thin delegation to DataLakeService
2556
+ *
2557
+ * @param params - The operation parameters.
2558
+ * @param params.action - The order action.
2559
+ * @param params.symbol - The trading pair symbol.
2560
+ * @param params.slPrice - The stop loss price.
2561
+ * @param params.tpPrice - The take profit price.
2562
+ * @param params.retryCount - Internal retry counter.
2563
+ * @param params._traceId - Internal trace ID.
2564
+ * @returns Whether the report was sent successfully, with an optional error message.
2565
+ */
2566
+ async reportOrderToDataLake(params) {
2567
+ return __classPrivateFieldGet(this, _PerpsController_dataLakeService, "f").reportOrder({
2568
+ action: params.action,
2569
+ symbol: params.symbol,
2570
+ slPrice: params.slPrice,
2571
+ tpPrice: params.tpPrice,
2572
+ isTestnet: this.state.isTestnet,
2573
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'reportOrderToDataLake', {}),
2574
+ retryCount: params.retryCount,
2575
+ _traceId: params._traceId,
2576
+ });
2577
+ }
2578
+ /**
2579
+ * Check if the controller is currently reinitializing
2580
+ *
2581
+ * @returns true if providers are being reinitialized
2582
+ */
2583
+ isCurrentlyReinitializing() {
2584
+ return __classPrivateFieldGet(this, _PerpsController_isReinitializing, "f");
2585
+ }
25
2586
  }
26
- exports.getDefaultPerpsControllerState = getDefaultPerpsControllerState;
2587
+ exports.PerpsController = PerpsController;
2588
+ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _PerpsController_isReinitializing = new WeakMap(), _PerpsController_blockedRegionListVersion = new WeakMap(), _PerpsController_hip3Enabled = new WeakMap(), _PerpsController_hip3AllowlistMarkets = new WeakMap(), _PerpsController_hip3BlocklistMarkets = new WeakMap(), _PerpsController_hip3ConfigSource = new WeakMap(), _PerpsController_standaloneProvider = new WeakMap(), _PerpsController_standaloneProviderIsTestnet = new WeakMap(), _PerpsController_standaloneProviderHip3Version = new WeakMap(), _PerpsController_options = new WeakMap(), _PerpsController_tradingService = new WeakMap(), _PerpsController_marketDataService = new WeakMap(), _PerpsController_accountService = new WeakMap(), _PerpsController_eligibilityService = new WeakMap(), _PerpsController_dataLakeService = new WeakMap(), _PerpsController_depositService = new WeakMap(), _PerpsController_featureFlagConfigurationService = new WeakMap(), _PerpsController_rewardsIntegrationService = new WeakMap(), _PerpsController_preloadTimer = new WeakMap(), _PerpsController_isPreloading = new WeakMap(), _PerpsController_isPreloadingUserData = new WeakMap(), _PerpsController_preloadStateUnsubscribe = new WeakMap(), _PerpsController_accountChangeUnsubscribe = new WeakMap(), _PerpsController_previousIsTestnet = new WeakMap(), _PerpsController_previousHip3ConfigVersion = new WeakMap(), _PerpsController_instances = new WeakSet(), _PerpsController_isMYXProviderEnabled = function _PerpsController_isMYXProviderEnabled() {
2589
+ const getLocalFlag = () => typeof globalThis.process !== 'undefined' &&
2590
+ globalThis.process.env?.MM_PERPS_MYX_PROVIDER_ENABLED === 'true';
2591
+ try {
2592
+ const localFlag = getLocalFlag();
2593
+ const remoteState = this.messenger.call('RemoteFeatureFlagController:getState');
2594
+ const remoteFlag = remoteState.remoteFeatureFlags?.perpsMyxProviderEnabled;
2595
+ if ((0, types_1.isVersionGatedFeatureFlag)(remoteFlag)) {
2596
+ const validated = __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.featureFlags.validateVersionGated(remoteFlag);
2597
+ return validated ?? localFlag;
2598
+ }
2599
+ return localFlag;
2600
+ }
2601
+ catch {
2602
+ // If RemoteFeatureFlagController not ready, use fallback
2603
+ return getLocalFlag();
2604
+ }
2605
+ }, _PerpsController_logError = function _PerpsController_logError(error, options) {
2606
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.logger.error(error, options);
2607
+ }, _PerpsController_debugLog = function _PerpsController_debugLog(...args) {
2608
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.debugLogger.log(...args);
2609
+ }, _PerpsController_getOrCreateStandaloneProvider = function _PerpsController_getOrCreateStandaloneProvider() {
2610
+ const currentIsTestnet = this.state.isTestnet;
2611
+ const currentHip3Version = this.state.hip3ConfigVersion ?? 0;
2612
+ if (__classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f") &&
2613
+ __classPrivateFieldGet(this, _PerpsController_standaloneProviderIsTestnet, "f") === currentIsTestnet &&
2614
+ __classPrivateFieldGet(this, _PerpsController_standaloneProviderHip3Version, "f") === currentHip3Version) {
2615
+ return __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
2616
+ }
2617
+ // Stale or missing — tear down old one (fire-and-forget)
2618
+ if (__classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")) {
2619
+ const old = __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
2620
+ Promise.resolve(old.disconnect()).catch(() => {
2621
+ /* best-effort */
2622
+ });
2623
+ }
2624
+ __classPrivateFieldSet(this, _PerpsController_standaloneProvider, new HyperLiquidProvider_1.HyperLiquidProvider({
2625
+ isTestnet: currentIsTestnet,
2626
+ hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
2627
+ allowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
2628
+ blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
2629
+ platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2630
+ messenger: this.messenger,
2631
+ }), "f");
2632
+ __classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, currentIsTestnet, "f");
2633
+ __classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, currentHip3Version, "f");
2634
+ return __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
2635
+ }, _PerpsController_cleanupStandaloneProvider =
27
2636
  /**
28
- * `PerpsController` manages perpetual trading functionality in MetaMask.
29
- *
30
- * This controller provides platform-agnostic perps trading capabilities.
2637
+ * Disconnect and discard the cached standalone provider (if any).
2638
+ * Best-effort — errors are silently caught.
2639
+ */
2640
+ async function _PerpsController_cleanupStandaloneProvider() {
2641
+ if (!__classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")) {
2642
+ return;
2643
+ }
2644
+ try {
2645
+ await __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f").disconnect();
2646
+ }
2647
+ catch {
2648
+ /* best-effort */
2649
+ }
2650
+ __classPrivateFieldSet(this, _PerpsController_standaloneProvider, null, "f");
2651
+ __classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, null, "f");
2652
+ __classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, null, "f");
2653
+ }, _PerpsController_getMetrics = function _PerpsController_getMetrics() {
2654
+ return __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.metrics;
2655
+ }, _PerpsController_findNetworkClientIdForChain = function _PerpsController_findNetworkClientIdForChain(chainId) {
2656
+ return this.messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
2657
+ }, _PerpsController_submitTransaction =
2658
+ /**
2659
+ * Submit a transaction via messenger (shows confirmation screen)
31
2660
  *
32
- * @example
2661
+ * @param txParams - The transaction parameters.
2662
+ * @param txParams.from - The sender address.
2663
+ * @param txParams.to - The recipient address.
2664
+ * @param txParams.value - The transaction value.
2665
+ * @param txParams.data - The transaction data payload.
2666
+ * @param txParams.gas - The gas limit.
2667
+ * @param options - The configuration options.
2668
+ * @param options.networkClientId - The network client identifier.
2669
+ * @param options.origin - The transaction origin.
2670
+ * @param options.type - The transaction type.
2671
+ * @param options.skipInitialGasEstimate - Whether to skip initial gas estimation.
2672
+ * @returns The transaction result containing a hash promise and transaction metadata.
2673
+ */
2674
+ async function _PerpsController_submitTransaction(txParams, options) {
2675
+ // Cast needed: PerpsController uses loose string types for txParams/options
2676
+ // while TransactionController uses strict branded types (TransactionParams, AddTransactionOptions)
2677
+ return this.messenger.call('TransactionController:addTransaction',
2678
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2679
+ txParams,
2680
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2681
+ options);
2682
+ }, _PerpsController_migrateRequestsIfNeeded = function _PerpsController_migrateRequestsIfNeeded() {
2683
+ this.update((state) => {
2684
+ // Remove withdrawal requests without accountAddress - they can't be attributed to any account
2685
+ state.withdrawalRequests = state.withdrawalRequests.filter((req) => Boolean(req.accountAddress));
2686
+ // Remove deposit requests without accountAddress - they can't be attributed to any account
2687
+ state.depositRequests = state.depositRequests.filter((req) => Boolean(req.accountAddress));
2688
+ });
2689
+ }, _PerpsController_withStreamPause =
2690
+ /**
2691
+ * Execute an operation while temporarily pausing specified stream channels
2692
+ * to prevent WebSocket updates from triggering UI re-renders during operations.
33
2693
  *
34
- * ``` ts
35
- * import { Messenger } from '@metamask/messenger';
36
- * import type {
37
- * PerpsControllerActions,
38
- * PerpsControllerEvents,
39
- * } from '@metamask/perps-controller';
40
- * import { PerpsController } from '@metamask/perps-controller';
2694
+ * WebSocket connections remain alive but updates are not emitted to subscribers.
2695
+ * This prevents race conditions where UI re-renders fetch stale data during operations.
41
2696
  *
42
- * const rootMessenger = new Messenger<
43
- * 'Root',
44
- * PerpsControllerActions,
45
- * PerpsControllerEvents
46
- * >({ namespace: 'Root' });
47
- * const perpsControllerMessenger = new Messenger<
48
- * 'PerpsController',
49
- * PerpsControllerActions,
50
- * PerpsControllerEvents,
51
- * typeof rootMessenger,
52
- * >({
53
- * namespace: 'PerpsController',
54
- * parent: rootMessenger,
55
- * });
56
- * // Instantiate the controller to register its actions on the messenger
57
- * new PerpsController({
58
- * messenger: perpsControllerMessenger,
59
- * });
2697
+ * @param operation - The async operation to execute
2698
+ * @param channels - Array of stream channel names to pause
2699
+ * @returns The result of the operation
2700
+ * @example
2701
+ * ```typescript
2702
+ * // Cancel orders without stream interference
2703
+ * await this.#withStreamPause(
2704
+ * async () => this.provider.cancelOrders({ cancelAll: true }),
2705
+ * ['orders']
2706
+ * );
60
2707
  *
61
- * const perpsControllerState = await rootMessenger.call(
62
- * 'PerpsController:getState',
2708
+ * // Close positions and pause multiple streams
2709
+ * await this.#withStreamPause(
2710
+ * async () => this.provider.closePositions(positions),
2711
+ * ['positions', 'account', 'orders']
63
2712
  * );
64
2713
  * ```
65
2714
  */
66
- class PerpsController extends base_controller_1.BaseController {
67
- /**
68
- * Constructs a new {@link PerpsController}.
69
- *
70
- * @param args - The arguments to this controller.
71
- * @param args.messenger - The messenger suited for this controller.
72
- * @param args.state - The desired state with which to initialize this
73
- * controller. Missing properties will be filled in with defaults.
74
- */
75
- constructor({ messenger, state, }) {
76
- super({
77
- messenger,
78
- metadata: perpsControllerMetadata,
79
- name: exports.controllerName,
80
- state: {
81
- ...getDefaultPerpsControllerState(),
82
- ...state,
2715
+ async function _PerpsController_withStreamPause(operation, channels) {
2716
+ const pausedChannels = [];
2717
+ const { streamManager } = __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure;
2718
+ // Pause emission on specified channels (WebSocket stays connected)
2719
+ // Track which channels successfully paused to ensure proper cleanup
2720
+ for (const channel of channels) {
2721
+ try {
2722
+ streamManager.pauseChannel(channel);
2723
+ pausedChannels.push(channel);
2724
+ }
2725
+ catch (error) {
2726
+ // Log error to Sentry but continue pausing remaining channels
2727
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.withStreamPause'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'withStreamPause', {
2728
+ operation: 'pause',
2729
+ channel: String(channel),
2730
+ pausedChannels: pausedChannels.join(','),
2731
+ }));
2732
+ }
2733
+ }
2734
+ try {
2735
+ // Execute operation without stream interference
2736
+ return await operation();
2737
+ }
2738
+ finally {
2739
+ // Resume only channels that were successfully paused
2740
+ for (const channel of pausedChannels) {
2741
+ try {
2742
+ streamManager.resumeChannel(channel);
2743
+ }
2744
+ catch (error) {
2745
+ // Log error to Sentry but continue resuming remaining channels
2746
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.withStreamPause'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'withStreamPause', {
2747
+ operation: 'resume',
2748
+ channel: String(channel),
2749
+ pausedChannels: pausedChannels.join(','),
2750
+ }));
2751
+ }
2752
+ }
2753
+ }
2754
+ }, _PerpsController_performInitialization =
2755
+ /**
2756
+ * Actual initialization implementation with retry logic
2757
+ */
2758
+ async function _PerpsController_performInitialization() {
2759
+ const maxAttempts = 3;
2760
+ const baseDelay = 1000;
2761
+ this.update((state) => {
2762
+ state.initializationState = InitializationState.Initializing;
2763
+ state.initializationError = null;
2764
+ state.initializationAttempts = 0;
2765
+ });
2766
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Initializing providers', {
2767
+ currentNetwork: this.state.isTestnet ? 'testnet' : 'mainnet',
2768
+ existingProviders: Array.from(this.providers.keys()),
2769
+ timestamp: new Date().toISOString(),
2770
+ });
2771
+ let lastError = null;
2772
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
2773
+ try {
2774
+ this.update((state) => {
2775
+ state.initializationAttempts = attempt;
2776
+ });
2777
+ // Disconnect existing providers to close WebSocket connections
2778
+ const existingProviders = Array.from(this.providers.values());
2779
+ if (existingProviders.length > 0) {
2780
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnecting existing providers', {
2781
+ count: existingProviders.length,
2782
+ timestamp: new Date().toISOString(),
2783
+ });
2784
+ await Promise.all(existingProviders.map((provider) => provider.disconnect()));
2785
+ }
2786
+ this.providers.clear();
2787
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2788
+ const { activeProvider } = this.state;
2789
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Creating provider with HIP-3 configuration', {
2790
+ hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
2791
+ hip3AllowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
2792
+ hip3BlocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
2793
+ hip3ConfigSource: __classPrivateFieldGet(this, _PerpsController_hip3ConfigSource, "f"),
2794
+ isTestnet: this.state.isTestnet,
2795
+ activeProvider,
2796
+ });
2797
+ // Always create HyperLiquid provider as the base provider
2798
+ const hyperLiquidProvider = new HyperLiquidProvider_1.HyperLiquidProvider({
2799
+ isTestnet: this.state.isTestnet,
2800
+ hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
2801
+ allowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
2802
+ blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
2803
+ platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2804
+ messenger: this.messenger,
2805
+ });
2806
+ this.providers.set('hyperliquid', hyperLiquidProvider);
2807
+ // Register MYX provider if enabled via feature flag
2808
+ const isMYXEnabled = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMYXProviderEnabled).call(this);
2809
+ if (isMYXEnabled) {
2810
+ const myxProvider = new MYXProvider_1.MYXProvider({
2811
+ isTestnet: perpsConfig_1.PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet,
2812
+ platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2813
+ });
2814
+ this.providers.set('myx', myxProvider);
2815
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider registered', {
2816
+ isTestnet: perpsConfig_1.PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet,
2817
+ });
2818
+ }
2819
+ // Set up active provider based on activeProvider value in state
2820
+ // 'aggregated' is treated as just another provider that wraps others
2821
+ if (activeProvider === 'aggregated') {
2822
+ // Aggregated mode: wrap in AggregatedPerpsProvider for multi-provider support
2823
+ this.activeProviderInstance = new AggregatedPerpsProvider_1.AggregatedPerpsProvider({
2824
+ providers: this.providers,
2825
+ defaultProvider: 'hyperliquid',
2826
+ infrastructure: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2827
+ });
2828
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Using aggregated provider (multi-provider)', { registeredProviders: Array.from(this.providers.keys()) });
2829
+ }
2830
+ else if (activeProvider === 'hyperliquid') {
2831
+ // Direct provider mode: use HyperLiquid provider directly
2832
+ this.activeProviderInstance = hyperLiquidProvider;
2833
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${activeProvider})`);
2834
+ }
2835
+ else if (activeProvider === 'myx') {
2836
+ // MYX provider mode
2837
+ const myxProvider = this.providers.get('myx');
2838
+ if (myxProvider) {
2839
+ this.activeProviderInstance = myxProvider;
2840
+ }
2841
+ else {
2842
+ // MYX feature flag is disabled — fall back to HyperLiquid
2843
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider not available (feature flag disabled), falling back to hyperliquid');
2844
+ this.activeProviderInstance = hyperLiquidProvider;
2845
+ this.update((state) => {
2846
+ state.activeProvider = 'hyperliquid';
2847
+ });
2848
+ }
2849
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${this.activeProviderInstance === hyperLiquidProvider ? 'hyperliquid' : activeProvider})`);
2850
+ }
2851
+ else {
2852
+ // Unsupported provider - throw error to prevent silent misconfiguration
2853
+ throw new Error(`Unsupported provider: ${String(activeProvider)}. Currently only 'hyperliquid', 'myx', and 'aggregated' are supported.`);
2854
+ }
2855
+ // Future providers can be added here with their own authentication patterns:
2856
+ // - Some might use API keys: new BinanceProvider({ apiKey, apiSecret })
2857
+ // - Some might use different wallet patterns: new GMXProvider({ signer })
2858
+ // - Some might not need auth at all: new DydxProvider()
2859
+ // Wait for WebSocket transport to be ready before marking as initialized
2860
+ await (0, wait_1.wait)(perpsConfig_1.PERPS_CONSTANTS.ReconnectionCleanupDelayMs);
2861
+ this.isInitialized = true;
2862
+ this.update((state) => {
2863
+ state.initializationState = InitializationState.Initialized;
2864
+ state.initializationError = null;
2865
+ });
2866
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Providers initialized successfully', {
2867
+ providerCount: this.providers.size,
2868
+ activeProvider,
2869
+ timestamp: new Date().toISOString(),
2870
+ attempts: attempt,
2871
+ });
2872
+ return; // Exit retry loop on success
2873
+ }
2874
+ catch (error) {
2875
+ lastError = (0, errorUtils_1.ensureError)(error, 'PerpsController.performInitialization');
2876
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, lastError, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'performInitialization', {
2877
+ attempt,
2878
+ maxAttempts,
2879
+ }));
2880
+ // If not the last attempt, wait before retrying (exponential backoff)
2881
+ if (attempt < maxAttempts) {
2882
+ const delay = baseDelay * Math.pow(2, attempt - 1); // 1s, 2s, 4s
2883
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Retrying initialization in ${delay}ms`, {
2884
+ attempt,
2885
+ maxAttempts,
2886
+ error: lastError.message,
2887
+ });
2888
+ await (0, wait_1.wait)(delay);
2889
+ }
2890
+ }
2891
+ }
2892
+ this.isInitialized = false;
2893
+ this.update((state) => {
2894
+ state.initializationState = InitializationState.Failed;
2895
+ state.initializationError = lastError?.message ?? 'Unknown error';
2896
+ });
2897
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f"); // Clear promise to allow retry
2898
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Initialization failed', {
2899
+ error: lastError?.message,
2900
+ attempts: maxAttempts,
2901
+ timestamp: new Date().toISOString(),
2902
+ });
2903
+ }, _PerpsController_getErrorContext = function _PerpsController_getErrorContext(method, extra) {
2904
+ return {
2905
+ tags: {
2906
+ feature: perpsConfig_1.PERPS_CONSTANTS.FeatureName,
2907
+ provider: this.state.activeProvider,
2908
+ network: this.state.isTestnet ? 'testnet' : 'mainnet',
2909
+ },
2910
+ context: {
2911
+ name: 'PerpsController',
2912
+ data: {
2913
+ method,
2914
+ ...extra,
83
2915
  },
2916
+ },
2917
+ };
2918
+ }, _PerpsController_getControllerState = function _PerpsController_getControllerState() {
2919
+ return this.state;
2920
+ }, _PerpsController_createServiceContext = function _PerpsController_createServiceContext(method, additionalContext) {
2921
+ return {
2922
+ tracingContext: {
2923
+ provider: this.state.activeProvider,
2924
+ isTestnet: this.state.isTestnet,
2925
+ },
2926
+ errorContext: {
2927
+ controller: 'PerpsController',
2928
+ method,
2929
+ },
2930
+ stateManager: {
2931
+ update: (updater) =>
2932
+ // @ts-expect-error TS2589 - excessively deep instantiation when inferring stateManager from BaseController
2933
+ this.update(updater),
2934
+ getState: () => __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getControllerState).call(this),
2935
+ },
2936
+ ...additionalContext,
2937
+ };
2938
+ }, _PerpsController_ensureTradingServiceDeps = function _PerpsController_ensureTradingServiceDeps() {
2939
+ __classPrivateFieldGet(this, _PerpsController_tradingService, "f").setControllerDependencies({
2940
+ rewardsIntegrationService: __classPrivateFieldGet(this, _PerpsController_rewardsIntegrationService, "f"),
2941
+ });
2942
+ }, _PerpsController_performMarketDataPreload =
2943
+ /**
2944
+ * Perform a single market data preload (best-effort, no throw).
2945
+ */
2946
+ async function _PerpsController_performMarketDataPreload() {
2947
+ if (__classPrivateFieldGet(this, _PerpsController_isPreloading, "f")) {
2948
+ return;
2949
+ }
2950
+ const now = Date.now();
2951
+ if (now - this.state.cachedMarketDataTimestamp <
2952
+ __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
2953
+ return;
2954
+ }
2955
+ __classPrivateFieldSet(this, _PerpsController_isPreloading, true, "f");
2956
+ const traceId = (0, uuid_1.v4)();
2957
+ const preloadStart = performance.now();
2958
+ let traceData;
2959
+ try {
2960
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.trace({
2961
+ name: types_1.PerpsTraceNames.MarketDataPreload,
2962
+ id: traceId,
2963
+ op: types_1.PerpsTraceOperations.Operation,
2964
+ tags: {
2965
+ provider: this.state.activeProvider,
2966
+ isTestnet: this.state.isTestnet,
2967
+ },
2968
+ });
2969
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching market data in background');
2970
+ const data = await this.getMarketDataWithPrices({ standalone: true });
2971
+ this.update((state) => {
2972
+ state.cachedMarketData = data;
2973
+ state.cachedMarketDataTimestamp = Date.now();
2974
+ });
2975
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Market data preloaded', {
2976
+ marketCount: data.length,
2977
+ });
2978
+ traceData = { success: true, marketCount: data.length };
2979
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.setMeasurement(performanceMetrics_1.PerpsMeasurementName.PerpsMarketDataPreload, performance.now() - preloadStart, 'millisecond');
2980
+ // Also preload user data (fire-and-forget, non-blocking)
2981
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
2982
+ /* fire-and-forget */
84
2983
  });
85
2984
  }
86
- }
87
- exports.PerpsController = PerpsController;
2985
+ catch (error) {
2986
+ traceData = {
2987
+ success: false,
2988
+ error: (0, errorUtils_1.ensureError)(error, 'PerpsController.performMarketDataPreload')
2989
+ .message,
2990
+ };
2991
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.performMarketDataPreload'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'performMarketDataPreload', {
2992
+ message: 'Background preload failed',
2993
+ }));
2994
+ }
2995
+ finally {
2996
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.endTrace({
2997
+ name: types_1.PerpsTraceNames.MarketDataPreload,
2998
+ id: traceId,
2999
+ data: traceData,
3000
+ });
3001
+ __classPrivateFieldSet(this, _PerpsController_isPreloading, false, "f");
3002
+ }
3003
+ }, _PerpsController_performUserDataPreload =
3004
+ /**
3005
+ * Perform a single user data preload (best-effort, no throw).
3006
+ * Fetches positions, open orders, and account state via lightweight REST calls.
3007
+ */
3008
+ async function _PerpsController_performUserDataPreload() {
3009
+ if (__classPrivateFieldGet(this, _PerpsController_isPreloadingUserData, "f")) {
3010
+ return;
3011
+ }
3012
+ // Get current user address
3013
+ const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
3014
+ if (!evmAccount?.address) {
3015
+ return;
3016
+ }
3017
+ const userAddress = evmAccount.address;
3018
+ // Skip if cache is fresh and for same account
3019
+ const now = Date.now();
3020
+ if (this.state.cachedUserDataAddress === userAddress &&
3021
+ now - this.state.cachedUserDataTimestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
3022
+ return;
3023
+ }
3024
+ // Skip standalone REST polling when WebSocket is connected — live data is streaming
3025
+ if (this.getWebSocketConnectionState() === types_1.WebSocketConnectionState.Connected) {
3026
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Skipping user data preload — WebSocket connected');
3027
+ return;
3028
+ }
3029
+ __classPrivateFieldSet(this, _PerpsController_isPreloadingUserData, true, "f");
3030
+ const traceId = (0, uuid_1.v4)();
3031
+ const preloadStart = performance.now();
3032
+ let traceData;
3033
+ try {
3034
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.trace({
3035
+ name: types_1.PerpsTraceNames.UserDataPreload,
3036
+ id: traceId,
3037
+ op: types_1.PerpsTraceOperations.Operation,
3038
+ tags: {
3039
+ provider: this.state.activeProvider,
3040
+ isTestnet: this.state.isTestnet,
3041
+ },
3042
+ data: { userAddress },
3043
+ });
3044
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching user data in background', {
3045
+ userAddress,
3046
+ });
3047
+ const [positions, orders, accountState] = await Promise.all([
3048
+ this.getPositions({ standalone: true, userAddress }),
3049
+ this.getOpenOrders({ standalone: true, userAddress }),
3050
+ this.getAccountState({ standalone: true, userAddress }),
3051
+ ]);
3052
+ this.update((state) => {
3053
+ state.cachedPositions = positions;
3054
+ state.cachedOrders = orders;
3055
+ state.cachedAccountState = accountState;
3056
+ state.cachedUserDataTimestamp = Date.now();
3057
+ state.cachedUserDataAddress = userAddress;
3058
+ });
3059
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
3060
+ positionCount: positions.length,
3061
+ orderCount: orders.length,
3062
+ totalBalance: accountState.totalBalance,
3063
+ });
3064
+ traceData = {
3065
+ success: true,
3066
+ positionCount: positions.length,
3067
+ orderCount: orders.length,
3068
+ };
3069
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.setMeasurement(performanceMetrics_1.PerpsMeasurementName.PerpsUserDataPreload, performance.now() - preloadStart, 'millisecond');
3070
+ }
3071
+ catch (error) {
3072
+ traceData = {
3073
+ success: false,
3074
+ error: (0, errorUtils_1.ensureError)(error, 'PerpsController.performUserDataPreload')
3075
+ .message,
3076
+ };
3077
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_1.ensureError)(error, 'PerpsController.performUserDataPreload'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'performUserDataPreload', {
3078
+ message: 'Background user data preload failed',
3079
+ }));
3080
+ }
3081
+ finally {
3082
+ __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.endTrace({
3083
+ name: types_1.PerpsTraceNames.UserDataPreload,
3084
+ id: traceId,
3085
+ data: traceData,
3086
+ });
3087
+ __classPrivateFieldSet(this, _PerpsController_isPreloadingUserData, false, "f");
3088
+ }
3089
+ };
3090
+ // ============================================================================
3091
+ // Market Data Preload (client-agnostic background caching)
3092
+ // ============================================================================
3093
+ /** State paths that the preload stateChange handler reads. */
3094
+ _PerpsController_preloadWatchedPaths = { value: new Set([
3095
+ 'isTestnet',
3096
+ 'hip3ConfigVersion',
3097
+ ]) };
3098
+ _PerpsController_preloadRefreshMs = { value: 5 * 60 * 1000 }; // 5 min
3099
+ _PerpsController_preloadGuardMs = { value: 30000 }; // 30s debounce
88
3100
  //# sourceMappingURL=PerpsController.cjs.map