@metamask-previews/perps-controller 0.0.0-preview-e4aa1532 → 0.0.0-preview-6dfa4aeba

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 (498) hide show
  1. package/CHANGELOG.md +1 -11
  2. package/dist/PerpsController.cjs +66 -2224
  3. package/dist/PerpsController.cjs.map +1 -1
  4. package/dist/PerpsController.d.cts +79 -933
  5. package/dist/PerpsController.d.cts.map +1 -1
  6. package/dist/PerpsController.d.mts +79 -933
  7. package/dist/PerpsController.d.mts.map +1 -1
  8. package/dist/PerpsController.mjs +64 -2221
  9. package/dist/PerpsController.mjs.map +1 -1
  10. package/dist/index.cjs +1 -32
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +2 -6
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.mts +2 -6
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +1 -9
  17. package/dist/index.mjs.map +1 -1
  18. package/package.json +4 -19
  19. package/dist/__mocks__/hyperliquidMock.cjs +0 -68
  20. package/dist/__mocks__/hyperliquidMock.cjs.map +0 -1
  21. package/dist/__mocks__/hyperliquidMock.d.cts +0 -15
  22. package/dist/__mocks__/hyperliquidMock.d.cts.map +0 -1
  23. package/dist/__mocks__/hyperliquidMock.d.mts +0 -15
  24. package/dist/__mocks__/hyperliquidMock.d.mts.map +0 -1
  25. package/dist/__mocks__/hyperliquidMock.mjs +0 -65
  26. package/dist/__mocks__/hyperliquidMock.mjs.map +0 -1
  27. package/dist/__mocks__/providerMocks.cjs +0 -144
  28. package/dist/__mocks__/providerMocks.cjs.map +0 -1
  29. package/dist/__mocks__/providerMocks.d.cts +0 -44
  30. package/dist/__mocks__/providerMocks.d.cts.map +0 -1
  31. package/dist/__mocks__/providerMocks.d.mts +0 -44
  32. package/dist/__mocks__/providerMocks.d.mts.map +0 -1
  33. package/dist/__mocks__/providerMocks.mjs +0 -136
  34. package/dist/__mocks__/providerMocks.mjs.map +0 -1
  35. package/dist/__mocks__/serviceMocks.cjs +0 -187
  36. package/dist/__mocks__/serviceMocks.cjs.map +0 -1
  37. package/dist/__mocks__/serviceMocks.d.cts +0 -58
  38. package/dist/__mocks__/serviceMocks.d.cts.map +0 -1
  39. package/dist/__mocks__/serviceMocks.d.mts +0 -58
  40. package/dist/__mocks__/serviceMocks.d.mts.map +0 -1
  41. package/dist/__mocks__/serviceMocks.mjs +0 -180
  42. package/dist/__mocks__/serviceMocks.mjs.map +0 -1
  43. package/dist/aggregation/SubscriptionMultiplexer.cjs +0 -459
  44. package/dist/aggregation/SubscriptionMultiplexer.cjs.map +0 -1
  45. package/dist/aggregation/SubscriptionMultiplexer.d.cts +0 -222
  46. package/dist/aggregation/SubscriptionMultiplexer.d.cts.map +0 -1
  47. package/dist/aggregation/SubscriptionMultiplexer.d.mts +0 -222
  48. package/dist/aggregation/SubscriptionMultiplexer.d.mts.map +0 -1
  49. package/dist/aggregation/SubscriptionMultiplexer.mjs +0 -455
  50. package/dist/aggregation/SubscriptionMultiplexer.mjs.map +0 -1
  51. package/dist/aggregation/index.cjs +0 -9
  52. package/dist/aggregation/index.cjs.map +0 -1
  53. package/dist/aggregation/index.d.cts +0 -6
  54. package/dist/aggregation/index.d.cts.map +0 -1
  55. package/dist/aggregation/index.d.mts +0 -6
  56. package/dist/aggregation/index.d.mts.map +0 -1
  57. package/dist/aggregation/index.mjs +0 -5
  58. package/dist/aggregation/index.mjs.map +0 -1
  59. package/dist/constants/eventNames.cjs +0 -117
  60. package/dist/constants/eventNames.cjs.map +0 -1
  61. package/dist/constants/eventNames.d.cts +0 -106
  62. package/dist/constants/eventNames.d.cts.map +0 -1
  63. package/dist/constants/eventNames.d.mts +0 -106
  64. package/dist/constants/eventNames.d.mts.map +0 -1
  65. package/dist/constants/eventNames.mjs +0 -114
  66. package/dist/constants/eventNames.mjs.map +0 -1
  67. package/dist/constants/hyperLiquidConfig.cjs +0 -366
  68. package/dist/constants/hyperLiquidConfig.cjs.map +0 -1
  69. package/dist/constants/hyperLiquidConfig.d.cts +0 -276
  70. package/dist/constants/hyperLiquidConfig.d.cts.map +0 -1
  71. package/dist/constants/hyperLiquidConfig.d.mts +0 -276
  72. package/dist/constants/hyperLiquidConfig.d.mts.map +0 -1
  73. package/dist/constants/hyperLiquidConfig.mjs +0 -357
  74. package/dist/constants/hyperLiquidConfig.mjs.map +0 -1
  75. package/dist/constants/index.cjs +0 -23
  76. package/dist/constants/index.cjs.map +0 -1
  77. package/dist/constants/index.d.cts +0 -7
  78. package/dist/constants/index.d.cts.map +0 -1
  79. package/dist/constants/index.d.mts +0 -7
  80. package/dist/constants/index.d.mts.map +0 -1
  81. package/dist/constants/index.mjs +0 -7
  82. package/dist/constants/index.mjs.map +0 -1
  83. package/dist/constants/orderTypes.cjs +0 -31
  84. package/dist/constants/orderTypes.cjs.map +0 -1
  85. package/dist/constants/orderTypes.d.cts +0 -19
  86. package/dist/constants/orderTypes.d.cts.map +0 -1
  87. package/dist/constants/orderTypes.d.mts +0 -19
  88. package/dist/constants/orderTypes.d.mts.map +0 -1
  89. package/dist/constants/orderTypes.mjs +0 -27
  90. package/dist/constants/orderTypes.mjs.map +0 -1
  91. package/dist/constants/performanceMetrics.cjs +0 -61
  92. package/dist/constants/performanceMetrics.cjs.map +0 -1
  93. package/dist/constants/performanceMetrics.d.cts +0 -44
  94. package/dist/constants/performanceMetrics.d.cts.map +0 -1
  95. package/dist/constants/performanceMetrics.d.mts +0 -44
  96. package/dist/constants/performanceMetrics.d.mts.map +0 -1
  97. package/dist/constants/performanceMetrics.mjs +0 -58
  98. package/dist/constants/performanceMetrics.mjs.map +0 -1
  99. package/dist/constants/perpsConfig.cjs +0 -461
  100. package/dist/constants/perpsConfig.cjs.map +0 -1
  101. package/dist/constants/perpsConfig.d.cts +0 -343
  102. package/dist/constants/perpsConfig.d.cts.map +0 -1
  103. package/dist/constants/perpsConfig.d.mts +0 -343
  104. package/dist/constants/perpsConfig.d.mts.map +0 -1
  105. package/dist/constants/perpsConfig.mjs +0 -458
  106. package/dist/constants/perpsConfig.mjs.map +0 -1
  107. package/dist/constants/perpsErrorCodes.cjs +0 -79
  108. package/dist/constants/perpsErrorCodes.cjs.map +0 -1
  109. package/dist/constants/perpsErrorCodes.d.cts +0 -64
  110. package/dist/constants/perpsErrorCodes.d.cts.map +0 -1
  111. package/dist/constants/perpsErrorCodes.d.mts +0 -64
  112. package/dist/constants/perpsErrorCodes.d.mts.map +0 -1
  113. package/dist/constants/perpsErrorCodes.mjs +0 -76
  114. package/dist/constants/perpsErrorCodes.mjs.map +0 -1
  115. package/dist/platform-services/HyperLiquidClientService.cjs +0 -857
  116. package/dist/platform-services/HyperLiquidClientService.cjs.map +0 -1
  117. package/dist/platform-services/HyperLiquidClientService.d.cts +0 -263
  118. package/dist/platform-services/HyperLiquidClientService.d.cts.map +0 -1
  119. package/dist/platform-services/HyperLiquidClientService.d.mts +0 -263
  120. package/dist/platform-services/HyperLiquidClientService.d.mts.map +0 -1
  121. package/dist/platform-services/HyperLiquidClientService.mjs +0 -853
  122. package/dist/platform-services/HyperLiquidClientService.mjs.map +0 -1
  123. package/dist/platform-services/HyperLiquidSubscriptionService.cjs +0 -2170
  124. package/dist/platform-services/HyperLiquidSubscriptionService.cjs.map +0 -1
  125. package/dist/platform-services/HyperLiquidSubscriptionService.d.cts +0 -424
  126. package/dist/platform-services/HyperLiquidSubscriptionService.d.cts.map +0 -1
  127. package/dist/platform-services/HyperLiquidSubscriptionService.d.mts +0 -424
  128. package/dist/platform-services/HyperLiquidSubscriptionService.d.mts.map +0 -1
  129. package/dist/platform-services/HyperLiquidSubscriptionService.mjs +0 -2166
  130. package/dist/platform-services/HyperLiquidSubscriptionService.mjs.map +0 -1
  131. package/dist/platform-services/HyperLiquidWalletService.cjs +0 -140
  132. package/dist/platform-services/HyperLiquidWalletService.cjs.map +0 -1
  133. package/dist/platform-services/HyperLiquidWalletService.d.cts +0 -78
  134. package/dist/platform-services/HyperLiquidWalletService.d.cts.map +0 -1
  135. package/dist/platform-services/HyperLiquidWalletService.d.mts +0 -78
  136. package/dist/platform-services/HyperLiquidWalletService.d.mts.map +0 -1
  137. package/dist/platform-services/HyperLiquidWalletService.mjs +0 -136
  138. package/dist/platform-services/HyperLiquidWalletService.mjs.map +0 -1
  139. package/dist/providers/AggregatedPerpsProvider.cjs +0 -777
  140. package/dist/providers/AggregatedPerpsProvider.cjs.map +0 -1
  141. package/dist/providers/AggregatedPerpsProvider.d.cts +0 -466
  142. package/dist/providers/AggregatedPerpsProvider.d.cts.map +0 -1
  143. package/dist/providers/AggregatedPerpsProvider.d.mts +0 -466
  144. package/dist/providers/AggregatedPerpsProvider.d.mts.map +0 -1
  145. package/dist/providers/AggregatedPerpsProvider.mjs +0 -773
  146. package/dist/providers/AggregatedPerpsProvider.mjs.map +0 -1
  147. package/dist/providers/HyperLiquidProvider.cjs +0 -5172
  148. package/dist/providers/HyperLiquidProvider.cjs.map +0 -1
  149. package/dist/providers/HyperLiquidProvider.d.cts +0 -881
  150. package/dist/providers/HyperLiquidProvider.d.cts.map +0 -1
  151. package/dist/providers/HyperLiquidProvider.d.mts +0 -881
  152. package/dist/providers/HyperLiquidProvider.d.mts.map +0 -1
  153. package/dist/providers/HyperLiquidProvider.mjs +0 -5168
  154. package/dist/providers/HyperLiquidProvider.mjs.map +0 -1
  155. package/dist/providers/index.cjs +0 -11
  156. package/dist/providers/index.cjs.map +0 -1
  157. package/dist/providers/index.d.cts +0 -6
  158. package/dist/providers/index.d.cts.map +0 -1
  159. package/dist/providers/index.d.mts +0 -6
  160. package/dist/providers/index.d.mts.map +0 -1
  161. package/dist/providers/index.mjs +0 -6
  162. package/dist/providers/index.mjs.map +0 -1
  163. package/dist/routing/ProviderRouter.cjs +0 -148
  164. package/dist/routing/ProviderRouter.cjs.map +0 -1
  165. package/dist/routing/ProviderRouter.d.cts +0 -124
  166. package/dist/routing/ProviderRouter.d.cts.map +0 -1
  167. package/dist/routing/ProviderRouter.d.mts +0 -124
  168. package/dist/routing/ProviderRouter.d.mts.map +0 -1
  169. package/dist/routing/ProviderRouter.mjs +0 -144
  170. package/dist/routing/ProviderRouter.mjs.map +0 -1
  171. package/dist/routing/index.cjs +0 -9
  172. package/dist/routing/index.cjs.map +0 -1
  173. package/dist/routing/index.d.cts +0 -6
  174. package/dist/routing/index.d.cts.map +0 -1
  175. package/dist/routing/index.d.mts +0 -6
  176. package/dist/routing/index.d.mts.map +0 -1
  177. package/dist/routing/index.mjs +0 -5
  178. package/dist/routing/index.mjs.map +0 -1
  179. package/dist/selectors.cjs +0 -161
  180. package/dist/selectors.cjs.map +0 -1
  181. package/dist/selectors.d.cts +0 -345
  182. package/dist/selectors.d.cts.map +0 -1
  183. package/dist/selectors.d.mts +0 -345
  184. package/dist/selectors.d.mts.map +0 -1
  185. package/dist/selectors.mjs +0 -153
  186. package/dist/selectors.mjs.map +0 -1
  187. package/dist/services/AccountService.cjs +0 -313
  188. package/dist/services/AccountService.cjs.map +0 -1
  189. package/dist/services/AccountService.d.cts +0 -53
  190. package/dist/services/AccountService.d.cts.map +0 -1
  191. package/dist/services/AccountService.d.mts +0 -53
  192. package/dist/services/AccountService.d.mts.map +0 -1
  193. package/dist/services/AccountService.mjs +0 -309
  194. package/dist/services/AccountService.mjs.map +0 -1
  195. package/dist/services/DataLakeService.cjs +0 -219
  196. package/dist/services/DataLakeService.cjs.map +0 -1
  197. package/dist/services/DataLakeService.d.cts +0 -49
  198. package/dist/services/DataLakeService.d.cts.map +0 -1
  199. package/dist/services/DataLakeService.d.mts +0 -49
  200. package/dist/services/DataLakeService.d.mts.map +0 -1
  201. package/dist/services/DataLakeService.mjs +0 -215
  202. package/dist/services/DataLakeService.mjs.map +0 -1
  203. package/dist/services/DepositService.cjs +0 -96
  204. package/dist/services/DepositService.cjs.map +0 -1
  205. package/dist/services/DepositService.d.cts +0 -37
  206. package/dist/services/DepositService.d.cts.map +0 -1
  207. package/dist/services/DepositService.d.mts +0 -37
  208. package/dist/services/DepositService.d.mts.map +0 -1
  209. package/dist/services/DepositService.mjs +0 -92
  210. package/dist/services/DepositService.mjs.map +0 -1
  211. package/dist/services/EligibilityService.cjs +0 -156
  212. package/dist/services/EligibilityService.cjs.map +0 -1
  213. package/dist/services/EligibilityService.d.cts +0 -48
  214. package/dist/services/EligibilityService.d.cts.map +0 -1
  215. package/dist/services/EligibilityService.d.mts +0 -48
  216. package/dist/services/EligibilityService.d.mts.map +0 -1
  217. package/dist/services/EligibilityService.mjs +0 -152
  218. package/dist/services/EligibilityService.mjs.map +0 -1
  219. package/dist/services/FeatureFlagConfigurationService.cjs +0 -258
  220. package/dist/services/FeatureFlagConfigurationService.cjs.map +0 -1
  221. package/dist/services/FeatureFlagConfigurationService.d.cts +0 -100
  222. package/dist/services/FeatureFlagConfigurationService.d.cts.map +0 -1
  223. package/dist/services/FeatureFlagConfigurationService.d.mts +0 -100
  224. package/dist/services/FeatureFlagConfigurationService.d.mts.map +0 -1
  225. package/dist/services/FeatureFlagConfigurationService.mjs +0 -254
  226. package/dist/services/FeatureFlagConfigurationService.mjs.map +0 -1
  227. package/dist/services/MarketDataService.cjs +0 -875
  228. package/dist/services/MarketDataService.cjs.map +0 -1
  229. package/dist/services/MarketDataService.d.cts +0 -289
  230. package/dist/services/MarketDataService.d.cts.map +0 -1
  231. package/dist/services/MarketDataService.d.mts +0 -289
  232. package/dist/services/MarketDataService.d.mts.map +0 -1
  233. package/dist/services/MarketDataService.mjs +0 -871
  234. package/dist/services/MarketDataService.mjs.map +0 -1
  235. package/dist/services/RewardsIntegrationService.cjs +0 -94
  236. package/dist/services/RewardsIntegrationService.cjs.map +0 -1
  237. package/dist/services/RewardsIntegrationService.d.cts +0 -30
  238. package/dist/services/RewardsIntegrationService.d.cts.map +0 -1
  239. package/dist/services/RewardsIntegrationService.d.mts +0 -30
  240. package/dist/services/RewardsIntegrationService.d.mts.map +0 -1
  241. package/dist/services/RewardsIntegrationService.mjs +0 -90
  242. package/dist/services/RewardsIntegrationService.mjs.map +0 -1
  243. package/dist/services/ServiceContext.cjs +0 -3
  244. package/dist/services/ServiceContext.cjs.map +0 -1
  245. package/dist/services/ServiceContext.d.cts +0 -110
  246. package/dist/services/ServiceContext.d.cts.map +0 -1
  247. package/dist/services/ServiceContext.d.mts +0 -110
  248. package/dist/services/ServiceContext.d.mts.map +0 -1
  249. package/dist/services/ServiceContext.mjs +0 -2
  250. package/dist/services/ServiceContext.mjs.map +0 -1
  251. package/dist/services/TradingService.cjs +0 -1481
  252. package/dist/services/TradingService.cjs.map +0 -1
  253. package/dist/services/TradingService.d.cts +0 -308
  254. package/dist/services/TradingService.d.cts.map +0 -1
  255. package/dist/services/TradingService.d.mts +0 -308
  256. package/dist/services/TradingService.d.mts.map +0 -1
  257. package/dist/services/TradingService.mjs +0 -1477
  258. package/dist/services/TradingService.mjs.map +0 -1
  259. package/dist/services/index.cjs +0 -26
  260. package/dist/services/index.cjs.map +0 -1
  261. package/dist/services/index.d.cts +0 -11
  262. package/dist/services/index.d.cts.map +0 -1
  263. package/dist/services/index.d.mts +0 -11
  264. package/dist/services/index.d.mts.map +0 -1
  265. package/dist/services/index.mjs +0 -10
  266. package/dist/services/index.mjs.map +0 -1
  267. package/dist/services/utils.cjs +0 -16
  268. package/dist/services/utils.cjs.map +0 -1
  269. package/dist/services/utils.d.cts +0 -8
  270. package/dist/services/utils.d.cts.map +0 -1
  271. package/dist/services/utils.d.mts +0 -8
  272. package/dist/services/utils.d.mts.map +0 -1
  273. package/dist/services/utils.mjs +0 -12
  274. package/dist/services/utils.mjs.map +0 -1
  275. package/dist/types/chart.cjs +0 -42
  276. package/dist/types/chart.cjs.map +0 -1
  277. package/dist/types/chart.d.cts +0 -62
  278. package/dist/types/chart.d.cts.map +0 -1
  279. package/dist/types/chart.d.mts +0 -62
  280. package/dist/types/chart.d.mts.map +0 -1
  281. package/dist/types/chart.mjs +0 -39
  282. package/dist/types/chart.mjs.map +0 -1
  283. package/dist/types/hyperliquid-types.cjs +0 -3
  284. package/dist/types/hyperliquid-types.cjs.map +0 -1
  285. package/dist/types/hyperliquid-types.d.cts +0 -52
  286. package/dist/types/hyperliquid-types.d.cts.map +0 -1
  287. package/dist/types/hyperliquid-types.d.mts +0 -52
  288. package/dist/types/hyperliquid-types.d.mts.map +0 -1
  289. package/dist/types/hyperliquid-types.mjs +0 -2
  290. package/dist/types/hyperliquid-types.mjs.map +0 -1
  291. package/dist/types/index.cjs +0 -96
  292. package/dist/types/index.cjs.map +0 -1
  293. package/dist/types/index.d.cts +0 -1153
  294. package/dist/types/index.d.cts.map +0 -1
  295. package/dist/types/index.d.mts +0 -1153
  296. package/dist/types/index.d.mts.map +0 -1
  297. package/dist/types/index.mjs +0 -79
  298. package/dist/types/index.mjs.map +0 -1
  299. package/dist/types/transactionTypes.cjs +0 -28
  300. package/dist/types/transactionTypes.cjs.map +0 -1
  301. package/dist/types/transactionTypes.d.cts +0 -64
  302. package/dist/types/transactionTypes.d.cts.map +0 -1
  303. package/dist/types/transactionTypes.d.mts +0 -64
  304. package/dist/types/transactionTypes.d.mts.map +0 -1
  305. package/dist/types/transactionTypes.mjs +0 -23
  306. package/dist/types/transactionTypes.mjs.map +0 -1
  307. package/dist/utils/accountUtils.cjs +0 -65
  308. package/dist/utils/accountUtils.cjs.map +0 -1
  309. package/dist/utils/accountUtils.d.cts +0 -26
  310. package/dist/utils/accountUtils.d.cts.map +0 -1
  311. package/dist/utils/accountUtils.d.mts +0 -26
  312. package/dist/utils/accountUtils.d.mts.map +0 -1
  313. package/dist/utils/accountUtils.mjs +0 -61
  314. package/dist/utils/accountUtils.mjs.map +0 -1
  315. package/dist/utils/amountConversion.cjs +0 -61
  316. package/dist/utils/amountConversion.cjs.map +0 -1
  317. package/dist/utils/amountConversion.d.cts +0 -16
  318. package/dist/utils/amountConversion.d.cts.map +0 -1
  319. package/dist/utils/amountConversion.d.mts +0 -16
  320. package/dist/utils/amountConversion.d.mts.map +0 -1
  321. package/dist/utils/amountConversion.mjs +0 -54
  322. package/dist/utils/amountConversion.mjs.map +0 -1
  323. package/dist/utils/chartUtils.cjs +0 -98
  324. package/dist/utils/chartUtils.cjs.map +0 -1
  325. package/dist/utils/chartUtils.d.cts +0 -14
  326. package/dist/utils/chartUtils.d.cts.map +0 -1
  327. package/dist/utils/chartUtils.d.mts +0 -14
  328. package/dist/utils/chartUtils.d.mts.map +0 -1
  329. package/dist/utils/chartUtils.mjs +0 -94
  330. package/dist/utils/chartUtils.mjs.map +0 -1
  331. package/dist/utils/errorUtils.cjs +0 -22
  332. package/dist/utils/errorUtils.cjs.map +0 -1
  333. package/dist/utils/errorUtils.d.cts +0 -13
  334. package/dist/utils/errorUtils.d.cts.map +0 -1
  335. package/dist/utils/errorUtils.d.mts +0 -13
  336. package/dist/utils/errorUtils.d.mts.map +0 -1
  337. package/dist/utils/errorUtils.mjs +0 -18
  338. package/dist/utils/errorUtils.mjs.map +0 -1
  339. package/dist/utils/formatUtils.cjs +0 -987
  340. package/dist/utils/formatUtils.cjs.map +0 -1
  341. package/dist/utils/formatUtils.d.cts +0 -387
  342. package/dist/utils/formatUtils.d.cts.map +0 -1
  343. package/dist/utils/formatUtils.d.mts +0 -387
  344. package/dist/utils/formatUtils.d.mts.map +0 -1
  345. package/dist/utils/formatUtils.mjs +0 -966
  346. package/dist/utils/formatUtils.mjs.map +0 -1
  347. package/dist/utils/hyperLiquidAdapter.cjs +0 -454
  348. package/dist/utils/hyperLiquidAdapter.cjs.map +0 -1
  349. package/dist/utils/hyperLiquidAdapter.d.cts +0 -158
  350. package/dist/utils/hyperLiquidAdapter.d.cts.map +0 -1
  351. package/dist/utils/hyperLiquidAdapter.d.mts +0 -158
  352. package/dist/utils/hyperLiquidAdapter.d.mts.map +0 -1
  353. package/dist/utils/hyperLiquidAdapter.mjs +0 -439
  354. package/dist/utils/hyperLiquidAdapter.mjs.map +0 -1
  355. package/dist/utils/hyperLiquidOrderBookProcessor.cjs +0 -89
  356. package/dist/utils/hyperLiquidOrderBookProcessor.cjs.map +0 -1
  357. package/dist/utils/hyperLiquidOrderBookProcessor.d.cts +0 -58
  358. package/dist/utils/hyperLiquidOrderBookProcessor.d.cts.map +0 -1
  359. package/dist/utils/hyperLiquidOrderBookProcessor.d.mts +0 -58
  360. package/dist/utils/hyperLiquidOrderBookProcessor.d.mts.map +0 -1
  361. package/dist/utils/hyperLiquidOrderBookProcessor.mjs +0 -84
  362. package/dist/utils/hyperLiquidOrderBookProcessor.mjs.map +0 -1
  363. package/dist/utils/hyperLiquidValidation.cjs +0 -426
  364. package/dist/utils/hyperLiquidValidation.cjs.map +0 -1
  365. package/dist/utils/hyperLiquidValidation.d.cts +0 -143
  366. package/dist/utils/hyperLiquidValidation.d.cts.map +0 -1
  367. package/dist/utils/hyperLiquidValidation.d.mts +0 -143
  368. package/dist/utils/hyperLiquidValidation.d.mts.map +0 -1
  369. package/dist/utils/hyperLiquidValidation.mjs +0 -413
  370. package/dist/utils/hyperLiquidValidation.mjs.map +0 -1
  371. package/dist/utils/idUtils.cjs +0 -50
  372. package/dist/utils/idUtils.cjs.map +0 -1
  373. package/dist/utils/idUtils.d.cts +0 -38
  374. package/dist/utils/idUtils.d.cts.map +0 -1
  375. package/dist/utils/idUtils.d.mts +0 -38
  376. package/dist/utils/idUtils.d.mts.map +0 -1
  377. package/dist/utils/idUtils.mjs +0 -42
  378. package/dist/utils/idUtils.mjs.map +0 -1
  379. package/dist/utils/marginUtils.cjs +0 -137
  380. package/dist/utils/marginUtils.cjs.map +0 -1
  381. package/dist/utils/marginUtils.d.cts +0 -64
  382. package/dist/utils/marginUtils.d.cts.map +0 -1
  383. package/dist/utils/marginUtils.d.mts +0 -64
  384. package/dist/utils/marginUtils.d.mts.map +0 -1
  385. package/dist/utils/marginUtils.mjs +0 -131
  386. package/dist/utils/marginUtils.mjs.map +0 -1
  387. package/dist/utils/marketDataTransform.cjs +0 -227
  388. package/dist/utils/marketDataTransform.cjs.map +0 -1
  389. package/dist/utils/marketDataTransform.d.cts +0 -45
  390. package/dist/utils/marketDataTransform.d.cts.map +0 -1
  391. package/dist/utils/marketDataTransform.d.mts +0 -45
  392. package/dist/utils/marketDataTransform.d.mts.map +0 -1
  393. package/dist/utils/marketDataTransform.mjs +0 -220
  394. package/dist/utils/marketDataTransform.mjs.map +0 -1
  395. package/dist/utils/marketUtils.cjs +0 -420
  396. package/dist/utils/marketUtils.cjs.map +0 -1
  397. package/dist/utils/marketUtils.d.cts +0 -227
  398. package/dist/utils/marketUtils.d.cts.map +0 -1
  399. package/dist/utils/marketUtils.d.mts +0 -227
  400. package/dist/utils/marketUtils.d.mts.map +0 -1
  401. package/dist/utils/marketUtils.mjs +0 -404
  402. package/dist/utils/marketUtils.mjs.map +0 -1
  403. package/dist/utils/orderBookGrouping.cjs +0 -151
  404. package/dist/utils/orderBookGrouping.cjs.map +0 -1
  405. package/dist/utils/orderBookGrouping.d.cts +0 -76
  406. package/dist/utils/orderBookGrouping.d.cts.map +0 -1
  407. package/dist/utils/orderBookGrouping.d.mts +0 -76
  408. package/dist/utils/orderBookGrouping.d.mts.map +0 -1
  409. package/dist/utils/orderBookGrouping.mjs +0 -143
  410. package/dist/utils/orderBookGrouping.mjs.map +0 -1
  411. package/dist/utils/orderCalculations.cjs +0 -283
  412. package/dist/utils/orderCalculations.cjs.map +0 -1
  413. package/dist/utils/orderCalculations.d.cts +0 -107
  414. package/dist/utils/orderCalculations.d.cts.map +0 -1
  415. package/dist/utils/orderCalculations.d.mts +0 -107
  416. package/dist/utils/orderCalculations.d.mts.map +0 -1
  417. package/dist/utils/orderCalculations.mjs +0 -274
  418. package/dist/utils/orderCalculations.mjs.map +0 -1
  419. package/dist/utils/orderUtils.cjs +0 -159
  420. package/dist/utils/orderUtils.cjs.map +0 -1
  421. package/dist/utils/orderUtils.d.cts +0 -66
  422. package/dist/utils/orderUtils.d.cts.map +0 -1
  423. package/dist/utils/orderUtils.d.mts +0 -66
  424. package/dist/utils/orderUtils.d.mts.map +0 -1
  425. package/dist/utils/orderUtils.mjs +0 -151
  426. package/dist/utils/orderUtils.mjs.map +0 -1
  427. package/dist/utils/pnlCalculations.cjs +0 -107
  428. package/dist/utils/pnlCalculations.cjs.map +0 -1
  429. package/dist/utils/pnlCalculations.d.cts +0 -79
  430. package/dist/utils/pnlCalculations.d.cts.map +0 -1
  431. package/dist/utils/pnlCalculations.d.mts +0 -79
  432. package/dist/utils/pnlCalculations.d.mts.map +0 -1
  433. package/dist/utils/pnlCalculations.mjs +0 -97
  434. package/dist/utils/pnlCalculations.mjs.map +0 -1
  435. package/dist/utils/positionCalculations.cjs +0 -176
  436. package/dist/utils/positionCalculations.cjs.map +0 -1
  437. package/dist/utils/positionCalculations.d.cts +0 -85
  438. package/dist/utils/positionCalculations.d.cts.map +0 -1
  439. package/dist/utils/positionCalculations.d.mts +0 -85
  440. package/dist/utils/positionCalculations.d.mts.map +0 -1
  441. package/dist/utils/positionCalculations.mjs +0 -165
  442. package/dist/utils/positionCalculations.mjs.map +0 -1
  443. package/dist/utils/sortMarkets.cjs +0 -88
  444. package/dist/utils/sortMarkets.cjs.map +0 -1
  445. package/dist/utils/sortMarkets.d.cts +0 -21
  446. package/dist/utils/sortMarkets.d.cts.map +0 -1
  447. package/dist/utils/sortMarkets.d.mts +0 -21
  448. package/dist/utils/sortMarkets.d.mts.map +0 -1
  449. package/dist/utils/sortMarkets.mjs +0 -84
  450. package/dist/utils/sortMarkets.mjs.map +0 -1
  451. package/dist/utils/standaloneInfoClient.cjs +0 -34
  452. package/dist/utils/standaloneInfoClient.cjs.map +0 -1
  453. package/dist/utils/standaloneInfoClient.d.cts +0 -31
  454. package/dist/utils/standaloneInfoClient.d.cts.map +0 -1
  455. package/dist/utils/standaloneInfoClient.d.mts +0 -31
  456. package/dist/utils/standaloneInfoClient.d.mts.map +0 -1
  457. package/dist/utils/standaloneInfoClient.mjs +0 -30
  458. package/dist/utils/standaloneInfoClient.mjs.map +0 -1
  459. package/dist/utils/stringParseUtils.cjs +0 -49
  460. package/dist/utils/stringParseUtils.cjs.map +0 -1
  461. package/dist/utils/stringParseUtils.d.cts +0 -35
  462. package/dist/utils/stringParseUtils.d.cts.map +0 -1
  463. package/dist/utils/stringParseUtils.d.mts +0 -35
  464. package/dist/utils/stringParseUtils.d.mts.map +0 -1
  465. package/dist/utils/stringParseUtils.mjs +0 -44
  466. package/dist/utils/stringParseUtils.mjs.map +0 -1
  467. package/dist/utils/time.cjs +0 -37
  468. package/dist/utils/time.cjs.map +0 -1
  469. package/dist/utils/time.d.cts +0 -17
  470. package/dist/utils/time.d.cts.map +0 -1
  471. package/dist/utils/time.d.mts +0 -17
  472. package/dist/utils/time.d.mts.map +0 -1
  473. package/dist/utils/time.mjs +0 -33
  474. package/dist/utils/time.mjs.map +0 -1
  475. package/dist/utils/tpslValidation.cjs +0 -505
  476. package/dist/utils/tpslValidation.cjs.map +0 -1
  477. package/dist/utils/tpslValidation.d.cts +0 -182
  478. package/dist/utils/tpslValidation.d.cts.map +0 -1
  479. package/dist/utils/tpslValidation.d.mts +0 -182
  480. package/dist/utils/tpslValidation.d.mts.map +0 -1
  481. package/dist/utils/tpslValidation.mjs +0 -482
  482. package/dist/utils/tpslValidation.mjs.map +0 -1
  483. package/dist/utils/transactionUtils.cjs +0 -36
  484. package/dist/utils/transactionUtils.cjs.map +0 -1
  485. package/dist/utils/transactionUtils.d.cts +0 -17
  486. package/dist/utils/transactionUtils.d.cts.map +0 -1
  487. package/dist/utils/transactionUtils.d.mts +0 -17
  488. package/dist/utils/transactionUtils.d.mts.map +0 -1
  489. package/dist/utils/transactionUtils.mjs +0 -32
  490. package/dist/utils/transactionUtils.mjs.map +0 -1
  491. package/dist/utils/wait.cjs +0 -12
  492. package/dist/utils/wait.cjs.map +0 -1
  493. package/dist/utils/wait.d.cts +0 -8
  494. package/dist/utils/wait.d.cts.map +0 -1
  495. package/dist/utils/wait.d.mts +0 -8
  496. package/dist/utils/wait.d.mts.map +0 -1
  497. package/dist/utils/wait.mjs +0 -8
  498. package/dist/utils/wait.mjs.map +0 -1
