@metamask-previews/perps-controller 11.0.0-preview-9efd0b754 → 12.0.0-preview-4e64b66e8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -1
- package/dist/PerpsController-method-action-types.cjs.map +1 -1
- package/dist/PerpsController-method-action-types.d.cts +36 -1
- package/dist/PerpsController-method-action-types.d.cts.map +1 -1
- package/dist/PerpsController-method-action-types.d.mts +36 -1
- package/dist/PerpsController-method-action-types.d.mts.map +1 -1
- package/dist/PerpsController-method-action-types.mjs.map +1 -1
- package/dist/PerpsController.cjs +600 -119
- package/dist/PerpsController.cjs.map +1 -1
- package/dist/PerpsController.d.cts +35 -4
- package/dist/PerpsController.d.cts.map +1 -1
- package/dist/PerpsController.d.mts +35 -4
- package/dist/PerpsController.d.mts.map +1 -1
- package/dist/PerpsController.mjs +603 -122
- package/dist/PerpsController.mjs.map +1 -1
- package/dist/constants/eventNames.cjs +3 -0
- package/dist/constants/eventNames.cjs.map +1 -1
- package/dist/constants/eventNames.d.cts +1 -0
- package/dist/constants/eventNames.d.cts.map +1 -1
- package/dist/constants/eventNames.d.mts +1 -0
- package/dist/constants/eventNames.d.mts.map +1 -1
- package/dist/constants/eventNames.mjs +3 -0
- package/dist/constants/eventNames.mjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.cjs +14 -2
- package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.cts +7 -0
- package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.mts +7 -0
- package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
- package/dist/constants/hyperLiquidConfig.mjs +11 -0
- package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
- package/dist/constants/perpsConfig.cjs +19 -2
- package/dist/constants/perpsConfig.cjs.map +1 -1
- package/dist/constants/perpsConfig.d.cts +39 -7
- package/dist/constants/perpsConfig.d.cts.map +1 -1
- package/dist/constants/perpsConfig.d.mts +39 -7
- package/dist/constants/perpsConfig.d.mts.map +1 -1
- package/dist/constants/perpsConfig.mjs +18 -1
- package/dist/constants/perpsConfig.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.cjs +16 -0
- package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.d.cts +3 -1
- package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.d.mts +3 -1
- package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.mjs +16 -0
- package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +325 -59
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts +27 -1
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts +27 -1
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +326 -60
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/services/HyperLiquidClientService.cjs +74 -25
- package/dist/services/HyperLiquidClientService.cjs.map +1 -1
- package/dist/services/HyperLiquidClientService.d.cts.map +1 -1
- package/dist/services/HyperLiquidClientService.d.mts.map +1 -1
- package/dist/services/HyperLiquidClientService.mjs +74 -25
- package/dist/services/HyperLiquidClientService.mjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.cjs +16 -5
- package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.mjs +16 -5
- package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
- package/dist/services/MarketDataService.cjs +49 -5
- package/dist/services/MarketDataService.cjs.map +1 -1
- package/dist/services/MarketDataService.d.cts +2 -2
- package/dist/services/MarketDataService.d.cts.map +1 -1
- package/dist/services/MarketDataService.d.mts +2 -2
- package/dist/services/MarketDataService.d.mts.map +1 -1
- package/dist/services/MarketDataService.mjs +49 -5
- package/dist/services/MarketDataService.mjs.map +1 -1
- package/dist/services/RewardsIntegrationService.cjs +330 -68
- package/dist/services/RewardsIntegrationService.cjs.map +1 -1
- package/dist/services/RewardsIntegrationService.d.cts +61 -5
- package/dist/services/RewardsIntegrationService.d.cts.map +1 -1
- package/dist/services/RewardsIntegrationService.d.mts +61 -5
- package/dist/services/RewardsIntegrationService.d.mts.map +1 -1
- package/dist/services/RewardsIntegrationService.mjs +330 -68
- package/dist/services/RewardsIntegrationService.mjs.map +1 -1
- package/dist/services/ServiceContext.cjs.map +1 -1
- package/dist/services/ServiceContext.d.cts +17 -1
- package/dist/services/ServiceContext.d.cts.map +1 -1
- package/dist/services/ServiceContext.d.mts +17 -1
- package/dist/services/ServiceContext.d.mts.map +1 -1
- package/dist/services/ServiceContext.mjs.map +1 -1
- package/dist/services/TerminalMarketService.cjs +422 -7
- package/dist/services/TerminalMarketService.cjs.map +1 -1
- package/dist/services/TerminalMarketService.d.cts +10 -1
- package/dist/services/TerminalMarketService.d.cts.map +1 -1
- package/dist/services/TerminalMarketService.d.mts +10 -1
- package/dist/services/TerminalMarketService.d.mts.map +1 -1
- package/dist/services/TerminalMarketService.mjs +423 -8
- package/dist/services/TerminalMarketService.mjs.map +1 -1
- package/dist/services/TradingService.cjs +52 -28
- package/dist/services/TradingService.cjs.map +1 -1
- package/dist/services/TradingService.d.cts.map +1 -1
- package/dist/services/TradingService.d.mts.map +1 -1
- package/dist/services/TradingService.mjs +52 -28
- package/dist/services/TradingService.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +156 -7
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +156 -7
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/utils/marketUtils.cjs +16 -1
- package/dist/utils/marketUtils.cjs.map +1 -1
- package/dist/utils/marketUtils.d.cts +1 -0
- package/dist/utils/marketUtils.d.cts.map +1 -1
- package/dist/utils/marketUtils.d.mts +1 -0
- package/dist/utils/marketUtils.d.mts.map +1 -1
- package/dist/utils/marketUtils.mjs +14 -0
- package/dist/utils/marketUtils.mjs.map +1 -1
- package/dist/utils/perpsDiskPersistence.cjs +19 -12
- package/dist/utils/perpsDiskPersistence.cjs.map +1 -1
- package/dist/utils/perpsDiskPersistence.d.cts +5 -1
- package/dist/utils/perpsDiskPersistence.d.cts.map +1 -1
- package/dist/utils/perpsDiskPersistence.d.mts +5 -1
- package/dist/utils/perpsDiskPersistence.d.mts.map +1 -1
- package/dist/utils/perpsDiskPersistence.mjs +19 -12
- package/dist/utils/perpsDiskPersistence.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PerpsControllerState } from "../PerpsController.cjs";
|
|
2
|
-
import type { Order, Position } from "../types/index.cjs";
|
|
2
|
+
import type { Order, PerpsGlobalSnapshotRequest, PerpsSubscriptionFeeWaiverStatus, Position } from "../types/index.cjs";
|
|
3
3
|
/**
|
|
4
4
|
* ServiceContext
|
|
5
5
|
*
|
|
@@ -55,6 +55,22 @@ export type ServiceContext = {
|
|
|
55
55
|
*/
|
|
56
56
|
getOpenOrders?: () => Promise<Order[]>;
|
|
57
57
|
getPositions?: () => Promise<Position[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Exact per-call identity and guards for adopting a global market snapshot.
|
|
60
|
+
* Omitted when the active provider or DEX configuration is not static.
|
|
61
|
+
*/
|
|
62
|
+
globalSnapshot?: {
|
|
63
|
+
request: PerpsGlobalSnapshotRequest;
|
|
64
|
+
isCurrent: () => boolean;
|
|
65
|
+
isMarketAllowed: (symbol: string) => boolean;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Cached subscription fee-waiver status for read-only fee previews.
|
|
69
|
+
* Read by the controller from `RewardsIntegrationService` — the same cached
|
|
70
|
+
* benefits snapshot the fee resolver uses — and omitted entirely when no
|
|
71
|
+
* subscription source is wired.
|
|
72
|
+
*/
|
|
73
|
+
subscriptionFeeWaiver?: PerpsSubscriptionFeeWaiverStatus;
|
|
58
74
|
/**
|
|
59
75
|
* Callback functions for controller-specific operations
|
|
60
76
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceContext.d.cts","sourceRoot":"","sources":["../../src/services/ServiceContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,+BAA8B;AAClE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ServiceContext.d.cts","sourceRoot":"","sources":["../../src/services/ServiceContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,+BAA8B;AAClE,OAAO,KAAK,EACV,KAAK,EACL,0BAA0B,EAC1B,gCAAgC,EAChC,QAAQ,EACT,2BAA0B;AAE3B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,cAAc,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IAEF;;;OAGG;IACH,YAAY,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC,CAAC;IAEF;;;;OAIG;IACH,YAAY,CAAC,EAAE;QACb,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,KAAK,IAAI,CAAC;QACjE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;KACtC,CAAC;IAEF;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEzC;;;OAGG;IACH,cAAc,CAAC,EAAE;QACf,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,OAAO,CAAC;QACzB,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;KAC9C,CAAC;IAEF;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,gCAAgC,CAAC;IAEzD;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAEpE;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM;QAC3B,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;KAC/B,CAAC;IACF,oBAAoB,CAAC,EAAE,CACrB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,QAAQ,GAAG,UAAU,KAC1B,IAAI,CAAC;IACV,aAAa,CAAC,EAAE,MAAM;QACpB,OAAO,EAAE,OAAO,CAAC;QACjB,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;KAC/B,CAAC;IACF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE;QACvB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;KAC/B,KAAK,IAAI,CAAC;IACX,0BAA0B,CAAC,EAAE,MAAM,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PerpsControllerState } from "../PerpsController.mjs";
|
|
2
|
-
import type { Order, Position } from "../types/index.mjs";
|
|
2
|
+
import type { Order, PerpsGlobalSnapshotRequest, PerpsSubscriptionFeeWaiverStatus, Position } from "../types/index.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* ServiceContext
|
|
5
5
|
*
|
|
@@ -55,6 +55,22 @@ export type ServiceContext = {
|
|
|
55
55
|
*/
|
|
56
56
|
getOpenOrders?: () => Promise<Order[]>;
|
|
57
57
|
getPositions?: () => Promise<Position[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Exact per-call identity and guards for adopting a global market snapshot.
|
|
60
|
+
* Omitted when the active provider or DEX configuration is not static.
|
|
61
|
+
*/
|
|
62
|
+
globalSnapshot?: {
|
|
63
|
+
request: PerpsGlobalSnapshotRequest;
|
|
64
|
+
isCurrent: () => boolean;
|
|
65
|
+
isMarketAllowed: (symbol: string) => boolean;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Cached subscription fee-waiver status for read-only fee previews.
|
|
69
|
+
* Read by the controller from `RewardsIntegrationService` — the same cached
|
|
70
|
+
* benefits snapshot the fee resolver uses — and omitted entirely when no
|
|
71
|
+
* subscription source is wired.
|
|
72
|
+
*/
|
|
73
|
+
subscriptionFeeWaiver?: PerpsSubscriptionFeeWaiverStatus;
|
|
58
74
|
/**
|
|
59
75
|
* Callback functions for controller-specific operations
|
|
60
76
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceContext.d.mts","sourceRoot":"","sources":["../../src/services/ServiceContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,+BAA8B;AAClE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ServiceContext.d.mts","sourceRoot":"","sources":["../../src/services/ServiceContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,+BAA8B;AAClE,OAAO,KAAK,EACV,KAAK,EACL,0BAA0B,EAC1B,gCAAgC,EAChC,QAAQ,EACT,2BAA0B;AAE3B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,cAAc,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IAEF;;;OAGG;IACH,YAAY,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC,CAAC;IAEF;;;;OAIG;IACH,YAAY,CAAC,EAAE;QACb,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,KAAK,IAAI,CAAC;QACjE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;KACtC,CAAC;IAEF;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEzC;;;OAGG;IACH,cAAc,CAAC,EAAE;QACf,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,OAAO,CAAC;QACzB,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;KAC9C,CAAC;IAEF;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,gCAAgC,CAAC;IAEzD;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAEpE;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM;QAC3B,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;KAC/B,CAAC;IACF,oBAAoB,CAAC,EAAE,CACrB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,QAAQ,GAAG,UAAU,KAC1B,IAAI,CAAC;IACV,aAAa,CAAC,EAAE,MAAM;QACpB,OAAO,EAAE,OAAO,CAAC;QACjB,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;KAC/B,CAAC;IACF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE;QACvB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;KAC/B,KAAK,IAAI,CAAC;IACX,0BAA0B,CAAC,EAAE,MAAM,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceContext.mjs","sourceRoot":"","sources":["../../src/services/ServiceContext.ts"],"names":[],"mappings":"","sourcesContent":["import type { PerpsControllerState } from '../PerpsController.js';\nimport type {
|
|
1
|
+
{"version":3,"file":"ServiceContext.mjs","sourceRoot":"","sources":["../../src/services/ServiceContext.ts"],"names":[],"mappings":"","sourcesContent":["import type { PerpsControllerState } from '../PerpsController.js';\nimport type {\n Order,\n PerpsGlobalSnapshotRequest,\n PerpsSubscriptionFeeWaiverStatus,\n Position,\n} from '../types/index.js';\n\n/**\n * ServiceContext\n *\n * Lightweight per-call context for Perps services.\n * Contains ONLY data that varies per operation:\n * - Tracing context (provider, network)\n * - Error context (controller, method)\n * - State management callbacks\n * - Query/action callbacks specific to the operation\n *\n * Platform dependencies (logging, metrics, tracing) are injected into service\n * instances via constructor, not passed per-call.\n *\n * Controller-level singletons (RewardsController, NetworkController, messenger)\n * are also injected into services that need them, not passed per-call.\n *\n * This enables:\n * - Clean method signatures (no verbose dependency passing)\n * - Fat services with complete orchestration\n * - Thin controller with pure delegation\n * - Easy testing through mock contexts and constructor injection\n */\nexport type ServiceContext = {\n /**\n * Tracing context for performance monitoring\n * Used in trace() calls to tag operations\n */\n tracingContext: {\n provider: string;\n isTestnet: boolean;\n };\n\n /**\n * Error logging context\n * Provides consistent error logging across services\n */\n errorContext: {\n controller: string;\n method: string;\n extra?: Record<string, unknown>;\n };\n\n /**\n * State management functions (optional)\n * Only provided for operations that need to mutate controller state\n * Example: Trading operations that update lastTransaction\n */\n stateManager?: {\n update: (updater: (state: PerpsControllerState) => void) => void;\n getState: () => PerpsControllerState;\n };\n\n /**\n * Query functions for dependent data\n * Required by: Operations that need to fetch related data\n */\n getOpenOrders?: () => Promise<Order[]>;\n getPositions?: () => Promise<Position[]>;\n\n /**\n * Exact per-call identity and guards for adopting a global market snapshot.\n * Omitted when the active provider or DEX configuration is not static.\n */\n globalSnapshot?: {\n request: PerpsGlobalSnapshotRequest;\n isCurrent: () => boolean;\n isMarketAllowed: (symbol: string) => boolean;\n };\n\n /**\n * Cached subscription fee-waiver status for read-only fee previews.\n * Read by the controller from `RewardsIntegrationService` — the same cached\n * benefits snapshot the fee resolver uses — and omitted entirely when no\n * subscription source is wired.\n */\n subscriptionFeeWaiver?: PerpsSubscriptionFeeWaiverStatus;\n\n /**\n * Callback functions for controller-specific operations\n */\n saveTradeConfiguration?: (symbol: string, leverage: number) => void;\n\n /**\n * Feature flag configuration callbacks\n * Required by: FeatureFlagConfigurationService\n */\n getBlockedRegionList?: () => {\n list: string[];\n source: 'remote' | 'fallback';\n };\n setBlockedRegionList?: (\n list: string[],\n source: 'remote' | 'fallback',\n ) => void;\n getHip3Config?: () => {\n enabled: boolean;\n allowlistMarkets: string[];\n blocklistMarkets: string[];\n source: 'remote' | 'fallback';\n };\n setHip3Config?: (config: {\n enabled?: boolean;\n allowlistMarkets?: string[];\n blocklistMarkets?: string[];\n source: 'remote' | 'fallback';\n }) => void;\n incrementHip3ConfigVersion?: () => number;\n refreshEligibility?: () => Promise<void>;\n};\n"]}
|
|
@@ -10,17 +10,70 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _TerminalMarketService_instances, _TerminalMarketService_deps, _TerminalMarketService_cache, _TerminalMarketService_validateItems, _TerminalMarketService_mapToMarketInfo, _TerminalMarketService_extractMetadata;
|
|
13
|
+
var _TerminalMarketService_instances, _TerminalMarketService_deps, _TerminalMarketService_cache, _TerminalMarketService_globalSnapshotCache, _TerminalMarketService_globalSnapshotInFlight, _TerminalMarketService_globalSnapshotGeneration, _TerminalMarketService_fetchAndValidateGlobalSnapshot, _TerminalMarketService_validateAndMapGlobalSnapshot, _TerminalMarketService_validateRequestedIdentity, _TerminalMarketService_buildGlobalSnapshotUrl, _TerminalMarketService_normalizeDexes, _TerminalMarketService_createFingerprint, _TerminalMarketService_validateSnapshotMarket, _TerminalMarketService_mapSnapshotMarket, _TerminalMarketService_marketTypeFor, _TerminalMarketService_cloneGlobalSnapshotResult, _TerminalMarketService_isNonNegativeSafeInteger, _TerminalMarketService_isPositiveSafeInteger, _TerminalMarketService_validateItems, _TerminalMarketService_mapToMarketInfo, _TerminalMarketService_extractMetadata;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.TerminalMarketService = void 0;
|
|
16
16
|
const superstruct_1 = require("@metamask/superstruct");
|
|
17
|
+
const utils_1 = require("@metamask/utils");
|
|
18
|
+
const hyperLiquidConfig_js_1 = require("../constants/hyperLiquidConfig.cjs");
|
|
17
19
|
const perpsConfig_js_1 = require("../constants/perpsConfig.cjs");
|
|
18
20
|
const index_js_1 = require("../types/index.cjs");
|
|
19
21
|
const errorUtils_js_1 = require("../utils/errorUtils.cjs");
|
|
22
|
+
const marketDataTransform_js_1 = require("../utils/marketDataTransform.cjs");
|
|
23
|
+
const marketUtils_js_1 = require("../utils/marketUtils.cjs");
|
|
20
24
|
const VALID_MARKET_TYPES = new Set(Object.values(index_js_1.MarketCategory));
|
|
25
|
+
const GLOBAL_SNAPSHOT_SCHEMA_VERSION = 2;
|
|
26
|
+
const GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS = 30000;
|
|
27
|
+
const GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES = 1048576;
|
|
28
|
+
const GLOBAL_SNAPSHOT_PERCENT_TOLERANCE = 0.01;
|
|
29
|
+
const GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS = 5000;
|
|
30
|
+
const MINIMUM_EPOCH_MILLISECONDS = Date.UTC(2000, 0, 1);
|
|
31
|
+
const DECIMAL_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/u;
|
|
32
|
+
const NON_NEGATIVE_DECIMAL_PATTERN = /^(?:0|[1-9]\d*)(?:\.\d+)?$/u;
|
|
33
|
+
const DEX_PATTERN = /^(?:main|[a-z0-9][a-z0-9-]*)$/u;
|
|
34
|
+
const GlobalSnapshotMarketStruct = (0, superstruct_1.object)({
|
|
35
|
+
symbol: (0, superstruct_1.string)(),
|
|
36
|
+
provider: (0, superstruct_1.string)(),
|
|
37
|
+
dex: (0, superstruct_1.string)(),
|
|
38
|
+
name: (0, superstruct_1.nullable)((0, superstruct_1.string)()),
|
|
39
|
+
description: (0, superstruct_1.nullable)((0, superstruct_1.string)()),
|
|
40
|
+
iconUrl: (0, superstruct_1.nullable)((0, superstruct_1.string)()),
|
|
41
|
+
szDecimals: (0, superstruct_1.number)(),
|
|
42
|
+
maxLeverage: (0, superstruct_1.number)(),
|
|
43
|
+
markPrice: (0, superstruct_1.string)(),
|
|
44
|
+
price: (0, superstruct_1.string)(),
|
|
45
|
+
midPrice: (0, superstruct_1.nullable)((0, superstruct_1.string)()),
|
|
46
|
+
oraclePrice: (0, superstruct_1.string)(),
|
|
47
|
+
change24h: (0, superstruct_1.string)(),
|
|
48
|
+
changePercent24h: (0, superstruct_1.number)(),
|
|
49
|
+
funding: (0, superstruct_1.string)(),
|
|
50
|
+
volume24h: (0, superstruct_1.string)(),
|
|
51
|
+
openInterest: (0, superstruct_1.string)(),
|
|
52
|
+
category: (0, superstruct_1.nullable)((0, superstruct_1.string)()),
|
|
53
|
+
keywords: (0, superstruct_1.nullable)((0, superstruct_1.array)((0, superstruct_1.string)())),
|
|
54
|
+
tags: (0, superstruct_1.nullable)((0, superstruct_1.array)((0, superstruct_1.string)())),
|
|
55
|
+
listedAt: (0, superstruct_1.nullable)((0, superstruct_1.number)()),
|
|
56
|
+
trend: (0, superstruct_1.array)((0, superstruct_1.tuple)([(0, superstruct_1.number)(), (0, superstruct_1.string)()])),
|
|
57
|
+
});
|
|
58
|
+
const GlobalSnapshotStruct = (0, superstruct_1.object)({
|
|
59
|
+
schemaVersion: (0, superstruct_1.number)(),
|
|
60
|
+
provider: (0, superstruct_1.string)(),
|
|
61
|
+
network: (0, superstruct_1.string)(),
|
|
62
|
+
enabledDexes: (0, superstruct_1.array)((0, superstruct_1.string)()),
|
|
63
|
+
fingerprint: (0, superstruct_1.string)(),
|
|
64
|
+
generatedAt: (0, superstruct_1.number)(),
|
|
65
|
+
receivedAt: (0, superstruct_1.number)(),
|
|
66
|
+
maxAgeMs: (0, superstruct_1.number)(),
|
|
67
|
+
complete: (0, superstruct_1.boolean)(),
|
|
68
|
+
perDexErrors: (0, superstruct_1.array)((0, superstruct_1.object)({
|
|
69
|
+
dex: (0, superstruct_1.string)(),
|
|
70
|
+
error: (0, superstruct_1.string)(),
|
|
71
|
+
})),
|
|
72
|
+
markets: (0, superstruct_1.array)(GlobalSnapshotMarketStruct),
|
|
73
|
+
});
|
|
21
74
|
/**
|
|
22
75
|
* Runtime validation schema for a single market item returned by
|
|
23
|
-
* `GET {
|
|
76
|
+
* `GET {terminalApi.marketDataUrl}`.
|
|
24
77
|
*
|
|
25
78
|
* Uses `type()` (loose object matching) so that extra fields the API sends
|
|
26
79
|
* (e.g. `price`, `iconUrl`, `trend`) are silently accepted.
|
|
@@ -57,6 +110,9 @@ class TerminalMarketService {
|
|
|
57
110
|
_TerminalMarketService_instances.add(this);
|
|
58
111
|
_TerminalMarketService_deps.set(this, void 0);
|
|
59
112
|
_TerminalMarketService_cache.set(this, null);
|
|
113
|
+
_TerminalMarketService_globalSnapshotCache.set(this, new Map());
|
|
114
|
+
_TerminalMarketService_globalSnapshotInFlight.set(this, new Map());
|
|
115
|
+
_TerminalMarketService_globalSnapshotGeneration.set(this, 0);
|
|
60
116
|
__classPrivateFieldSet(this, _TerminalMarketService_deps, deps, "f");
|
|
61
117
|
}
|
|
62
118
|
/**
|
|
@@ -73,10 +129,11 @@ class TerminalMarketService {
|
|
|
73
129
|
metadata: __classPrivateFieldGet(this, _TerminalMarketService_cache, "f").metadata,
|
|
74
130
|
};
|
|
75
131
|
}
|
|
76
|
-
|
|
77
|
-
|
|
132
|
+
const marketDataUrl = __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.marketDataUrl ?? __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApiUrl;
|
|
133
|
+
if (!marketDataUrl) {
|
|
134
|
+
throw new Error('Terminal API market-data URL not configured');
|
|
78
135
|
}
|
|
79
|
-
const url =
|
|
136
|
+
const url = marketDataUrl;
|
|
80
137
|
const controller = new AbortController();
|
|
81
138
|
const timeoutId = setTimeout(() => controller.abort(new Error('Terminal API fetch timed out')), perpsConfig_js_1.TERMINAL_API_CONFIG.FetchTimeoutMs);
|
|
82
139
|
let response;
|
|
@@ -103,11 +160,65 @@ class TerminalMarketService {
|
|
|
103
160
|
__classPrivateFieldSet(this, _TerminalMarketService_cache, { markets, metadata, timestamp: Date.now() }, "f");
|
|
104
161
|
return { markets, metadata };
|
|
105
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Fetch, authenticate by exact identity, and map a schema-v2 atomic market
|
|
165
|
+
* snapshot. Accepted entries remain inside the source freshness window;
|
|
166
|
+
* rejected responses are never cached.
|
|
167
|
+
*
|
|
168
|
+
* @param request - Exact provider/network/DEX identity expected by the client.
|
|
169
|
+
* @returns UI-ready market data and its source-bounded expiry.
|
|
170
|
+
*/
|
|
171
|
+
async fetchGlobalSnapshot(request) {
|
|
172
|
+
const identity = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_validateRequestedIdentity).call(this, request);
|
|
173
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.globalSnapshotUrl) {
|
|
174
|
+
throw new Error('Terminal global snapshot URL not configured');
|
|
175
|
+
}
|
|
176
|
+
const url = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_buildGlobalSnapshotUrl).call(this, __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi.globalSnapshotUrl, identity);
|
|
177
|
+
const cacheKey = [
|
|
178
|
+
url,
|
|
179
|
+
String(GLOBAL_SNAPSHOT_SCHEMA_VERSION),
|
|
180
|
+
identity.provider,
|
|
181
|
+
identity.network,
|
|
182
|
+
identity.enabledDexes.join(','),
|
|
183
|
+
].join('|');
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
const cached = __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").get(cacheKey);
|
|
186
|
+
if (cached && now < cached.expiresAt) {
|
|
187
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_cloneGlobalSnapshotResult).call(this, cached);
|
|
188
|
+
}
|
|
189
|
+
if (cached) {
|
|
190
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").delete(cacheKey);
|
|
191
|
+
}
|
|
192
|
+
const existing = __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").get(cacheKey);
|
|
193
|
+
if (existing) {
|
|
194
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_cloneGlobalSnapshotResult).call(this, await existing);
|
|
195
|
+
}
|
|
196
|
+
const generation = __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotGeneration, "f");
|
|
197
|
+
const pending = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_fetchAndValidateGlobalSnapshot).call(this, identity, url).then((result) => {
|
|
198
|
+
if (__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotGeneration, "f") !== generation) {
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").set(cacheKey, result);
|
|
202
|
+
return result;
|
|
203
|
+
});
|
|
204
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").set(cacheKey, pending);
|
|
205
|
+
try {
|
|
206
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_cloneGlobalSnapshotResult).call(this, await pending);
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
if (__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").get(cacheKey) === pending) {
|
|
210
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").delete(cacheKey);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
106
214
|
/**
|
|
107
215
|
* Invalidate the internal cache so the next fetch hits the network.
|
|
108
216
|
*/
|
|
109
217
|
clearCache() {
|
|
110
218
|
__classPrivateFieldSet(this, _TerminalMarketService_cache, null, "f");
|
|
219
|
+
__classPrivateFieldSet(this, _TerminalMarketService_globalSnapshotGeneration, __classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotGeneration, "f") + 1, "f");
|
|
220
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotCache, "f").clear();
|
|
221
|
+
__classPrivateFieldGet(this, _TerminalMarketService_globalSnapshotInFlight, "f").clear();
|
|
111
222
|
}
|
|
112
223
|
/**
|
|
113
224
|
* Log a Terminal API error to Sentry without surfacing it to the user.
|
|
@@ -120,13 +231,317 @@ class TerminalMarketService {
|
|
|
120
231
|
tags: { feature: perpsConfig_js_1.PERPS_CONSTANTS.FeatureName, source: 'terminal-api' },
|
|
121
232
|
context: {
|
|
122
233
|
name: `TerminalMarketService.${method}`,
|
|
123
|
-
data: {
|
|
234
|
+
data: {
|
|
235
|
+
url: method.includes('globalSnapshot')
|
|
236
|
+
? __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.globalSnapshotUrl
|
|
237
|
+
: (__classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApi?.marketDataUrl ??
|
|
238
|
+
__classPrivateFieldGet(this, _TerminalMarketService_deps, "f").terminalApiUrl),
|
|
239
|
+
},
|
|
124
240
|
},
|
|
125
241
|
});
|
|
126
242
|
}
|
|
127
243
|
}
|
|
128
244
|
exports.TerminalMarketService = TerminalMarketService;
|
|
129
|
-
_TerminalMarketService_deps = new WeakMap(), _TerminalMarketService_cache = new WeakMap(), _TerminalMarketService_instances = new WeakSet(),
|
|
245
|
+
_TerminalMarketService_deps = new WeakMap(), _TerminalMarketService_cache = new WeakMap(), _TerminalMarketService_globalSnapshotCache = new WeakMap(), _TerminalMarketService_globalSnapshotInFlight = new WeakMap(), _TerminalMarketService_globalSnapshotGeneration = new WeakMap(), _TerminalMarketService_instances = new WeakSet(), _TerminalMarketService_fetchAndValidateGlobalSnapshot = async function _TerminalMarketService_fetchAndValidateGlobalSnapshot(identity, url) {
|
|
246
|
+
const controller = new AbortController();
|
|
247
|
+
const timeoutId = setTimeout(() => controller.abort(new Error('Terminal global snapshot timed out')), perpsConfig_js_1.TERMINAL_API_CONFIG.FetchTimeoutMs);
|
|
248
|
+
try {
|
|
249
|
+
const response = await fetch(url, {
|
|
250
|
+
method: 'GET',
|
|
251
|
+
headers: { 'Content-Type': 'application/json' },
|
|
252
|
+
signal: controller.signal,
|
|
253
|
+
});
|
|
254
|
+
if (!response.ok) {
|
|
255
|
+
throw new Error(`Terminal global snapshot returned ${String(response.status)}: ${response.statusText}`);
|
|
256
|
+
}
|
|
257
|
+
const declaredLength = response.headers?.get('content-length');
|
|
258
|
+
if (declaredLength !== null &&
|
|
259
|
+
declaredLength !== undefined &&
|
|
260
|
+
/^\d+$/u.test(declaredLength) &&
|
|
261
|
+
Number(declaredLength) > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES) {
|
|
262
|
+
throw new Error('Terminal global snapshot payload exceeds 1 MiB');
|
|
263
|
+
}
|
|
264
|
+
// React Native fetch does not consistently expose a streaming reader.
|
|
265
|
+
// Reject declared oversize bodies before allocation, then enforce the same
|
|
266
|
+
// byte cap after text() for servers that omit Content-Length.
|
|
267
|
+
const text = await response.text();
|
|
268
|
+
if ((0, utils_1.stringToBytes)(text).byteLength > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES) {
|
|
269
|
+
throw new Error('Terminal global snapshot payload exceeds 1 MiB');
|
|
270
|
+
}
|
|
271
|
+
let body;
|
|
272
|
+
try {
|
|
273
|
+
body = JSON.parse(text);
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
throw new Error('Terminal global snapshot returned invalid JSON');
|
|
277
|
+
}
|
|
278
|
+
if (!(0, superstruct_1.is)(body, GlobalSnapshotStruct)) {
|
|
279
|
+
throw new Error('Terminal global snapshot failed schema validation');
|
|
280
|
+
}
|
|
281
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_validateAndMapGlobalSnapshot).call(this, body, identity, Date.now());
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
clearTimeout(timeoutId);
|
|
285
|
+
}
|
|
286
|
+
}, _TerminalMarketService_validateAndMapGlobalSnapshot = async function _TerminalMarketService_validateAndMapGlobalSnapshot(snapshot, identity, now) {
|
|
287
|
+
if (snapshot.schemaVersion !== GLOBAL_SNAPSHOT_SCHEMA_VERSION) {
|
|
288
|
+
throw new Error('Terminal global snapshot schema version mismatch');
|
|
289
|
+
}
|
|
290
|
+
if (snapshot.provider !== identity.provider ||
|
|
291
|
+
snapshot.network !== identity.network) {
|
|
292
|
+
throw new Error('Terminal global snapshot identity mismatch');
|
|
293
|
+
}
|
|
294
|
+
const responseDexes = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_normalizeDexes).call(this, snapshot.enabledDexes);
|
|
295
|
+
if (responseDexes.length !== identity.enabledDexes.length ||
|
|
296
|
+
responseDexes.some((dex, index) => dex !== identity.enabledDexes[index])) {
|
|
297
|
+
throw new Error('Terminal global snapshot DEX mismatch');
|
|
298
|
+
}
|
|
299
|
+
const expectedFingerprint = await __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_createFingerprint).call(this, identity);
|
|
300
|
+
if (snapshot.fingerprint !== expectedFingerprint) {
|
|
301
|
+
throw new Error('Terminal global snapshot fingerprint mismatch');
|
|
302
|
+
}
|
|
303
|
+
if (!snapshot.complete || snapshot.perDexErrors.length > 0) {
|
|
304
|
+
throw new Error('Terminal global snapshot is incomplete');
|
|
305
|
+
}
|
|
306
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, snapshot.generatedAt) ||
|
|
307
|
+
!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, snapshot.receivedAt) ||
|
|
308
|
+
!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isPositiveSafeInteger).call(this, snapshot.maxAgeMs) ||
|
|
309
|
+
snapshot.receivedAt > snapshot.generatedAt ||
|
|
310
|
+
snapshot.generatedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS ||
|
|
311
|
+
snapshot.receivedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS) {
|
|
312
|
+
throw new Error('Terminal global snapshot has invalid timestamps');
|
|
313
|
+
}
|
|
314
|
+
const trustedMaxAgeMs = Math.min(snapshot.maxAgeMs, GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS);
|
|
315
|
+
const expiresAt = snapshot.receivedAt + trustedMaxAgeMs;
|
|
316
|
+
if (now >= expiresAt) {
|
|
317
|
+
throw new Error('Terminal global snapshot is stale');
|
|
318
|
+
}
|
|
319
|
+
if (snapshot.markets.length === 0) {
|
|
320
|
+
throw new Error('Terminal global snapshot has no markets');
|
|
321
|
+
}
|
|
322
|
+
const marketKeys = new Set();
|
|
323
|
+
const representedDexes = new Set();
|
|
324
|
+
const markets = snapshot.markets
|
|
325
|
+
.map((market, index) => {
|
|
326
|
+
__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_validateSnapshotMarket).call(this, market, identity, index, snapshot.generatedAt);
|
|
327
|
+
const key = `${market.dex}:${market.symbol}`;
|
|
328
|
+
if (marketKeys.has(key)) {
|
|
329
|
+
throw new Error(`Terminal global snapshot duplicates market ${key}`);
|
|
330
|
+
}
|
|
331
|
+
marketKeys.add(key);
|
|
332
|
+
representedDexes.add(market.dex);
|
|
333
|
+
return market;
|
|
334
|
+
})
|
|
335
|
+
.map((market) => __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_mapSnapshotMarket).call(this, market, expiresAt));
|
|
336
|
+
if (identity.enabledDexes.some((dex) => !representedDexes.has(dex))) {
|
|
337
|
+
throw new Error('Terminal global snapshot is missing a requested DEX');
|
|
338
|
+
}
|
|
339
|
+
if (markets.length === 0) {
|
|
340
|
+
throw new Error('Terminal global snapshot has no tradable markets');
|
|
341
|
+
}
|
|
342
|
+
return { markets, expiresAt };
|
|
343
|
+
}, _TerminalMarketService_validateRequestedIdentity = function _TerminalMarketService_validateRequestedIdentity(request) {
|
|
344
|
+
if (request.provider !== 'hyperliquid') {
|
|
345
|
+
throw new Error('Terminal global snapshot provider is unsupported');
|
|
346
|
+
}
|
|
347
|
+
if (request.network !== 'mainnet' && request.network !== 'testnet') {
|
|
348
|
+
throw new Error('Terminal global snapshot network is unsupported');
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
provider: request.provider,
|
|
352
|
+
network: request.network,
|
|
353
|
+
enabledDexes: __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_normalizeDexes).call(this, request.enabledDexes),
|
|
354
|
+
};
|
|
355
|
+
}, _TerminalMarketService_buildGlobalSnapshotUrl = function _TerminalMarketService_buildGlobalSnapshotUrl(baseUrl, identity) {
|
|
356
|
+
const query = new URLSearchParams({
|
|
357
|
+
provider: identity.provider,
|
|
358
|
+
network: identity.network,
|
|
359
|
+
dexes: identity.enabledDexes.join(','),
|
|
360
|
+
});
|
|
361
|
+
return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${query.toString()}`;
|
|
362
|
+
}, _TerminalMarketService_normalizeDexes = function _TerminalMarketService_normalizeDexes(dexes) {
|
|
363
|
+
if (!Array.isArray(dexes) || dexes.length === 0) {
|
|
364
|
+
throw new Error('Terminal global snapshot requires at least one DEX');
|
|
365
|
+
}
|
|
366
|
+
const normalized = dexes.map((dex) => {
|
|
367
|
+
if (typeof dex !== 'string' || !DEX_PATTERN.test(dex)) {
|
|
368
|
+
throw new Error('Terminal global snapshot contains an invalid DEX');
|
|
369
|
+
}
|
|
370
|
+
return dex;
|
|
371
|
+
});
|
|
372
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
373
|
+
throw new Error('Terminal global snapshot contains duplicate DEXes');
|
|
374
|
+
}
|
|
375
|
+
if (!normalized.includes('main')) {
|
|
376
|
+
throw new Error('Terminal global snapshot requires the main DEX');
|
|
377
|
+
}
|
|
378
|
+
return (0, hyperLiquidConfig_js_1.canonicalizeHyperLiquidDexes)(normalized);
|
|
379
|
+
}, _TerminalMarketService_createFingerprint = async function _TerminalMarketService_createFingerprint(identity) {
|
|
380
|
+
const canonicalIdentity = JSON.stringify({
|
|
381
|
+
provider: identity.provider,
|
|
382
|
+
network: identity.network,
|
|
383
|
+
enabledDexes: identity.enabledDexes,
|
|
384
|
+
});
|
|
385
|
+
const digest = await (0, utils_1.sha256)((0, utils_1.stringToBytes)(canonicalIdentity));
|
|
386
|
+
return `sha256:${(0, utils_1.bytesToHex)(digest).slice(2)}`;
|
|
387
|
+
}, _TerminalMarketService_validateSnapshotMarket = function _TerminalMarketService_validateSnapshotMarket(market, identity, index, generatedAt) {
|
|
388
|
+
const invalid = (field) => new Error(`Terminal global snapshot market ${String(index)} has invalid ${field}`);
|
|
389
|
+
if (!identity.enabledDexes.includes(market.dex)) {
|
|
390
|
+
throw invalid('dex');
|
|
391
|
+
}
|
|
392
|
+
const expectedProvider = market.dex === 'main' ? 'hyperliquid' : market.dex;
|
|
393
|
+
if (market.provider !== expectedProvider) {
|
|
394
|
+
throw invalid('provider');
|
|
395
|
+
}
|
|
396
|
+
const expectedPrefix = market.dex === 'main' ? '' : `${market.dex}:`;
|
|
397
|
+
if (market.symbol.length === 0 ||
|
|
398
|
+
(expectedPrefix
|
|
399
|
+
? !market.symbol.startsWith(expectedPrefix)
|
|
400
|
+
: market.symbol.includes(':'))) {
|
|
401
|
+
throw invalid('symbol');
|
|
402
|
+
}
|
|
403
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, market.szDecimals) ||
|
|
404
|
+
!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isPositiveSafeInteger).call(this, market.maxLeverage) ||
|
|
405
|
+
(market.listedAt !== null &&
|
|
406
|
+
(!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, market.listedAt) ||
|
|
407
|
+
market.listedAt < MINIMUM_EPOCH_MILLISECONDS ||
|
|
408
|
+
market.listedAt > generatedAt))) {
|
|
409
|
+
throw invalid('integer field');
|
|
410
|
+
}
|
|
411
|
+
const decimalFields = [
|
|
412
|
+
['markPrice', market.markPrice, true],
|
|
413
|
+
['price', market.price, true],
|
|
414
|
+
['oraclePrice', market.oraclePrice, true],
|
|
415
|
+
['change24h', market.change24h, false],
|
|
416
|
+
['volume24h', market.volume24h, true],
|
|
417
|
+
['openInterest', market.openInterest, true],
|
|
418
|
+
['funding', market.funding, false],
|
|
419
|
+
];
|
|
420
|
+
if (market.midPrice !== null) {
|
|
421
|
+
decimalFields.push(['midPrice', market.midPrice, true]);
|
|
422
|
+
}
|
|
423
|
+
for (const [field, value, nonNegative] of decimalFields) {
|
|
424
|
+
const pattern = nonNegative
|
|
425
|
+
? NON_NEGATIVE_DECIMAL_PATTERN
|
|
426
|
+
: DECIMAL_PATTERN;
|
|
427
|
+
if (!pattern.test(value) || !Number.isFinite(Number(value))) {
|
|
428
|
+
throw invalid(field);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (market.price !== market.markPrice) {
|
|
432
|
+
throw invalid('deprecated price alias');
|
|
433
|
+
}
|
|
434
|
+
if (Number(market.oraclePrice) <= 0 ||
|
|
435
|
+
(market.midPrice !== null && Number(market.midPrice) <= 0)) {
|
|
436
|
+
throw invalid('reference price');
|
|
437
|
+
}
|
|
438
|
+
const price = Number(market.markPrice);
|
|
439
|
+
const change24h = Number(market.change24h);
|
|
440
|
+
const previousPrice = price - change24h;
|
|
441
|
+
if (price <= 0 || previousPrice <= 0 || !Number.isFinite(previousPrice)) {
|
|
442
|
+
throw invalid('mark/change coherence');
|
|
443
|
+
}
|
|
444
|
+
const derivedPercent = (change24h / previousPrice) * 100;
|
|
445
|
+
if (!Number.isFinite(derivedPercent) ||
|
|
446
|
+
!Number.isFinite(market.changePercent24h) ||
|
|
447
|
+
Math.abs(market.changePercent24h - derivedPercent) >
|
|
448
|
+
GLOBAL_SNAPSHOT_PERCENT_TOLERANCE) {
|
|
449
|
+
throw invalid('changePercent24h coherence');
|
|
450
|
+
}
|
|
451
|
+
for (const [field, values] of [
|
|
452
|
+
['keywords', market.keywords],
|
|
453
|
+
['tags', market.tags],
|
|
454
|
+
]) {
|
|
455
|
+
if (values !== null &&
|
|
456
|
+
(values.some((value) => value.length === 0) ||
|
|
457
|
+
new Set(values).size !== values.length)) {
|
|
458
|
+
throw invalid(field);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
for (const [field, value] of [
|
|
462
|
+
['name', market.name],
|
|
463
|
+
['description', market.description],
|
|
464
|
+
['iconUrl', market.iconUrl],
|
|
465
|
+
['category', market.category],
|
|
466
|
+
]) {
|
|
467
|
+
if (value !== null && value.length === 0) {
|
|
468
|
+
throw invalid(field);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
let previousTrendTimestamp = -1;
|
|
472
|
+
for (const [timestamp, trendPrice] of market.trend) {
|
|
473
|
+
if (!__classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, timestamp) ||
|
|
474
|
+
timestamp < MINIMUM_EPOCH_MILLISECONDS ||
|
|
475
|
+
timestamp > generatedAt ||
|
|
476
|
+
timestamp <= previousTrendTimestamp ||
|
|
477
|
+
!NON_NEGATIVE_DECIMAL_PATTERN.test(trendPrice) ||
|
|
478
|
+
!Number.isFinite(Number(trendPrice)) ||
|
|
479
|
+
Number(trendPrice) <= 0) {
|
|
480
|
+
throw invalid('trend');
|
|
481
|
+
}
|
|
482
|
+
previousTrendTimestamp = timestamp;
|
|
483
|
+
}
|
|
484
|
+
}, _TerminalMarketService_mapSnapshotMarket = function _TerminalMarketService_mapSnapshotMarket(market, sourceExpiresAt) {
|
|
485
|
+
const formatters = __classPrivateFieldGet(this, _TerminalMarketService_deps, "f").marketDataFormatters;
|
|
486
|
+
// Keep both provider price semantics explicit in the wire contract. Core
|
|
487
|
+
// maps markPrice to its UI price while retaining validation of midPrice.
|
|
488
|
+
const price = Number(market.markPrice);
|
|
489
|
+
const change24h = Number(market.change24h);
|
|
490
|
+
const volume = Number(market.volume24h);
|
|
491
|
+
const openInterest = Number(market.openInterest);
|
|
492
|
+
const isHip3 = market.dex !== 'main';
|
|
493
|
+
const marketType = __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_marketTypeFor).call(this, market.dex, market.category);
|
|
494
|
+
return {
|
|
495
|
+
symbol: market.symbol,
|
|
496
|
+
name: market.name ?? market.symbol,
|
|
497
|
+
...(market.description !== null && {
|
|
498
|
+
description: market.description,
|
|
499
|
+
}),
|
|
500
|
+
maxLeverage: `${String(market.maxLeverage)}x`,
|
|
501
|
+
price: formatters.formatPerpsFiat(price, {
|
|
502
|
+
ranges: formatters.priceRangesUniversal,
|
|
503
|
+
}),
|
|
504
|
+
change24h: (0, marketDataTransform_js_1.formatChange)(change24h, formatters),
|
|
505
|
+
change24hPercent: formatters.formatPercentage(market.changePercent24h),
|
|
506
|
+
volume: formatters.formatVolume(volume),
|
|
507
|
+
openInterest: formatters.formatVolume(openInterest),
|
|
508
|
+
fundingRate: Number(market.funding),
|
|
509
|
+
marketSource: isHip3 ? market.dex : undefined,
|
|
510
|
+
marketType,
|
|
511
|
+
isHip3,
|
|
512
|
+
isNewMarket: isHip3 && marketType === undefined,
|
|
513
|
+
...(market.keywords && { keywords: market.keywords }),
|
|
514
|
+
...(market.tags && { tags: market.tags }),
|
|
515
|
+
...(market.category && { categories: [market.category] }),
|
|
516
|
+
...(market.listedAt !== null && { listedAt: market.listedAt }),
|
|
517
|
+
trend: market.trend,
|
|
518
|
+
dataSource: 'terminal-global-snapshot-mark',
|
|
519
|
+
sourceExpiresAt,
|
|
520
|
+
};
|
|
521
|
+
}, _TerminalMarketService_marketTypeFor = function _TerminalMarketService_marketTypeFor(dex, category) {
|
|
522
|
+
if (dex === 'main') {
|
|
523
|
+
return index_js_1.MarketCategory.CryptoCurrency;
|
|
524
|
+
}
|
|
525
|
+
if (category === 'stocks') {
|
|
526
|
+
return index_js_1.MarketCategory.Stock;
|
|
527
|
+
}
|
|
528
|
+
if (category === 'pre_ipo') {
|
|
529
|
+
return index_js_1.MarketCategory.PreIpo;
|
|
530
|
+
}
|
|
531
|
+
if (category && VALID_MARKET_TYPES.has(category)) {
|
|
532
|
+
return category;
|
|
533
|
+
}
|
|
534
|
+
return undefined;
|
|
535
|
+
}, _TerminalMarketService_cloneGlobalSnapshotResult = function _TerminalMarketService_cloneGlobalSnapshotResult(result) {
|
|
536
|
+
return {
|
|
537
|
+
expiresAt: result.expiresAt,
|
|
538
|
+
markets: (0, marketUtils_js_1.clonePerpsMarketData)(result.markets),
|
|
539
|
+
};
|
|
540
|
+
}, _TerminalMarketService_isNonNegativeSafeInteger = function _TerminalMarketService_isNonNegativeSafeInteger(value) {
|
|
541
|
+
return (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0);
|
|
542
|
+
}, _TerminalMarketService_isPositiveSafeInteger = function _TerminalMarketService_isPositiveSafeInteger(value) {
|
|
543
|
+
return __classPrivateFieldGet(this, _TerminalMarketService_instances, "m", _TerminalMarketService_isNonNegativeSafeInteger).call(this, value) && value > 0;
|
|
544
|
+
}, _TerminalMarketService_validateItems = function _TerminalMarketService_validateItems(raw) {
|
|
130
545
|
const valid = [];
|
|
131
546
|
for (const item of raw) {
|
|
132
547
|
if ((0, superstruct_1.is)(item, TerminalPerpetualItemStruct)) {
|