@@ -1,2240 +1,83 @@
1
- // Note: ESLint rules below are disabled because this file was migrated from Mobile
2
- // which has different ESLint configurations. The following rules are Core-specific
3
- // and would require extensive refactoring to satisfy. The code is functionally correct.
4
- /* eslint-disable jsdoc/require-param-description, jsdoc/require-returns */
5
- /* eslint-disable no-restricted-syntax */
6
- /* eslint-disable @typescript-eslint/naming-convention */
7
- /* eslint-disable id-denylist, id-length */
8
- /* eslint-disable consistent-return */
9
- /* eslint-disable @typescript-eslint/explicit-function-return-type */
10
- /* eslint-disable promise/always-return */
11
- /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
12
1
  import { BaseController } from "@metamask/base-controller";
13
- import { TransactionType } from "@metamask/transaction-controller";
14
- import { PerpsEventProperties, PerpsEventValues } from "./constants/eventNames.mjs";
15
- import { ARBITRUM_MAINNET_CHAIN_ID_HEX, USDC_ARBITRUM_MAINNET_ADDRESS, USDC_SYMBOL } from "./constants/hyperLiquidConfig.mjs";
16
- import { PERPS_CONSTANTS, MARKET_SORTING_CONFIG } from "./constants/perpsConfig.mjs";
17
- import { PERPS_ERROR_CODES } from "./constants/perpsErrorCodes.mjs";
18
- import { AggregatedPerpsProvider } from "./providers/AggregatedPerpsProvider.mjs";
19
- import { HyperLiquidProvider } from "./providers/HyperLiquidProvider.mjs";
20
- import { AccountService } from "./services/AccountService.mjs";
21
- import { DataLakeService } from "./services/DataLakeService.mjs";
22
- import { DepositService } from "./services/DepositService.mjs";
23
- import { EligibilityService } from "./services/EligibilityService.mjs";
24
- import { FeatureFlagConfigurationService } from "./services/FeatureFlagConfigurationService.mjs";
25
- import { MarketDataService } from "./services/MarketDataService.mjs";
26
- import { RewardsIntegrationService } from "./services/RewardsIntegrationService.mjs";
27
- import { TradingService } from "./services/TradingService.mjs";
28
- import { WebSocketConnectionState } from "./types/index.mjs";
29
- import { PerpsAnalyticsEvent } from "./types/index.mjs";
30
- import { CandlePeriod } from "./types/chart.mjs";
31
- import { ensureError } from "./utils/errorUtils.mjs";
32
- import { wait } from "./utils/wait.mjs";
33
- // Re-export error codes from separate file to avoid circular dependencies
34
- export { PERPS_ERROR_CODES } from "./constants/perpsErrorCodes.mjs";
35
2
  /**
36
- * Initialization state enum for state machine tracking
3
+ * The name of the {@link PerpsController}, used to namespace the
4
+ * controller's actions and events and to namespace the controller's state data
5
+ * when composed with other controllers.
37
6
  */
38
- export var InitializationState;
39
- (function (InitializationState) {
40
- InitializationState["Uninitialized"] = "uninitialized";
41
- InitializationState["Initializing"] = "initializing";
42
- InitializationState["Initialized"] = "initialized";
43
- InitializationState["Failed"] = "failed";
44
- })(InitializationState || (InitializationState = {}));
7
+ export const controllerName = 'PerpsController';
45
8
  /**
46
- * Get default PerpsController state
47
- *
48
- * To change the active provider, modify the `activeProvider` value below:
49
- * - 'hyperliquid': HyperLiquid provider (default, production)
50
- * - 'aggregated': Multi-provider aggregation mode
51
- * - 'myx': MYX provider (future implementation)
9
+ * The metadata for each property in {@link PerpsControllerState}.
52
10
  */
53
- export const getDefaultPerpsControllerState = () => ({
54
- activeProvider: 'hyperliquid',
55
- isTestnet: false, // Default to mainnet
56
- initializationState: InitializationState.Uninitialized,
57
- initializationError: null,
58
- initializationAttempts: 0,
59
- accountState: null,
60
- perpsBalances: {},
61
- depositInProgress: false,
62
- lastDepositResult: null,
63
- withdrawInProgress: false,
64
- lastDepositTransactionId: null,
65
- lastWithdrawResult: null,
66
- withdrawalRequests: [],
67
- withdrawalProgress: {
68
- progress: 0,
69
- lastUpdated: 0,
70
- activeWithdrawalId: null,
71
- },
72
- depositRequests: [],
73
- lastError: null,
74
- lastUpdateTimestamp: 0,
75
- isEligible: false,
76
- isFirstTimeUser: {
77
- testnet: true,
78
- mainnet: true,
79
- },
80
- hasPlacedFirstOrder: {
81
- testnet: false,
82
- mainnet: false,
83
- },
84
- watchlistMarkets: {
85
- testnet: [],
86
- mainnet: [],
87
- },
88
- tradeConfigurations: {
89
- testnet: {},
90
- mainnet: {},
91
- },
92
- marketFilterPreferences: {
93
- optionId: MARKET_SORTING_CONFIG.DefaultSortOptionId,
94
- direction: MARKET_SORTING_CONFIG.DefaultDirection,
95
- },
96
- hip3ConfigVersion: 0,
97
- });
11
+ const perpsControllerMetadata = {};
98
12
  /**
99
- * State metadata for the PerpsController
13
+ * Constructs the default {@link PerpsController} state. This allows
14
+ * consumers to provide a partial state object when initializing the controller
15
+ * and also helps in constructing complete state objects for this controller in
16
+ * tests.
17
+ *
18
+ * @returns The default {@link PerpsController} state.
100
19
  */
101
- const metadata = {
102
- accountState: {
103
- includeInStateLogs: true,
104
- persist: true,
105
- includeInDebugSnapshot: false,
106
- usedInUi: true,
107
- },
108
- perpsBalances: {
109
- includeInStateLogs: true,
110
- persist: true,
111
- includeInDebugSnapshot: false,
112
- usedInUi: true,
113
- },
114
- isTestnet: {
115
- includeInStateLogs: true,
116
- persist: true,
117
- includeInDebugSnapshot: false,
118
- usedInUi: true,
119
- },
120
- activeProvider: {
121
- includeInStateLogs: true,
122
- persist: true,
123
- includeInDebugSnapshot: false,
124
- usedInUi: true,
125
- },
126
- initializationState: {
127
- includeInStateLogs: true,
128
- persist: false,
129
- includeInDebugSnapshot: false,
130
- usedInUi: true,
131
- },
132
- initializationError: {
133
- includeInStateLogs: true,
134
- persist: false,
135
- includeInDebugSnapshot: false,
136
- usedInUi: true,
137
- },
138
- initializationAttempts: {
139
- includeInStateLogs: true,
140
- persist: false,
141
- includeInDebugSnapshot: false,
142
- usedInUi: false,
143
- },
144
- depositInProgress: {
145
- includeInStateLogs: true,
146
- persist: false,
147
- includeInDebugSnapshot: false,
148
- usedInUi: true,
149
- },
150
- lastDepositTransactionId: {
151
- includeInStateLogs: true,
152
- persist: false,
153
- includeInDebugSnapshot: false,
154
- usedInUi: true,
155
- },
156
- lastDepositResult: {
157
- includeInStateLogs: true,
158
- persist: false,
159
- includeInDebugSnapshot: false,
160
- usedInUi: true,
161
- },
162
- withdrawInProgress: {
163
- includeInStateLogs: true,
164
- persist: false,
165
- includeInDebugSnapshot: false,
166
- usedInUi: true,
167
- },
168
- lastWithdrawResult: {
169
- includeInStateLogs: true,
170
- persist: false,
171
- includeInDebugSnapshot: false,
172
- usedInUi: true,
173
- },
174
- withdrawalRequests: {
175
- includeInStateLogs: true,
176
- persist: true,
177
- includeInDebugSnapshot: false,
178
- usedInUi: true,
179
- },
180
- withdrawalProgress: {
181
- includeInStateLogs: true,
182
- persist: true,
183
- includeInDebugSnapshot: false,
184
- usedInUi: true,
185
- },
186
- depositRequests: {
187
- includeInStateLogs: true,
188
- persist: true,
189
- includeInDebugSnapshot: false,
190
- usedInUi: true,
191
- },
192
- lastError: {
193
- includeInStateLogs: false,
194
- persist: false,
195
- includeInDebugSnapshot: false,
196
- usedInUi: false,
197
- },
198
- lastUpdateTimestamp: {
199
- includeInStateLogs: true,
200
- persist: false,
201
- includeInDebugSnapshot: false,
202
- usedInUi: false,
203
- },
204
- isEligible: {
205
- includeInStateLogs: true,
206
- persist: false,
207
- includeInDebugSnapshot: false,
208
- usedInUi: true,
209
- },
210
- isFirstTimeUser: {
211
- includeInStateLogs: true,
212
- persist: true,
213
- includeInDebugSnapshot: false,
214
- usedInUi: true,
215
- },
216
- hasPlacedFirstOrder: {
217
- includeInStateLogs: true,
218
- persist: true,
219
- includeInDebugSnapshot: false,
220
- usedInUi: true,
221
- },
222
- watchlistMarkets: {
223
- includeInStateLogs: true,
224
- persist: true,
225
- includeInDebugSnapshot: false,
226
- usedInUi: true,
227
- },
228
- tradeConfigurations: {
229
- includeInStateLogs: true,
230
- persist: true,
231
- includeInDebugSnapshot: false,
232
- usedInUi: true,
233
- },
234
- marketFilterPreferences: {
235
- includeInStateLogs: true,
236
- persist: true,
237
- includeInDebugSnapshot: false,
238
- usedInUi: true,
239
- },
240
- hip3ConfigVersion: {
241
- includeInStateLogs: true,
242
- persist: true,
243
- includeInDebugSnapshot: false,
244
- usedInUi: false,
245
- },
246
- };
20
+ export function getDefaultPerpsControllerState() {
21
+ return {};
22
+ }
247
23
  /**
248
- * PerpsController - Protocol-agnostic perpetuals trading controller
24
+ * `PerpsController` manages perpetual trading functionality in MetaMask.
25
+ *
26
+ * This controller provides platform-agnostic perps trading capabilities.
27
+ *
28
+ * @example
29
+ *
30
+ * ``` ts
31
+ * import { Messenger } from '@metamask/messenger';
32
+ * import type {
33
+ * PerpsControllerActions,
34
+ * PerpsControllerEvents,
35
+ * } from '@metamask/perps-controller';
36
+ * import { PerpsController } from '@metamask/perps-controller';
37
+ *
38
+ * const rootMessenger = new Messenger<
39
+ * 'Root',
40
+ * PerpsControllerActions,
41
+ * PerpsControllerEvents
42
+ * >({ namespace: 'Root' });
43
+ * const perpsControllerMessenger = new Messenger<
44
+ * 'PerpsController',
45
+ * PerpsControllerActions,
46
+ * PerpsControllerEvents,
47
+ * typeof rootMessenger,
48
+ * >({
49
+ * namespace: 'PerpsController',
50
+ * parent: rootMessenger,
51
+ * });
52
+ * // Instantiate the controller to register its actions on the messenger
53
+ * new PerpsController({
54
+ * messenger: perpsControllerMessenger,
55
+ * });
249
56
  *
250
- * Provides a unified interface for perpetual futures trading across multiple protocols.
251
- * Features dual data flow architecture:
252
- * - Trading actions use Redux for persistence and optimistic updates
253
- * - Live data uses direct callbacks for maximum performance
57
+ * const perpsControllerState = await rootMessenger.call(
58
+ * 'PerpsController:getState',
59
+ * );
60
+ * ```
254
61
  */
255
62
  export class PerpsController extends BaseController {
256
- constructor({ messenger, state = {}, clientConfig = {}, infrastructure, }) {
257
- super({
258
- name: 'PerpsController',
259
- metadata,
260
- messenger,
261
- state: { ...getDefaultPerpsControllerState(), ...state },
262
- });
263
- this.isInitialized = false;
264
- this.initializationPromise = null;
265
- this.isReinitializing = false;
266
- this.blockedRegionList = {
267
- list: [],
268
- source: 'fallback',
269
- };
270
- /**
271
- * Version counter for blocked region list.
272
- * Used to prevent race conditions where stale eligibility checks
273
- * (started with fallback config) overwrite results from newer checks
274
- * (started with remote config).
275
- */
276
- this.blockedRegionListVersion = 0;
277
- this.hip3ConfigSource = 'fallback';
278
- /**
279
- * Active provider instance for routing operations.
280
- * When activeProvider is 'hyperliquid' or 'myx': points to specific provider directly
281
- * When activeProvider is 'aggregated': points to AggregatedPerpsProvider wrapper
282
- */
283
- this.activeProviderInstance = null;
284
- // Store options for dependency injection
285
- this.options = {
286
- messenger,
287
- state,
288
- clientConfig,
289
- infrastructure,
290
- };
291
- // Instantiate services with platform dependencies
292
- this.tradingService = new TradingService(infrastructure);
293
- this.marketDataService = new MarketDataService(infrastructure);
294
- this.accountService = new AccountService(infrastructure);
295
- this.eligibilityService = new EligibilityService(infrastructure);
296
- this.dataLakeService = new DataLakeService(infrastructure);
297
- this.depositService = new DepositService(infrastructure);
298
- this.featureFlagConfigurationService = new FeatureFlagConfigurationService(infrastructure);
299
- this.rewardsIntegrationService = new RewardsIntegrationService(infrastructure);
300
- // Set HIP-3 fallback configuration from client (will be updated if remote flags available)
301
- this.hip3Enabled = clientConfig.fallbackHip3Enabled ?? false;
302
- this.hip3AllowlistMarkets = [
303
- ...(clientConfig.fallbackHip3AllowlistMarkets ?? []),
304
- ];
305
- this.hip3BlocklistMarkets = [
306
- ...(clientConfig.fallbackHip3BlocklistMarkets ?? []),
307
- ];
308
- // Immediately set the fallback region list since RemoteFeatureFlagController is empty by default and takes a moment to populate.
309
- this.setBlockedRegionList(clientConfig.fallbackBlockedRegions ?? [], 'fallback');
310
- /**
311
- * Immediately read current state to catch any flags already loaded
312
- * This is necessary to avoid race conditions where the RemoteFeatureFlagController fetches flags
313
- * before the PerpsController initializes its RemoteFeatureFlagController subscription.
314
- *
315
- * We still subscribe in case the RemoteFeatureFlagController is not yet populated and updates later.
316
- */
317
- try {
318
- const currentRemoteFeatureFlagState = this.messenger.call('RemoteFeatureFlagController:getState');
319
- this.refreshEligibilityOnFeatureFlagChange(currentRemoteFeatureFlagState);
320
- }
321
- catch (error) {
322
- // If we can't read the remote feature flags at construction time, we'll rely on:
323
- // 1. The fallback blocked regions already set above
324
- // 2. The subscription to catch updates when RemoteFeatureFlagController is ready
325
- this.logError(ensureError(error), this.getErrorContext('constructor', {
326
- operation: 'readRemoteFeatureFlags',
327
- }));
328
- }
329
- this.messenger.subscribe('RemoteFeatureFlagController:stateChange', this.refreshEligibilityOnFeatureFlagChange.bind(this));
330
- this.providers = new Map();
331
- // Migrate old persisted data without accountAddress
332
- this.migrateRequestsIfNeeded();
333
- }
334
- // ============================================================================
335
- // Infrastructure Access Methods
336
- // These methods provide access to platform-specific infrastructure via dependency injection.
337
- // Infrastructure is required and must be provided at instantiation time.
338
- // ============================================================================
339
- /**
340
- * Log an error using injected infrastructure logger
341
- *
342
- * @param error
343
- * @param options
344
- */
345
- logError(error, options) {
346
- this.options.infrastructure.logger.error(error, options);
347
- }
348
- /**
349
- * Log debug message using injected infrastructure debugLogger
350
- *
351
- * @param args
352
- */
353
- debugLog(...args) {
354
- this.options.infrastructure.debugLogger.log(...args);
355
- }
356
- /**
357
- * Debug method for validating Core integration.
358
- * Logs via injected debugLogger and returns debug info.
359
- *
360
- * @returns Debug information object
361
- */
362
- debug() {
363
- const debugInfo = {
364
- timestamp: new Date().toISOString(),
365
- source: '@metamask/perps-controller',
366
- message: 'DEBUG v5 - Hello from Core PerpsController!',
367
- };
368
- this.debugLog('[PerpsController.debug]', debugInfo);
369
- return debugInfo;
370
- }
371
- /**
372
- * Get metrics instance from platform dependencies
373
- */
374
- getMetrics() {
375
- return this.options.infrastructure.metrics;
376
- }
377
- /**
378
- * Clean up old withdrawal/deposit requests that don't have accountAddress
379
- * These are from before the accountAddress field was added and can't be displayed
380
- * in the UI (which filters by account), so we discard them
381
- */
382
- migrateRequestsIfNeeded() {
383
- this.update((state) => {
384
- // Remove withdrawal requests without accountAddress - they can't be attributed to any account
385
- state.withdrawalRequests = state.withdrawalRequests.filter((req) => Boolean(req.accountAddress));
386
- // Remove deposit requests without accountAddress - they can't be attributed to any account
387
- state.depositRequests = state.depositRequests.filter((req) => Boolean(req.accountAddress));
388
- });
389
- }
390
- setBlockedRegionList(list, source) {
391
- this.featureFlagConfigurationService.setBlockedRegions({
392
- list,
393
- source,
394
- context: this.createServiceContext('setBlockedRegionList', {
395
- getBlockedRegionList: () => this.blockedRegionList,
396
- setBlockedRegionList: (newList, newSource) => {
397
- this.blockedRegionList = { list: newList, source: newSource };
398
- this.blockedRegionListVersion += 1;
399
- },
400
- refreshEligibility: () => this.refreshEligibility(),
401
- }),
402
- });
403
- }
404
- /**
405
- * Respond to RemoteFeatureFlagController state changes
406
- * Refreshes user eligibility based on geo-blocked regions defined in remote feature flag.
407
- * Uses fallback configuration when remote feature flag is undefined.
408
- * Note: Initial eligibility is set in the constructor if fallback regions are provided.
409
- *
410
- * @param remoteFeatureFlagControllerState
411
- */
412
- refreshEligibilityOnFeatureFlagChange(remoteFeatureFlagControllerState) {
413
- this.featureFlagConfigurationService.refreshEligibility({
414
- remoteFeatureFlagControllerState,
415
- context: this.createServiceContext('refreshEligibilityOnFeatureFlagChange', {
416
- getBlockedRegionList: () => this.blockedRegionList,
417
- setBlockedRegionList: (list, source) => {
418
- this.blockedRegionList = { list, source };
419
- this.blockedRegionListVersion += 1;
420
- },
421
- refreshEligibility: () => this.refreshEligibility(),
422
- getHip3Config: () => ({
423
- enabled: this.hip3Enabled,
424
- allowlistMarkets: this.hip3AllowlistMarkets,
425
- blocklistMarkets: this.hip3BlocklistMarkets,
426
- source: this.hip3ConfigSource,
427
- }),
428
- setHip3Config: (config) => {
429
- if (config.enabled !== undefined) {
430
- this.hip3Enabled = config.enabled;
431
- }
432
- if (config.allowlistMarkets !== undefined) {
433
- this.hip3AllowlistMarkets = [...config.allowlistMarkets];
434
- }
435
- if (config.blocklistMarkets !== undefined) {
436
- this.hip3BlocklistMarkets = [...config.blocklistMarkets];
437
- }
438
- if (config.source !== undefined) {
439
- this.hip3ConfigSource = config.source;
440
- }
441
- },
442
- incrementHip3ConfigVersion: () => {
443
- const newVersion = (this.state.hip3ConfigVersion || 0) + 1;
444
- this.update((state) => {
445
- state.hip3ConfigVersion = newVersion;
446
- });
447
- return newVersion;
448
- },
449
- }),
450
- });
451
- }
452
- /**
453
- * Execute an operation while temporarily pausing specified stream channels
454
- * to prevent WebSocket updates from triggering UI re-renders during operations.
455
- *
456
- * WebSocket connections remain alive but updates are not emitted to subscribers.
457
- * This prevents race conditions where UI re-renders fetch stale data during operations.
458
- *
459
- * @param operation - The async operation to execute
460
- * @param channels - Array of stream channel names to pause
461
- * @returns The result of the operation
462
- *
463
- * @example
464
- * ```typescript
465
- * // Cancel orders without stream interference
466
- * await this.withStreamPause(
467
- * async () => this.provider.cancelOrders({ cancelAll: true }),
468
- * ['orders']
469
- * );
470
- *
471
- * // Close positions and pause multiple streams
472
- * await this.withStreamPause(
473
- * async () => this.provider.closePositions(positions),
474
- * ['positions', 'account', 'orders']
475
- * );
476
- * ```
477
- */
478
- async withStreamPause(operation, channels) {
479
- const pausedChannels = [];
480
- const { streamManager } = this.options.infrastructure;
481
- // Pause emission on specified channels (WebSocket stays connected)
482
- // Track which channels successfully paused to ensure proper cleanup
483
- for (const channel of channels) {
484
- try {
485
- streamManager.pauseChannel(channel);
486
- pausedChannels.push(channel);
487
- }
488
- catch (err) {
489
- // Log error to Sentry but continue pausing remaining channels
490
- this.logError(ensureError(err), this.getErrorContext('withStreamPause', {
491
- operation: 'pause',
492
- channel: String(channel),
493
- pausedChannels: pausedChannels.join(','),
494
- }));
495
- }
496
- }
497
- try {
498
- // Execute operation without stream interference
499
- return await operation();
500
- }
501
- finally {
502
- // Resume only channels that were successfully paused
503
- for (const channel of pausedChannels) {
504
- try {
505
- streamManager.resumeChannel(channel);
506
- }
507
- catch (err) {
508
- // Log error to Sentry but continue resuming remaining channels
509
- this.logError(ensureError(err), this.getErrorContext('withStreamPause', {
510
- operation: 'resume',
511
- channel: String(channel),
512
- pausedChannels: pausedChannels.join(','),
513
- }));
514
- }
515
- }
516
- }
517
- }
518
- /**
519
- * Initialize the PerpsController providers
520
- * Must be called before using any other methods
521
- * Prevents double initialization with promise caching
522
- */
523
- async init() {
524
- if (this.isInitialized) {
525
- return;
526
- }
527
- if (this.initializationPromise) {
528
- return this.initializationPromise;
529
- }
530
- this.initializationPromise = this.performInitialization();
531
- return this.initializationPromise;
532
- }
533
- /**
534
- * Actual initialization implementation with retry logic
535
- */
536
- async performInitialization() {
537
- const maxAttempts = 3;
538
- const baseDelay = 1000;
539
- this.update((state) => {
540
- state.initializationState = InitializationState.Initializing;
541
- state.initializationError = null;
542
- state.initializationAttempts = 0;
543
- });
544
- this.debugLog('PerpsController: Initializing providers', {
545
- currentNetwork: this.state.isTestnet ? 'testnet' : 'mainnet',
546
- existingProviders: Array.from(this.providers.keys()),
547
- timestamp: new Date().toISOString(),
548
- });
549
- let lastError = null;
550
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
551
- try {
552
- this.update((state) => {
553
- state.initializationAttempts = attempt;
554
- });
555
- // Disconnect existing providers to close WebSocket connections
556
- const existingProviders = Array.from(this.providers.values());
557
- if (existingProviders.length > 0) {
558
- this.debugLog('PerpsController: Disconnecting existing providers', {
559
- count: existingProviders.length,
560
- timestamp: new Date().toISOString(),
561
- });
562
- await Promise.all(existingProviders.map((provider) => provider.disconnect()));
563
- }
564
- this.providers.clear();
565
- const { activeProvider } = this.state;
566
- this.debugLog('PerpsController: Creating provider with HIP-3 configuration', {
567
- hip3Enabled: this.hip3Enabled,
568
- hip3AllowlistMarkets: this.hip3AllowlistMarkets,
569
- hip3BlocklistMarkets: this.hip3BlocklistMarkets,
570
- hip3ConfigSource: this.hip3ConfigSource,
571
- isTestnet: this.state.isTestnet,
572
- activeProvider,
573
- });
574
- // Always create HyperLiquid provider as the base provider
575
- const hyperLiquidProvider = new HyperLiquidProvider({
576
- isTestnet: this.state.isTestnet,
577
- hip3Enabled: this.hip3Enabled,
578
- allowlistMarkets: this.hip3AllowlistMarkets,
579
- blocklistMarkets: this.hip3BlocklistMarkets,
580
- platformDependencies: this.options.infrastructure,
581
- });
582
- this.providers.set('hyperliquid', hyperLiquidProvider);
583
- // Set up active provider based on activeProvider value in state
584
- // 'aggregated' is treated as just another provider that wraps others
585
- if (activeProvider === 'aggregated') {
586
- // Aggregated mode: wrap in AggregatedPerpsProvider for multi-provider support
587
- // Future: register additional providers here (MYX, etc.)
588
- this.activeProviderInstance = new AggregatedPerpsProvider({
589
- providers: this.providers,
590
- defaultProvider: 'hyperliquid',
591
- infrastructure: this.options.infrastructure,
592
- });
593
- this.debugLog('PerpsController: Using aggregated provider (multi-provider)', { registeredProviders: Array.from(this.providers.keys()) });
594
- }
595
- else if (activeProvider === 'hyperliquid') {
596
- // Direct provider mode: use HyperLiquid provider directly
597
- this.activeProviderInstance = hyperLiquidProvider;
598
- this.debugLog(`PerpsController: Using direct provider (${activeProvider})`);
599
- }
600
- else {
601
- // Unsupported provider - throw error to prevent silent misconfiguration
602
- throw new Error(`Unsupported provider: ${activeProvider}. Currently only 'hyperliquid' and 'aggregated' are supported.`);
603
- }
604
- // Future providers can be added here with their own authentication patterns:
605
- // - Some might use API keys: new BinanceProvider({ apiKey, apiSecret })
606
- // - Some might use different wallet patterns: new GMXProvider({ signer })
607
- // - Some might not need auth at all: new DydxProvider()
608
- // Wait for WebSocket transport to be ready before marking as initialized
609
- await wait(PERPS_CONSTANTS.ReconnectionCleanupDelayMs);
610
- this.isInitialized = true;
611
- this.update((state) => {
612
- state.initializationState = InitializationState.Initialized;
613
- state.initializationError = null;
614
- });
615
- this.debugLog('PerpsController: Providers initialized successfully', {
616
- providerCount: this.providers.size,
617
- activeProvider,
618
- timestamp: new Date().toISOString(),
619
- attempts: attempt,
620
- });
621
- return; // Exit retry loop on success
622
- }
623
- catch (error) {
624
- lastError = ensureError(error);
625
- this.logError(lastError, this.getErrorContext('performInitialization', {
626
- attempt,
627
- maxAttempts,
628
- }));
629
- // If not the last attempt, wait before retrying (exponential backoff)
630
- if (attempt < maxAttempts) {
631
- const delay = baseDelay * Math.pow(2, attempt - 1); // 1s, 2s, 4s
632
- this.debugLog(`PerpsController: Retrying initialization in ${delay}ms`, {
633
- attempt,
634
- maxAttempts,
635
- error: lastError.message,
636
- });
637
- await wait(delay);
638
- }
639
- }
640
- }
641
- this.isInitialized = false;
642
- this.update((state) => {
643
- state.initializationState = InitializationState.Failed;
644
- state.initializationError = lastError?.message ?? 'Unknown error';
645
- });
646
- this.initializationPromise = null; // Clear promise to allow retry
647
- this.debugLog('PerpsController: Initialization failed', {
648
- error: lastError?.message,
649
- attempts: maxAttempts,
650
- timestamp: new Date().toISOString(),
651
- });
652
- }
653
- /**
654
- * Generate standard error context for Logger.error calls with searchable tags and context.
655
- * Enables Sentry dashboard filtering by feature, provider, and network.
656
- *
657
- * @param method - The method name where the error occurred
658
- * @param extra - Optional additional context fields (becomes searchable context data)
659
- * @returns PerpsLoggerOptions with tags (searchable) and context (searchable)
660
- * @private
661
- *
662
- * @example
663
- * this.logError(error, this.getErrorContext('placeOrder', { symbol: 'BTC', operation: 'validate' }));
664
- * // Creates searchable tags: feature:perps, provider:hyperliquid, network:mainnet
665
- * // Creates searchable context: perps_controller.method:placeOrder, perps_controller.symbol:BTC, perps_controller.operation:validate
666
- */
667
- getErrorContext(method, extra) {
668
- return {
669
- tags: {
670
- feature: PERPS_CONSTANTS.FeatureName,
671
- provider: this.state.activeProvider,
672
- network: this.state.isTestnet ? 'testnet' : 'mainnet',
673
- },
674
- context: {
675
- name: 'PerpsController',
676
- data: {
677
- method,
678
- ...extra,
679
- },
680
- },
681
- };
682
- }
683
- /**
684
- * Create a ServiceContext for dependency injection into services
685
- * Provides all orchestration dependencies (tracing, analytics, state management)
686
- *
687
- * @param method - Method name for error context
688
- * @param additionalContext - Optional additional context (e.g., rewardsController, streamManager)
689
- * @returns ServiceContext with all required dependencies
690
- */
691
- createServiceContext(method, additionalContext) {
692
- return {
693
- tracingContext: {
694
- provider: this.state.activeProvider,
695
- isTestnet: this.state.isTestnet,
696
- },
697
- errorContext: {
698
- controller: 'PerpsController',
699
- method,
700
- },
701
- stateManager: {
702
- update: (updater) => this.update(updater),
703
- getState: () => this.state,
704
- },
705
- ...additionalContext,
706
- };
707
- }
708
- /**
709
- * Ensure TradingService has controller dependencies set.
710
- * Uses injectable dependencies from infrastructure for core migration compatibility.
711
- */
712
- ensureTradingServiceDeps() {
713
- const { controllers } = this.options.infrastructure;
714
- this.tradingService.setControllerDependencies({
715
- controllers,
716
- messenger: this.messenger,
717
- rewardsIntegrationService: this.rewardsIntegrationService,
718
- });
719
- }
720
- /**
721
- * Get the currently active provider.
722
- * In aggregated mode, returns AggregatedPerpsProvider which routes to underlying providers.
723
- * In single provider mode, returns HyperLiquidProvider directly.
724
- *
725
- * @returns The active provider (aggregated wrapper or direct provider based on mode)
726
- * @throws Error if provider is not initialized or reinitializing
727
- */
728
- getActiveProvider() {
729
- // Check if we're in the middle of reinitializing
730
- if (this.isReinitializing) {
731
- this.update((state) => {
732
- state.lastError = PERPS_ERROR_CODES.CLIENT_REINITIALIZING;
733
- state.lastUpdateTimestamp = Date.now();
734
- });
735
- throw new Error(PERPS_ERROR_CODES.CLIENT_REINITIALIZING);
736
- }
737
- // Check if not initialized
738
- if (this.state.initializationState !== InitializationState.Initialized ||
739
- !this.isInitialized) {
740
- const errorMessage = this.state.initializationState === InitializationState.Failed
741
- ? `${PERPS_ERROR_CODES.CLIENT_NOT_INITIALIZED}: ${this.state.initializationError || 'Initialization failed'}`
742
- : PERPS_ERROR_CODES.CLIENT_NOT_INITIALIZED;
743
- this.update((state) => {
744
- state.lastError = errorMessage;
745
- state.lastUpdateTimestamp = Date.now();
746
- });
747
- throw new Error(errorMessage);
748
- }
749
- // Return the active provider instance (set during initialization based on providerMode)
750
- if (!this.activeProviderInstance) {
751
- this.update((state) => {
752
- state.lastError = PERPS_ERROR_CODES.PROVIDER_NOT_AVAILABLE;
753
- state.lastUpdateTimestamp = Date.now();
754
- });
755
- throw new Error(PERPS_ERROR_CODES.PROVIDER_NOT_AVAILABLE);
756
- }
757
- return this.activeProviderInstance;
758
- }
759
- /**
760
- * Get the currently active provider, returning null if not available
761
- * Use this method when the caller can gracefully handle a missing provider
762
- * (e.g., UI components during initialization or reconnection)
763
- *
764
- * @returns The active provider, or null if not initialized/reinitializing
765
- */
766
- getActiveProviderOrNull() {
767
- // Return null during reinitialization
768
- if (this.isReinitializing) {
769
- return null;
770
- }
771
- // Return null if not initialized
772
- if (this.state.initializationState !== InitializationState.Initialized ||
773
- !this.isInitialized) {
774
- return null;
775
- }
776
- // Return the active provider instance or null if not found
777
- return this.activeProviderInstance || null;
778
- }
779
- /**
780
- * Place a new order
781
- * Thin delegation to TradingService
782
- *
783
- * @param params
784
- */
785
- async placeOrder(params) {
786
- const provider = this.getActiveProvider();
787
- this.ensureTradingServiceDeps();
788
- return this.tradingService.placeOrder({
789
- provider,
790
- params,
791
- context: this.createServiceContext('placeOrder', {
792
- saveTradeConfiguration: (symbol, leverage) => this.saveTradeConfiguration(symbol, leverage),
793
- }),
794
- reportOrderToDataLake: (dataLakeParams) => this.reportOrderToDataLake(dataLakeParams),
795
- });
796
- }
797
- /**
798
- * Edit an existing order
799
- * Thin delegation to TradingService
800
- *
801
- * @param params
802
- */
803
- async editOrder(params) {
804
- const provider = this.getActiveProvider();
805
- this.ensureTradingServiceDeps();
806
- return this.tradingService.editOrder({
807
- provider,
808
- params,
809
- context: this.createServiceContext('editOrder'),
810
- });
811
- }
812
- /**
813
- * Cancel an existing order
814
- *
815
- * @param params
816
- */
817
- async cancelOrder(params) {
818
- const provider = this.getActiveProvider();
819
- return this.tradingService.cancelOrder({
820
- provider,
821
- params,
822
- context: this.createServiceContext('cancelOrder'),
823
- });
824
- }
825
- /**
826
- * Cancel multiple orders in parallel
827
- * Batch version of cancelOrder() that cancels multiple orders simultaneously
828
- *
829
- * @param params
830
- */
831
- async cancelOrders(params) {
832
- const provider = this.getActiveProvider();
833
- return this.tradingService.cancelOrders({
834
- provider,
835
- params,
836
- context: this.createServiceContext('cancelOrders', {
837
- getOpenOrders: () => this.getOpenOrders(),
838
- }),
839
- withStreamPause: (operation, channels) => this.withStreamPause(operation, channels),
840
- });
841
- }
842
63
  /**
843
- * Close a position (partial or full)
844
- * Thin delegation to TradingService
64
+ * Constructs a new {@link PerpsController}.
845
65
  *
846
- * @param params
66
+ * @param args - The arguments to this controller.
67
+ * @param args.messenger - The messenger suited for this controller.
68
+ * @param args.state - The desired state with which to initialize this
69
+ * controller. Missing properties will be filled in with defaults.
847
70
  */
848
- async closePosition(params) {
849
- const provider = this.getActiveProvider();
850
- this.ensureTradingServiceDeps();
851
- return this.tradingService.closePosition({
852
- provider,
853
- params,
854
- context: this.createServiceContext('closePosition', {
855
- getPositions: () => this.getPositions(),
856
- }),
857
- reportOrderToDataLake: (dataLakeParams) => this.reportOrderToDataLake(dataLakeParams),
858
- });
859
- }
860
- /**
861
- * Close multiple positions in parallel
862
- * Batch version of closePosition() that closes multiple positions simultaneously
863
- *
864
- * @param params
865
- */
866
- async closePositions(params) {
867
- const provider = this.getActiveProvider();
868
- this.ensureTradingServiceDeps();
869
- return this.tradingService.closePositions({
870
- provider,
871
- params,
872
- context: this.createServiceContext('closePositions', {
873
- getPositions: () => this.getPositions(),
874
- }),
875
- });
876
- }
877
- /**
878
- * Update TP/SL for an existing position
879
- *
880
- * @param params
881
- */
882
- async updatePositionTPSL(params) {
883
- const provider = this.getActiveProvider();
884
- this.ensureTradingServiceDeps();
885
- return this.tradingService.updatePositionTPSL({
886
- provider,
887
- params,
888
- context: this.createServiceContext('updatePositionTPSL'),
889
- });
890
- }
891
- /**
892
- * Update margin for an existing position (add or remove)
893
- *
894
- * @param params
895
- */
896
- async updateMargin(params) {
897
- const provider = this.getActiveProvider();
898
- this.ensureTradingServiceDeps();
899
- return this.tradingService.updateMargin({
900
- provider,
901
- symbol: params.symbol,
902
- amount: params.amount,
903
- context: this.createServiceContext('updateMargin'),
904
- });
905
- }
906
- /**
907
- * Flip position (reverse direction while keeping size and leverage)
908
- *
909
- * @param params
910
- */
911
- async flipPosition(params) {
912
- const provider = this.getActiveProvider();
913
- this.ensureTradingServiceDeps();
914
- return this.tradingService.flipPosition({
915
- provider,
916
- position: params.position,
917
- context: this.createServiceContext('flipPosition'),
918
- });
919
- }
920
- /**
921
- * Simplified deposit method that prepares transaction for confirmation screen
922
- * No complex state tracking - just sets a loading flag
923
- *
924
- * @param amount
925
- */
926
- async depositWithConfirmation(amount) {
927
- const { controllers } = this.options.infrastructure;
928
- try {
929
- // Clear any stale results when starting a new deposit flow
930
- // Don't set depositInProgress yet - wait until user confirms
931
- // Prepare deposit transaction using DepositService
932
- const provider = this.getActiveProvider();
933
- const { transaction, assetChainId, currentDepositId } = await this.depositService.prepareTransaction({ provider });
934
- this.update((state) => {
935
- state.lastDepositResult = null;
936
- // Get current account address via infrastructure
937
- const evmAccount = this.options.infrastructure.controllers.accounts.getSelectedEvmAccount();
938
- const accountAddress = evmAccount?.address || 'unknown';
939
- // Add deposit request to tracking
940
- const depositRequest = {
941
- id: currentDepositId,
942
- timestamp: Date.now(),
943
- amount: amount || '0', // Use provided amount or default to '0'
944
- asset: USDC_SYMBOL,
945
- accountAddress, // Track which account initiated deposit
946
- success: false, // Will be updated when transaction completes
947
- txHash: undefined,
948
- status: 'pending',
949
- source: undefined,
950
- transactionId: undefined, // Will be set to depositId when available
951
- };
952
- state.depositRequests.unshift(depositRequest); // Add to beginning of array
953
- });
954
- const networkClientId = controllers.network.findNetworkClientIdForChain(assetChainId);
955
- if (!networkClientId) {
956
- throw new Error(`No network client found for chain ${assetChainId}. Please add the network first.`);
957
- }
958
- const gasFeeToken = transaction.to &&
959
- assetChainId.toLowerCase() === ARBITRUM_MAINNET_CHAIN_ID_HEX &&
960
- transaction.to.toLowerCase() ===
961
- USDC_ARBITRUM_MAINNET_ADDRESS.toLowerCase()
962
- ? transaction.to
963
- : undefined;
964
- // submit shows the confirmation screen and returns a promise
965
- // The promise will resolve when transaction completes or reject if cancelled/failed
966
- const { result, transactionMeta } = await controllers.transaction.submit(transaction, {
967
- networkClientId,
968
- origin: 'metamask',
969
- type: TransactionType.perpsDeposit,
970
- skipInitialGasEstimate: true,
971
- gasFeeToken,
972
- });
973
- // Store the transaction ID and try to get amount from transaction
974
- this.update((state) => {
975
- state.lastDepositTransactionId = transactionMeta.id;
976
- });
977
- // At this point, the confirmation modal is shown to the user
978
- // The result promise will resolve/reject based on user action and transaction outcome
979
- // Track the transaction lifecycle
980
- // The result promise will resolve/reject based on user action and transaction outcome
981
- // Note: We intentionally don't set depositInProgress immediately to avoid
982
- // showing toasts before the user confirms the transaction
983
- // TODO: @abretonc7s Find a better way to trigger our custom toast notification then having to toggle the state
984
- // How to replace the system notifications?
985
- result
986
- .then((actualTxHash) => {
987
- // Transaction was successfully completed
988
- // Set depositInProgress to true temporarily to show success
989
- this.update((state) => {
990
- state.depositInProgress = true;
991
- state.lastDepositResult = {
992
- success: true,
993
- txHash: actualTxHash,
994
- amount: amount || '0',
995
- asset: USDC_SYMBOL, // Default asset for deposits
996
- timestamp: Date.now(),
997
- error: '',
998
- };
999
- // Update the deposit request by request ID to avoid race conditions
1000
- if (state.depositRequests.length > 0) {
1001
- const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
1002
- if (requestToUpdate) {
1003
- // For deposits, we have a txHash immediately, so mark as completed
1004
- // (the transaction hash means the deposit was successful)
1005
- requestToUpdate.status = 'completed';
1006
- requestToUpdate.success = true;
1007
- requestToUpdate.txHash = actualTxHash;
1008
- }
1009
- }
1010
- });
1011
- // Clear depositInProgress after a short delay
1012
- setTimeout(() => {
1013
- this.update((state) => {
1014
- state.depositInProgress = false;
1015
- state.lastDepositTransactionId = null;
1016
- });
1017
- }, 100);
1018
- })
1019
- .catch((error) => {
1020
- // Check if user denied/cancelled the transaction
1021
- const errorMessage = error instanceof Error ? error.message : String(error);
1022
- const userCancelled = errorMessage.includes('User denied') ||
1023
- errorMessage.includes('User rejected') ||
1024
- errorMessage.includes('User cancelled') ||
1025
- errorMessage.includes('User canceled');
1026
- if (userCancelled) {
1027
- // User cancelled - clear any state, no toast
1028
- this.update((state) => {
1029
- state.depositInProgress = false;
1030
- state.lastDepositTransactionId = null;
1031
- // Don't set lastDepositResult - no toast needed
1032
- });
1033
- }
1034
- else {
1035
- // Transaction failed after confirmation - show error toast
1036
- this.update((state) => {
1037
- state.depositInProgress = false;
1038
- state.lastDepositTransactionId = null;
1039
- state.lastDepositResult = {
1040
- success: false,
1041
- error: errorMessage,
1042
- amount: amount || '0',
1043
- asset: USDC_SYMBOL, // Default asset for deposits
1044
- timestamp: Date.now(),
1045
- txHash: '',
1046
- };
1047
- // Update the deposit request by request ID to avoid race conditions
1048
- if (state.depositRequests.length > 0) {
1049
- const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
1050
- if (requestToUpdate) {
1051
- requestToUpdate.status = 'failed';
1052
- requestToUpdate.success = false;
1053
- }
1054
- }
1055
- });
1056
- }
1057
- });
1058
- return {
1059
- result,
1060
- };
1061
- }
1062
- catch (error) {
1063
- // Check if user denied/cancelled the transaction
1064
- const errorMessage = error instanceof Error ? error.message : String(error);
1065
- const userCancelled = errorMessage.includes('User denied') ||
1066
- errorMessage.includes('User rejected') ||
1067
- errorMessage.includes('User cancelled') ||
1068
- errorMessage.includes('User canceled');
1069
- if (!userCancelled) {
1070
- // Only track actual errors, not user cancellations
1071
- this.update((state) => {
1072
- state.lastDepositTransactionId = null;
1073
- // Note: lastDepositResult is already set in the catch block above
1074
- });
1075
- }
1076
- throw error;
1077
- }
1078
- }
1079
- /**
1080
- * Clear the last deposit result after it has been shown to the user
1081
- */
1082
- clearDepositResult() {
1083
- this.update((state) => {
1084
- state.lastDepositResult = null;
1085
- });
1086
- }
1087
- clearWithdrawResult() {
1088
- this.update((state) => {
1089
- state.lastWithdrawResult = null;
1090
- });
1091
- }
1092
- /**
1093
- * Update withdrawal request status when it completes
1094
- * This is called when a withdrawal is matched with a completed withdrawal from the API
1095
- *
1096
- * @param withdrawalId
1097
- * @param status
1098
- * @param txHash
1099
- */
1100
- updateWithdrawalStatus(withdrawalId, status, txHash) {
1101
- let withdrawalAmount;
1102
- this.update((state) => {
1103
- const withdrawalIndex = state.withdrawalRequests.findIndex((request) => request.id === withdrawalId);
1104
- if (withdrawalIndex >= 0) {
1105
- const request = state.withdrawalRequests[withdrawalIndex];
1106
- withdrawalAmount = request.amount;
1107
- const originalStatus = request.status;
1108
- request.status = status;
1109
- request.success = status === 'completed';
1110
- if (txHash) {
1111
- request.txHash = txHash;
1112
- }
1113
- // Clear withdrawal progress when withdrawal completes
1114
- if (status === 'completed' || status === 'failed') {
1115
- state.withdrawalProgress = {
1116
- progress: 0,
1117
- lastUpdated: Date.now(),
1118
- activeWithdrawalId: null,
1119
- };
1120
- }
1121
- // Track withdrawal transaction completed/failed (confirmed via HyperLiquid API)
1122
- if (withdrawalAmount !== undefined && originalStatus !== status) {
1123
- this.getMetrics().trackPerpsEvent(PerpsAnalyticsEvent.WithdrawalTransaction, {
1124
- [PerpsEventProperties.STATUS]: status === 'completed'
1125
- ? PerpsEventValues.STATUS.COMPLETED
1126
- : PerpsEventValues.STATUS.FAILED,
1127
- [PerpsEventProperties.WITHDRAWAL_AMOUNT]: Number.parseFloat(withdrawalAmount),
1128
- });
1129
- }
1130
- this.debugLog('PerpsController: Updated withdrawal status', {
1131
- withdrawalId,
1132
- status,
1133
- txHash,
1134
- });
1135
- }
1136
- });
1137
- }
1138
- /**
1139
- * Update withdrawal progress (persistent across navigation)
1140
- *
1141
- * @param progress
1142
- * @param activeWithdrawalId
1143
- */
1144
- updateWithdrawalProgress(progress, activeWithdrawalId = null) {
1145
- this.update((state) => {
1146
- state.withdrawalProgress = {
1147
- progress,
1148
- lastUpdated: Date.now(),
1149
- activeWithdrawalId,
1150
- };
1151
- });
1152
- }
1153
- /**
1154
- * Get current withdrawal progress
1155
- */
1156
- getWithdrawalProgress() {
1157
- return this.state.withdrawalProgress;
1158
- }
1159
- /**
1160
- * Withdraw funds from trading account
1161
- *
1162
- * The withdrawal process varies by provider and may involve:
1163
- * - Direct on-chain transfers
1164
- * - Bridge operations
1165
- * - Multi-step validation processes
1166
- *
1167
- * Check the specific provider documentation for detailed withdrawal flows.
1168
- *
1169
- * @param params Withdrawal parameters
1170
- * @returns WithdrawResult with withdrawal ID and tracking info
1171
- */
1172
- async withdraw(params) {
1173
- const provider = this.getActiveProvider();
1174
- return this.accountService.withdraw({
1175
- provider,
1176
- params,
1177
- context: this.createServiceContext('withdraw'),
1178
- refreshAccountState: async () => {
1179
- await this.getAccountState({ source: 'post_withdrawal' });
71
+ constructor({ messenger, state, }) {
72
+ super({
73
+ messenger,
74
+ metadata: perpsControllerMetadata,
75
+ name: controllerName,
76
+ state: {
77
+ ...getDefaultPerpsControllerState(),
78
+ ...state,
1180
79
  },
1181
80
  });
1182
81
  }
1183
- /**
1184
- * Get current positions
1185
- * Thin delegation to MarketDataService
1186
- *
1187
- * @param params
1188
- */
1189
- async getPositions(params) {
1190
- const provider = this.getActiveProvider();
1191
- return this.marketDataService.getPositions({
1192
- provider,
1193
- params,
1194
- context: this.createServiceContext('getPositions'),
1195
- });
1196
- }
1197
- /**
1198
- * Get historical user fills (trade executions)
1199
- * Thin delegation to MarketDataService
1200
- *
1201
- * @param params
1202
- */
1203
- async getOrderFills(params) {
1204
- const provider = this.getActiveProvider();
1205
- return this.marketDataService.getOrderFills({
1206
- provider,
1207
- params,
1208
- context: this.createServiceContext('getOrderFills'),
1209
- });
1210
- }
1211
- /**
1212
- * Get historical user orders (order lifecycle)
1213
- * Thin delegation to MarketDataService
1214
- *
1215
- * @param params
1216
- */
1217
- async getOrders(params) {
1218
- const provider = this.getActiveProvider();
1219
- return this.marketDataService.getOrders({
1220
- provider,
1221
- params,
1222
- context: this.createServiceContext('getOrders'),
1223
- });
1224
- }
1225
- /**
1226
- * Get currently open orders (real-time status)
1227
- * Thin delegation to MarketDataService
1228
- *
1229
- * @param params
1230
- */
1231
- async getOpenOrders(params) {
1232
- const provider = this.getActiveProvider();
1233
- return this.marketDataService.getOpenOrders({
1234
- provider,
1235
- params,
1236
- context: this.createServiceContext('getOpenOrders'),
1237
- });
1238
- }
1239
- /**
1240
- * Get historical user funding history (funding payments)
1241
- * Thin delegation to MarketDataService
1242
- *
1243
- * @param params
1244
- */
1245
- async getFunding(params) {
1246
- const provider = this.getActiveProvider();
1247
- return this.marketDataService.getFunding({
1248
- provider,
1249
- params,
1250
- context: this.createServiceContext('getFunding'),
1251
- });
1252
- }
1253
- /**
1254
- * Get account state (balances, etc.)
1255
- * Thin delegation to MarketDataService
1256
- *
1257
- * @param params
1258
- */
1259
- async getAccountState(params) {
1260
- const provider = this.getActiveProvider();
1261
- return this.marketDataService.getAccountState({
1262
- provider,
1263
- params,
1264
- context: this.createServiceContext('getAccountState'),
1265
- });
1266
- }
1267
- /**
1268
- * Get historical portfolio data
1269
- * Thin delegation to MarketDataService
1270
- *
1271
- * @param params
1272
- */
1273
- async getHistoricalPortfolio(params) {
1274
- const provider = this.getActiveProvider();
1275
- return this.marketDataService.getHistoricalPortfolio({
1276
- provider,
1277
- params,
1278
- context: this.createServiceContext('getHistoricalPortfolio'),
1279
- });
1280
- }
1281
- /**
1282
- * Get available markets with optional filtering
1283
- * Thin delegation to MarketDataService
1284
- *
1285
- * For readOnly mode, bypasses getActiveProvider() to allow market discovery
1286
- * without full perps initialization (e.g., for discovery banners on spot screens)
1287
- *
1288
- * @param params
1289
- */
1290
- async getMarkets(params) {
1291
- // For readOnly mode, access provider directly without initialization check
1292
- // This allows discovery use cases (checking if market exists) without full perps setup
1293
- if (params?.readOnly) {
1294
- // Try to get existing provider, or create a temporary one for readOnly queries
1295
- // Note: 'aggregated' mode uses activeProviderInstance directly, not the providers map
1296
- const { activeProvider } = this.state;
1297
- let provider = activeProvider === 'aggregated'
1298
- ? undefined
1299
- : this.providers.get(activeProvider);
1300
- // Create a temporary provider instance for readOnly queries
1301
- // The readOnly path in provider creates a standalone InfoClient without full init
1302
- provider ?? (provider = new HyperLiquidProvider({
1303
- isTestnet: this.state.isTestnet,
1304
- hip3Enabled: this.hip3Enabled,
1305
- allowlistMarkets: this.hip3AllowlistMarkets,
1306
- blocklistMarkets: this.hip3BlocklistMarkets,
1307
- platformDependencies: this.options.infrastructure,
1308
- }));
1309
- return provider.getMarkets(params);
1310
- }
1311
- const provider = this.getActiveProvider();
1312
- return this.marketDataService.getMarkets({
1313
- provider,
1314
- params,
1315
- context: this.createServiceContext('getMarkets'),
1316
- });
1317
- }
1318
- /**
1319
- * Get list of available HIP-3 builder-deployed DEXs
1320
- *
1321
- * @param params - Optional parameters for filtering
1322
- * @returns Array of DEX names
1323
- */
1324
- async getAvailableDexs(params) {
1325
- const provider = this.getActiveProvider();
1326
- const context = this.createServiceContext('getAvailableDexs');
1327
- return this.marketDataService.getAvailableDexs({
1328
- provider,
1329
- params,
1330
- context,
1331
- });
1332
- }
1333
- /**
1334
- * Fetch historical candle data
1335
- * Thin delegation to MarketDataService
1336
- *
1337
- * @param symbol
1338
- * @param interval
1339
- * @param limit
1340
- * @param endTime
1341
- */
1342
- async fetchHistoricalCandles(symbol, interval, limit = 100, endTime) {
1343
- const provider = this.getActiveProvider();
1344
- return this.marketDataService.fetchHistoricalCandles({
1345
- provider,
1346
- symbol,
1347
- interval,
1348
- limit,
1349
- endTime,
1350
- context: this.createServiceContext('fetchHistoricalCandles'),
1351
- });
1352
- }
1353
- /**
1354
- * Calculate liquidation price for a position
1355
- * Uses provider-specific formulas based on protocol rules
1356
- *
1357
- * @param params
1358
- */
1359
- async calculateLiquidationPrice(params) {
1360
- const provider = this.getActiveProvider();
1361
- const context = this.createServiceContext('calculateLiquidationPrice');
1362
- return this.marketDataService.calculateLiquidationPrice({
1363
- provider,
1364
- params,
1365
- context,
1366
- });
1367
- }
1368
- /**
1369
- * Calculate maintenance margin for a specific asset
1370
- * Returns a percentage (e.g., 0.0125 for 1.25%)
1371
- *
1372
- * @param params
1373
- */
1374
- async calculateMaintenanceMargin(params) {
1375
- const provider = this.getActiveProvider();
1376
- const context = this.createServiceContext('calculateMaintenanceMargin');
1377
- return this.marketDataService.calculateMaintenanceMargin({
1378
- provider,
1379
- params,
1380
- context,
1381
- });
1382
- }
1383
- /**
1384
- * Get maximum leverage allowed for an asset
1385
- *
1386
- * @param asset
1387
- */
1388
- async getMaxLeverage(asset) {
1389
- const provider = this.getActiveProvider();
1390
- const context = this.createServiceContext('getMaxLeverage');
1391
- return this.marketDataService.getMaxLeverage({ provider, asset, context });
1392
- }
1393
- /**
1394
- * Validate order parameters according to protocol-specific rules
1395
- *
1396
- * @param params
1397
- */
1398
- async validateOrder(params) {
1399
- const provider = this.getActiveProvider();
1400
- const context = this.createServiceContext('validateOrder');
1401
- return this.marketDataService.validateOrder({ provider, params, context });
1402
- }
1403
- /**
1404
- * Validate close position parameters according to protocol-specific rules
1405
- *
1406
- * @param params
1407
- */
1408
- async validateClosePosition(params) {
1409
- const provider = this.getActiveProvider();
1410
- const context = this.createServiceContext('validateClosePosition');
1411
- return this.marketDataService.validateClosePosition({
1412
- provider,
1413
- params,
1414
- context,
1415
- });
1416
- }
1417
- /**
1418
- * Validate withdrawal parameters according to protocol-specific rules
1419
- *
1420
- * @param params
1421
- */
1422
- async validateWithdrawal(params) {
1423
- const provider = this.getActiveProvider();
1424
- return this.accountService.validateWithdrawal({ provider, params });
1425
- }
1426
- /**
1427
- * Get supported withdrawal routes - returns complete asset and routing information
1428
- */
1429
- getWithdrawalRoutes() {
1430
- try {
1431
- const provider = this.getActiveProvider();
1432
- return this.marketDataService.getWithdrawalRoutes({ provider });
1433
- }
1434
- catch (error) {
1435
- this.logError(ensureError(error), this.getErrorContext('getWithdrawalRoutes'));
1436
- // Return empty array if provider is not available
1437
- return [];
1438
- }
1439
- }
1440
- /**
1441
- * Toggle between testnet and mainnet
1442
- */
1443
- async toggleTestnet() {
1444
- // Prevent concurrent reinitializations
1445
- if (this.isReinitializing) {
1446
- this.debugLog('PerpsController: Already reinitializing, skipping toggle', {
1447
- timestamp: new Date().toISOString(),
1448
- });
1449
- return {
1450
- success: false,
1451
- isTestnet: this.state.isTestnet,
1452
- error: PERPS_ERROR_CODES.CLIENT_REINITIALIZING,
1453
- };
1454
- }
1455
- this.isReinitializing = true;
1456
- try {
1457
- const previousNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
1458
- this.update((state) => {
1459
- state.isTestnet = !state.isTestnet;
1460
- });
1461
- const newNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
1462
- this.debugLog('PerpsController: Network toggle initiated', {
1463
- from: previousNetwork,
1464
- to: newNetwork,
1465
- timestamp: new Date().toISOString(),
1466
- });
1467
- // Reset initialization state and reinitialize provider with new testnet setting
1468
- this.isInitialized = false;
1469
- this.initializationPromise = null;
1470
- await this.init();
1471
- this.debugLog('PerpsController: Network toggle completed', {
1472
- newNetwork,
1473
- isTestnet: this.state.isTestnet,
1474
- timestamp: new Date().toISOString(),
1475
- });
1476
- return { success: true, isTestnet: this.state.isTestnet };
1477
- }
1478
- catch (error) {
1479
- return {
1480
- success: false,
1481
- isTestnet: this.state.isTestnet,
1482
- error: error instanceof Error
1483
- ? error.message
1484
- : PERPS_ERROR_CODES.UNKNOWN_ERROR,
1485
- };
1486
- }
1487
- finally {
1488
- this.isReinitializing = false;
1489
- }
1490
- }
1491
- /**
1492
- * Switch to a different provider
1493
- *
1494
- * @param providerId
1495
- */
1496
- async switchProvider(providerId) {
1497
- // 'aggregated' is always valid, individual providers must exist in the map
1498
- const isValidProvider = providerId === 'aggregated' || this.providers.has(providerId);
1499
- if (!isValidProvider) {
1500
- return {
1501
- success: false,
1502
- providerId: this.state.activeProvider,
1503
- error: `Provider ${providerId} not available`,
1504
- };
1505
- }
1506
- this.update((state) => {
1507
- state.activeProvider = providerId;
1508
- });
1509
- return { success: true, providerId };
1510
- }
1511
- /**
1512
- * Get current network (mainnet/testnet)
1513
- */
1514
- getCurrentNetwork() {
1515
- return this.state.isTestnet ? 'testnet' : 'mainnet';
1516
- }
1517
- /**
1518
- * Get the current WebSocket connection state from the active provider.
1519
- * Used by the UI to monitor connection health and show notifications.
1520
- *
1521
- * @returns The current WebSocket connection state, or DISCONNECTED if not supported
1522
- */
1523
- getWebSocketConnectionState() {
1524
- try {
1525
- const provider = this.getActiveProvider();
1526
- if (provider.getWebSocketConnectionState) {
1527
- return provider.getWebSocketConnectionState();
1528
- }
1529
- // Fallback for providers that don't support this method
1530
- return WebSocketConnectionState.Disconnected;
1531
- }
1532
- catch {
1533
- // If no provider is active, return disconnected
1534
- return WebSocketConnectionState.Disconnected;
1535
- }
1536
- }
1537
- /**
1538
- * Subscribe to WebSocket connection state changes from the active provider.
1539
- * The listener will be called immediately with the current state and whenever the state changes.
1540
- *
1541
- * @param listener - Callback function that receives the new connection state and reconnection attempt
1542
- * @returns Unsubscribe function to remove the listener, or no-op if not supported
1543
- */
1544
- subscribeToConnectionState(listener) {
1545
- try {
1546
- const provider = this.getActiveProvider();
1547
- if (provider.subscribeToConnectionState) {
1548
- return provider.subscribeToConnectionState(listener);
1549
- }
1550
- // Fallback: immediately call with current state and return no-op unsubscribe
1551
- listener(this.getWebSocketConnectionState(), 0);
1552
- return () => {
1553
- // No-op
1554
- };
1555
- }
1556
- catch {
1557
- // If no provider is active, call with disconnected and return no-op
1558
- listener(WebSocketConnectionState.Disconnected, 0);
1559
- return () => {
1560
- // No-op
1561
- };
1562
- }
1563
- }
1564
- /**
1565
- * Manually trigger a WebSocket reconnection attempt.
1566
- * Used by the UI retry button when connection is lost.
1567
- */
1568
- async reconnect() {
1569
- this.debugLog('[PerpsController] reconnect() called');
1570
- try {
1571
- const provider = this.getActiveProvider();
1572
- if (provider.reconnect) {
1573
- this.debugLog('[PerpsController] Delegating to provider.reconnect()');
1574
- await provider.reconnect();
1575
- this.debugLog('[PerpsController] provider.reconnect() completed');
1576
- }
1577
- else {
1578
- this.debugLog('[PerpsController] Provider does not support reconnect()');
1579
- }
1580
- }
1581
- catch (error) {
1582
- this.logError(ensureError(error), this.getErrorContext('reconnect', {
1583
- operation: 'websocket_reconnect',
1584
- }));
1585
- }
1586
- }
1587
- // Live data delegation (NO Redux) - delegates to active provider
1588
- /**
1589
- * Subscribe to live price updates
1590
- *
1591
- * @param params
1592
- */
1593
- subscribeToPrices(params) {
1594
- try {
1595
- const provider = this.getActiveProvider();
1596
- return provider.subscribeToPrices(params);
1597
- }
1598
- catch (error) {
1599
- this.logError(ensureError(error), this.getErrorContext('subscribeToPrices', {
1600
- symbols: params.symbols?.join(','),
1601
- }));
1602
- // Return a no-op unsubscribe function
1603
- return () => {
1604
- // No-op: Provider not initialized
1605
- };
1606
- }
1607
- }
1608
- /**
1609
- * Subscribe to live position updates
1610
- *
1611
- * @param params
1612
- */
1613
- subscribeToPositions(params) {
1614
- try {
1615
- const provider = this.getActiveProvider();
1616
- return provider.subscribeToPositions(params);
1617
- }
1618
- catch (error) {
1619
- this.logError(ensureError(error), this.getErrorContext('subscribeToPositions', {
1620
- accountId: params.accountId,
1621
- }));
1622
- // Return a no-op unsubscribe function
1623
- return () => {
1624
- // No-op: Provider not initialized
1625
- };
1626
- }
1627
- }
1628
- /**
1629
- * Subscribe to live order fill updates
1630
- *
1631
- * @param params
1632
- */
1633
- subscribeToOrderFills(params) {
1634
- try {
1635
- const provider = this.getActiveProvider();
1636
- return provider.subscribeToOrderFills(params);
1637
- }
1638
- catch (error) {
1639
- this.logError(ensureError(error), this.getErrorContext('subscribeToOrderFills', {
1640
- accountId: params.accountId,
1641
- }));
1642
- // Return a no-op unsubscribe function
1643
- return () => {
1644
- // No-op: Provider not initialized
1645
- };
1646
- }
1647
- }
1648
- /**
1649
- * Subscribe to live order updates
1650
- *
1651
- * @param params
1652
- */
1653
- subscribeToOrders(params) {
1654
- try {
1655
- const provider = this.getActiveProvider();
1656
- return provider.subscribeToOrders(params);
1657
- }
1658
- catch (error) {
1659
- this.logError(ensureError(error), this.getErrorContext('subscribeToOrders', {
1660
- accountId: params.accountId,
1661
- }));
1662
- // Return a no-op unsubscribe function
1663
- return () => {
1664
- // No-op: Provider not initialized
1665
- };
1666
- }
1667
- }
1668
- /**
1669
- * Subscribe to live account updates
1670
- *
1671
- * @param params
1672
- */
1673
- subscribeToAccount(params) {
1674
- try {
1675
- const provider = this.getActiveProvider();
1676
- return provider.subscribeToAccount(params);
1677
- }
1678
- catch (error) {
1679
- this.logError(ensureError(error), this.getErrorContext('subscribeToAccount', {
1680
- accountId: params.accountId,
1681
- }));
1682
- // Return a no-op unsubscribe function
1683
- return () => {
1684
- // No-op: Provider not initialized
1685
- };
1686
- }
1687
- }
1688
- /**
1689
- * Subscribe to full order book updates with multiple depth levels
1690
- * Creates a dedicated L2Book subscription for real-time order book data
1691
- *
1692
- * @param params
1693
- */
1694
- subscribeToOrderBook(params) {
1695
- try {
1696
- const provider = this.getActiveProvider();
1697
- return provider.subscribeToOrderBook(params);
1698
- }
1699
- catch (error) {
1700
- this.logError(ensureError(error), this.getErrorContext('subscribeToOrderBook', {
1701
- symbol: params.symbol,
1702
- levels: params.levels,
1703
- }));
1704
- // Return a no-op unsubscribe function
1705
- return () => {
1706
- // No-op: Provider not initialized
1707
- };
1708
- }
1709
- }
1710
- /**
1711
- * Subscribe to live candle updates
1712
- *
1713
- * @param params
1714
- */
1715
- subscribeToCandles(params) {
1716
- try {
1717
- const provider = this.getActiveProvider();
1718
- return provider.subscribeToCandles(params);
1719
- }
1720
- catch (error) {
1721
- this.logError(ensureError(error), this.getErrorContext('subscribeToCandles', {
1722
- symbol: params.symbol,
1723
- interval: params.interval,
1724
- duration: params.duration,
1725
- }));
1726
- // Return a no-op unsubscribe function
1727
- return () => {
1728
- // No-op: Provider not initialized
1729
- };
1730
- }
1731
- }
1732
- /**
1733
- * Subscribe to open interest cap updates
1734
- * Zero additional network overhead - data comes from existing webData3 subscription
1735
- *
1736
- * @param params
1737
- */
1738
- subscribeToOICaps(params) {
1739
- try {
1740
- const provider = this.getActiveProvider();
1741
- return provider.subscribeToOICaps(params);
1742
- }
1743
- catch (error) {
1744
- this.logError(ensureError(error), this.getErrorContext('subscribeToOICaps', {
1745
- accountId: params.accountId,
1746
- }));
1747
- // Return a no-op unsubscribe function
1748
- return () => {
1749
- // No-op: Provider not initialized
1750
- };
1751
- }
1752
- }
1753
- /**
1754
- * Configure live data throttling
1755
- *
1756
- * @param config
1757
- */
1758
- setLiveDataConfig(config) {
1759
- try {
1760
- const provider = this.getActiveProvider();
1761
- provider.setLiveDataConfig(config);
1762
- }
1763
- catch (error) {
1764
- this.logError(ensureError(error), this.getErrorContext('setLiveDataConfig'));
1765
- }
1766
- }
1767
- /**
1768
- * Calculate trading fees for the active provider
1769
- * Each provider implements its own fee structure
1770
- *
1771
- * @param params
1772
- */
1773
- async calculateFees(params) {
1774
- const provider = this.getActiveProvider();
1775
- const context = this.createServiceContext('calculateFees');
1776
- return this.marketDataService.calculateFees({ provider, params, context });
1777
- }
1778
- /**
1779
- * Disconnect provider and cleanup subscriptions
1780
- * Call this when navigating away from Perps screens to prevent battery drain
1781
- */
1782
- async disconnect() {
1783
- this.debugLog('PerpsController: Disconnecting provider to cleanup subscriptions', {
1784
- timestamp: new Date().toISOString(),
1785
- });
1786
- // Only disconnect the provider if we're initialized
1787
- if (this.isInitialized && !this.isReinitializing) {
1788
- try {
1789
- const provider = this.getActiveProvider();
1790
- await provider.disconnect();
1791
- }
1792
- catch (error) {
1793
- this.logError(ensureError(error), this.getErrorContext('disconnect'));
1794
- }
1795
- }
1796
- // Reset initialization state to ensure proper reconnection
1797
- this.isInitialized = false;
1798
- this.initializationPromise = null;
1799
- }
1800
- /**
1801
- * Eligibility (Geo-Blocking)
1802
- */
1803
- /**
1804
- * Fetch geo location
1805
- *
1806
- * Returned in Country or Country-Region format
1807
- * Example: FR, DE, US-MI, CA-ON
1808
- */
1809
- /**
1810
- * Refresh eligibility status
1811
- */
1812
- async refreshEligibility() {
1813
- // Capture the current version before starting the async operation.
1814
- // This prevents race conditions where stale eligibility checks
1815
- // (started with fallback config) overwrite results from newer checks
1816
- // (started with remote config after it was fetched).
1817
- const versionAtStart = this.blockedRegionListVersion;
1818
- try {
1819
- // TODO: It would be good to have this location before we call this async function to avoid the race condition
1820
- const isEligible = await this.eligibilityService.checkEligibility(this.blockedRegionList.list);
1821
- // Only update state if the blocked region list hasn't changed while we were awaiting.
1822
- // This prevents stale fallback-based eligibility checks from overwriting
1823
- // results from remote-based checks.
1824
- if (this.blockedRegionListVersion !== versionAtStart) {
1825
- return;
1826
- }
1827
- this.update((state) => {
1828
- state.isEligible = isEligible;
1829
- });
1830
- }
1831
- catch (error) {
1832
- this.logError(ensureError(error), this.getErrorContext('refreshEligibility'));
1833
- // Only update on error if version is still current
1834
- if (this.blockedRegionListVersion === versionAtStart) {
1835
- // Default to eligible on error
1836
- this.update((state) => {
1837
- state.isEligible = true;
1838
- });
1839
- }
1840
- }
1841
- }
1842
- /**
1843
- * Get block explorer URL for an address or just the base URL
1844
- *
1845
- * @param address - Optional address to append to the base URL
1846
- * @returns Block explorer URL
1847
- */
1848
- getBlockExplorerUrl(address) {
1849
- const provider = this.getActiveProvider();
1850
- return this.marketDataService.getBlockExplorerUrl({ provider, address });
1851
- }
1852
- /**
1853
- * Check if user is first-time for the current network
1854
- */
1855
- isFirstTimeUserOnCurrentNetwork() {
1856
- const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
1857
- return this.state.isFirstTimeUser[currentNetwork];
1858
- }
1859
- /**
1860
- * Mark that the user has completed the tutorial/onboarding
1861
- * This prevents the tutorial from showing again
1862
- */
1863
- markTutorialCompleted() {
1864
- const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
1865
- this.debugLog('PerpsController: Marking tutorial as completed', {
1866
- timestamp: new Date().toISOString(),
1867
- network: currentNetwork,
1868
- });
1869
- this.update((state) => {
1870
- state.isFirstTimeUser[currentNetwork] = false;
1871
- });
1872
- }
1873
- /*
1874
- * Mark that user has placed their first successful order
1875
- * This prevents the notification tooltip from showing again
1876
- */
1877
- markFirstOrderCompleted() {
1878
- const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
1879
- this.debugLog('PerpsController: Marking first order completed', {
1880
- timestamp: new Date().toISOString(),
1881
- network: currentNetwork,
1882
- });
1883
- this.update((state) => {
1884
- state.hasPlacedFirstOrder[currentNetwork] = true;
1885
- });
1886
- }
1887
- /**
1888
- * Reset first-time user state for both networks
1889
- * This is useful for testing the tutorial flow
1890
- * Called by Reset Account feature in settings
1891
- */
1892
- resetFirstTimeUserState() {
1893
- this.debugLog('PerpsController: Resetting first-time user state', {
1894
- timestamp: new Date().toISOString(),
1895
- previousState: this.state.isFirstTimeUser,
1896
- });
1897
- this.update((state) => {
1898
- state.isFirstTimeUser = {
1899
- testnet: true,
1900
- mainnet: true,
1901
- };
1902
- state.hasPlacedFirstOrder = {
1903
- testnet: false,
1904
- mainnet: false,
1905
- };
1906
- });
1907
- }
1908
- /**
1909
- * Clear pending/bridging withdrawal and deposit requests
1910
- * This is useful when users want to clear stuck pending indicators
1911
- * Called by Reset Account feature in settings
1912
- */
1913
- clearPendingTransactionRequests() {
1914
- this.debugLog('PerpsController: Clearing pending transaction requests', {
1915
- timestamp: new Date().toISOString(),
1916
- });
1917
- this.update((state) => {
1918
- // Filter out pending/bridging withdrawals, keep completed/failed for history
1919
- state.withdrawalRequests = state.withdrawalRequests.filter((req) => req.status !== 'pending' && req.status !== 'bridging');
1920
- // Filter out pending deposits, keep completed/failed for history
1921
- state.depositRequests = state.depositRequests.filter((req) => req.status !== 'pending' && req.status !== 'bridging');
1922
- // Reset withdrawal progress
1923
- state.withdrawalProgress = {
1924
- progress: 0,
1925
- lastUpdated: Date.now(),
1926
- activeWithdrawalId: null,
1927
- };
1928
- });
1929
- }
1930
- /**
1931
- * Get saved trade configuration for a market
1932
- *
1933
- * @param symbol
1934
- */
1935
- getTradeConfiguration(symbol) {
1936
- const network = this.state.isTestnet ? 'testnet' : 'mainnet';
1937
- const config = this.state.tradeConfigurations[network]?.[symbol];
1938
- if (!config?.leverage) {
1939
- return undefined;
1940
- }
1941
- this.debugLog('PerpsController: Retrieved trade config', {
1942
- symbol,
1943
- network,
1944
- leverage: config.leverage,
1945
- });
1946
- return { leverage: config.leverage };
1947
- }
1948
- /**
1949
- * Save trade configuration for a market
1950
- *
1951
- * @param symbol - Market symbol
1952
- * @param leverage - Leverage value
1953
- */
1954
- saveTradeConfiguration(symbol, leverage) {
1955
- const network = this.state.isTestnet ? 'testnet' : 'mainnet';
1956
- this.debugLog('PerpsController: Saving trade configuration', {
1957
- symbol,
1958
- network,
1959
- leverage,
1960
- timestamp: new Date().toISOString(),
1961
- });
1962
- this.update((state) => {
1963
- if (!state.tradeConfigurations[network]) {
1964
- state.tradeConfigurations[network] = {};
1965
- }
1966
- const existingConfig = state.tradeConfigurations[network][symbol] || {};
1967
- state.tradeConfigurations[network][symbol] = {
1968
- ...existingConfig,
1969
- leverage,
1970
- };
1971
- });
1972
- }
1973
- /**
1974
- * Save pending trade configuration for a market
1975
- * This is a temporary configuration that expires after 5 minutes
1976
- *
1977
- * @param symbol - Market symbol
1978
- * @param config - Pending trade configuration
1979
- * @param config.amount
1980
- * @param config.leverage
1981
- * @param config.takeProfitPrice
1982
- * @param config.stopLossPrice
1983
- * @param config.limitPrice
1984
- * @param config.orderType
1985
- */
1986
- savePendingTradeConfiguration(symbol, config) {
1987
- const network = this.state.isTestnet ? 'testnet' : 'mainnet';
1988
- this.debugLog('PerpsController: Saving pending trade configuration', {
1989
- symbol,
1990
- network,
1991
- config,
1992
- timestamp: new Date().toISOString(),
1993
- });
1994
- this.update((state) => {
1995
- if (!state.tradeConfigurations[network]) {
1996
- state.tradeConfigurations[network] = {};
1997
- }
1998
- const existingConfig = state.tradeConfigurations[network][symbol] || {};
1999
- state.tradeConfigurations[network][symbol] = {
2000
- ...existingConfig,
2001
- pendingConfig: {
2002
- ...config,
2003
- timestamp: Date.now(),
2004
- },
2005
- };
2006
- });
2007
- }
2008
- /**
2009
- * Get pending trade configuration for a market
2010
- * Returns undefined if config doesn't exist or has expired (more than 5 minutes old)
2011
- *
2012
- * @param symbol - Market symbol
2013
- * @returns Pending trade configuration or undefined
2014
- */
2015
- getPendingTradeConfiguration(symbol) {
2016
- const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2017
- const config = this.state.tradeConfigurations[network]?.[symbol]?.pendingConfig;
2018
- if (!config) {
2019
- return undefined;
2020
- }
2021
- // Check if config has expired (5 minutes = 300,000 milliseconds)
2022
- const FIVE_MINUTES_MS = 5 * 60 * 1000;
2023
- const now = Date.now();
2024
- const age = now - config.timestamp;
2025
- if (age > FIVE_MINUTES_MS) {
2026
- this.debugLog('PerpsController: Pending trade config expired', {
2027
- symbol,
2028
- network,
2029
- age,
2030
- timestamp: config.timestamp,
2031
- });
2032
- // Clear expired config
2033
- this.update((state) => {
2034
- if (state.tradeConfigurations[network]?.[symbol]?.pendingConfig) {
2035
- delete state.tradeConfigurations[network][symbol].pendingConfig;
2036
- }
2037
- });
2038
- return undefined;
2039
- }
2040
- this.debugLog('PerpsController: Retrieved pending trade config', {
2041
- symbol,
2042
- network,
2043
- config,
2044
- age,
2045
- });
2046
- // Return config without timestamp
2047
- const { timestamp, ...configWithoutTimestamp } = config;
2048
- return configWithoutTimestamp;
2049
- }
2050
- /**
2051
- * Clear pending trade configuration for a market
2052
- *
2053
- * @param symbol - Market symbol
2054
- */
2055
- clearPendingTradeConfiguration(symbol) {
2056
- const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2057
- this.debugLog('PerpsController: Clearing pending trade configuration', {
2058
- symbol,
2059
- network,
2060
- timestamp: new Date().toISOString(),
2061
- });
2062
- this.update((state) => {
2063
- if (state.tradeConfigurations[network]?.[symbol]?.pendingConfig) {
2064
- delete state.tradeConfigurations[network][symbol].pendingConfig;
2065
- }
2066
- });
2067
- }
2068
- /**
2069
- * Get saved market filter preferences
2070
- * Handles backward compatibility with legacy string format
2071
- */
2072
- getMarketFilterPreferences() {
2073
- const pref = this.state.marketFilterPreferences;
2074
- // Handle legacy string format (backward compatibility)
2075
- if (typeof pref === 'string') {
2076
- // Map legacy compound IDs to new format
2077
- // Old format: 'priceChange-desc' or 'priceChange-asc'
2078
- // New format: { optionId: 'priceChange', direction: 'desc'/'asc' }
2079
- if (pref === 'priceChange-desc') {
2080
- return {
2081
- optionId: 'priceChange',
2082
- direction: 'desc',
2083
- };
2084
- }
2085
- if (pref === 'priceChange-asc') {
2086
- return {
2087
- optionId: 'priceChange',
2088
- direction: 'asc',
2089
- };
2090
- }
2091
- // Handle other simple legacy strings (e.g., 'volume', 'openInterest', etc.)
2092
- return {
2093
- optionId: pref,
2094
- direction: MARKET_SORTING_CONFIG.DefaultDirection,
2095
- };
2096
- }
2097
- // Return new object format or default
2098
- return (pref ?? {
2099
- optionId: MARKET_SORTING_CONFIG.DefaultSortOptionId,
2100
- direction: MARKET_SORTING_CONFIG.DefaultDirection,
2101
- });
2102
- }
2103
- /**
2104
- * Save market filter preferences
2105
- *
2106
- * @param optionId - Sort/filter option ID
2107
- * @param direction - Sort direction ('asc' or 'desc')
2108
- */
2109
- saveMarketFilterPreferences(optionId, direction) {
2110
- this.debugLog('PerpsController: Saving market filter preferences', {
2111
- optionId,
2112
- direction,
2113
- timestamp: new Date().toISOString(),
2114
- });
2115
- this.update((state) => {
2116
- state.marketFilterPreferences = { optionId, direction };
2117
- });
2118
- }
2119
- /**
2120
- * Get saved order book grouping for a market
2121
- *
2122
- * @param symbol - Market symbol
2123
- * @returns The saved grouping value or undefined if not set
2124
- */
2125
- getOrderBookGrouping(symbol) {
2126
- const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2127
- const grouping = this.state.tradeConfigurations[network]?.[symbol]?.orderBookGrouping;
2128
- if (grouping !== undefined) {
2129
- this.debugLog('PerpsController: Retrieved order book grouping', {
2130
- symbol,
2131
- network,
2132
- grouping,
2133
- });
2134
- }
2135
- return grouping;
2136
- }
2137
- /**
2138
- * Save order book grouping for a market
2139
- *
2140
- * @param symbol - Market symbol
2141
- * @param grouping - Price grouping value
2142
- */
2143
- saveOrderBookGrouping(symbol, grouping) {
2144
- const network = this.state.isTestnet ? 'testnet' : 'mainnet';
2145
- this.debugLog('PerpsController: Saving order book grouping', {
2146
- symbol,
2147
- network,
2148
- grouping,
2149
- timestamp: new Date().toISOString(),
2150
- });
2151
- this.update((state) => {
2152
- if (!state.tradeConfigurations[network]) {
2153
- state.tradeConfigurations[network] = {};
2154
- }
2155
- const existingConfig = state.tradeConfigurations[network][symbol] || {};
2156
- state.tradeConfigurations[network][symbol] = {
2157
- ...existingConfig,
2158
- orderBookGrouping: grouping,
2159
- };
2160
- });
2161
- }
2162
- /**
2163
- * Toggle watchlist status for a market
2164
- * Watchlist markets are stored per network (testnet/mainnet)
2165
- *
2166
- * @param symbol
2167
- */
2168
- toggleWatchlistMarket(symbol) {
2169
- const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2170
- const currentWatchlist = this.state.watchlistMarkets[currentNetwork];
2171
- const isWatchlisted = currentWatchlist.includes(symbol);
2172
- this.debugLog('PerpsController: Toggling watchlist market', {
2173
- timestamp: new Date().toISOString(),
2174
- network: currentNetwork,
2175
- symbol,
2176
- action: isWatchlisted ? 'remove' : 'add',
2177
- });
2178
- this.update((state) => {
2179
- if (isWatchlisted) {
2180
- // Remove from watchlist
2181
- state.watchlistMarkets[currentNetwork] = currentWatchlist.filter((s) => s !== symbol);
2182
- }
2183
- else {
2184
- // Add to watchlist
2185
- state.watchlistMarkets[currentNetwork] = [...currentWatchlist, symbol];
2186
- }
2187
- });
2188
- }
2189
- /**
2190
- * Check if a market is in the watchlist on the current network
2191
- *
2192
- * @param symbol
2193
- */
2194
- isWatchlistMarket(symbol) {
2195
- const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2196
- return this.state.watchlistMarkets[currentNetwork].includes(symbol);
2197
- }
2198
- /**
2199
- * Get all watchlist markets for the current network
2200
- */
2201
- getWatchlistMarkets() {
2202
- const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
2203
- return this.state.watchlistMarkets[currentNetwork];
2204
- }
2205
- /**
2206
- * Report order events to data lake API with retry (non-blocking)
2207
- * Thin delegation to DataLakeService
2208
- *
2209
- * @param params
2210
- * @param params.action
2211
- * @param params.symbol
2212
- * @param params.sl_price
2213
- * @param params.tp_price
2214
- * @param params.retryCount
2215
- * @param params._traceId
2216
- */
2217
- async reportOrderToDataLake(params) {
2218
- return this.dataLakeService.reportOrder({
2219
- action: params.action,
2220
- symbol: params.symbol,
2221
- sl_price: params.sl_price,
2222
- tp_price: params.tp_price,
2223
- isTestnet: this.state.isTestnet,
2224
- context: this.createServiceContext('reportOrderToDataLake', {
2225
- messenger: this.messenger,
2226
- }),
2227
- retryCount: params.retryCount,
2228
- _traceId: params._traceId,
2229
- });
2230
- }
2231
- /**
2232
- * Check if the controller is currently reinitializing
2233
- *
2234
- * @returns true if providers are being reinitialized
2235
- */
2236
- isCurrentlyReinitializing() {
2237
- return this.isReinitializing;
2238
- }
2239
82
  }
2240
83
  //# sourceMappingURL=PerpsController.mjs.map