@metamask-previews/perps-controller 22.0.0-preview-a0d99e051 → 22.0.0-preview-060b37d94
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 +14 -0
- package/dist/services/TerminalMarketService.d.ts.map +1 -1
- package/dist/services/TerminalMarketService.js +5 -1
- package/dist/services/TerminalMarketService.js.map +1 -1
- package/dist/utils/lighterAdapter.js +2 -1
- package/dist/utils/lighterAdapter.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Map `onlyIsolated` and `marginMode` from Terminal v4 global snapshot markets into the `MarketInfo` that `getMarkets()` returns, so a client reading only the snapshot can withhold Cross margin on isolated-only markets ([#11030](https://github.com/MetaMask/core/pull/11030))
|
|
13
|
+
- Snapshots without these fields, or with `null` values, still validate. An unrecognized `marginMode` rejects the snapshot, so snapshot-backed reads fall back to the provider.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Bump `@metamask/utils` from `^12.0.0` to `^12.0.1` ([#11107](https://github.com/MetaMask/core/pull/11107))
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Lighter `Position.returnOnEquity` is now a fraction (`-0.107` for -10.7%), the same unit as Hyperliquid positions, instead of a percent, so clients that multiply it by 100 no longer show Lighter position PnL % 100x too large ([#11080](https://github.com/MetaMask/core/pull/11080))
|
|
22
|
+
- Lighter `AccountState.returnOnEquity` is unchanged: it stays a percent, like Hyperliquid's.
|
|
23
|
+
|
|
10
24
|
## [22.0.0]
|
|
11
25
|
|
|
12
26
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalMarketService.d.ts","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TerminalMarketService.d.ts","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,UAAU,EACV,0BAA0B,EAC1B,yBAAyB,EAEzB,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AA0G3B;;;;;;;;GAQG;AACH,qBAAa,qBAAqB;;IAchC,YAAY,IAAI,EAAE,yBAAyB,EAE1C;IAED;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC;QAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;QACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;KAC9C,CAAC,CAqDD;IAED;;;;;;;OAOG;IACG,mBAAmB,CACvB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,CAAC,CAiDpC;IAmeD;;OAEG;IACH,UAAU,IAAI,IAAI,CAKjB;IA+HD;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAgB7C;CACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { array, boolean, is, nullable, number, object, optional, string, tuple, type, union, } from '@metamask/superstruct';
|
|
1
|
+
import { array, boolean, enums, is, nullable, number, object, optional, string, tuple, type, union, } from '@metamask/superstruct';
|
|
2
2
|
import { bytesToHex, sha256, stringToBytes } from '@metamask/utils';
|
|
3
3
|
import { canonicalizeHyperLiquidDexes } from '../constants/hyperLiquidConfig.js';
|
|
4
4
|
import { PERPS_CONSTANTS, TERMINAL_API_CONFIG, } from '../constants/perpsConfig.js';
|
|
@@ -45,6 +45,8 @@ const GlobalSnapshotMarketStruct = type({
|
|
|
45
45
|
tags: nullable(array(string())),
|
|
46
46
|
listedAt: nullable(number()),
|
|
47
47
|
trend: array(tuple([number(), string()])),
|
|
48
|
+
onlyIsolated: optional(nullable(boolean())),
|
|
49
|
+
marginMode: optional(nullable(enums(['strictIsolated', 'noCross']))),
|
|
48
50
|
});
|
|
49
51
|
const GlobalSnapshotStruct = type({
|
|
50
52
|
schemaVersion: number(),
|
|
@@ -516,6 +518,8 @@ export class TerminalMarketService {
|
|
|
516
518
|
szDecimals: market.szDecimals,
|
|
517
519
|
maxLeverage: market.maxLeverage,
|
|
518
520
|
marginTableId: 0,
|
|
521
|
+
...(market.onlyIsolated === true && { onlyIsolated: true }),
|
|
522
|
+
...(market.marginMode && { marginMode: market.marginMode }),
|
|
519
523
|
},
|
|
520
524
|
};
|
|
521
525
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalMarketService.js","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Infer } from '@metamask/superstruct';\nimport {\n array,\n boolean,\n is,\n nullable,\n number,\n object,\n optional,\n string,\n tuple,\n type,\n union,\n} from '@metamask/superstruct';\nimport { bytesToHex, sha256, stringToBytes } from '@metamask/utils';\n\nimport { canonicalizeHyperLiquidDexes } from '../constants/hyperLiquidConfig.js';\nimport {\n PERPS_CONSTANTS,\n TERMINAL_API_CONFIG,\n} from '../constants/perpsConfig.js';\nimport type {\n MarketInfo,\n PerpsGlobalSnapshotRequest,\n PerpsGlobalSnapshotResult,\n PerpsMarketData,\n PerpsPlatformDependencies,\n TerminalAssetMetadata,\n} from '../types/index.js';\nimport { MarketCategory } from '../types/index.js';\nimport { ensureError } from '../utils/errorUtils.js';\nimport { formatChange } from '../utils/marketDataTransform.js';\nimport { clonePerpsMarketData } from '../utils/marketUtils.js';\n\nconst VALID_MARKET_TYPES = new Set<string>(Object.values(MarketCategory));\nconst GLOBAL_SNAPSHOT_SCHEMA_VERSION = 4;\nconst GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS = 30_000;\nconst GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES = 1_048_576;\nconst GLOBAL_SNAPSHOT_PERCENT_TOLERANCE = 0.01;\nconst GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS = 5_000;\nconst MINIMUM_EPOCH_MILLISECONDS = Date.UTC(2000, 0, 1);\nconst DECIMAL_PATTERN = /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$/u;\nconst NON_NEGATIVE_DECIMAL_PATTERN = /^(?:0|[1-9]\\d*)(?:\\.\\d+)?$/u;\nconst DEX_PATTERN = /^(?:main|[a-z0-9][a-z0-9-]*)$/u;\n\nconst GlobalSnapshotMarketStruct = type({\n id: string(),\n symbol: string(),\n network: string(),\n provider: string(),\n dex: string(),\n name: nullable(string()),\n description: nullable(string()),\n iconUrl: nullable(string()),\n szDecimals: number(),\n maxLeverage: number(),\n markPrice: string(),\n price: string(),\n midPrice: nullable(string()),\n oraclePrice: string(),\n change24h: string(),\n changePercent24h: number(),\n change5m: nullable(string()),\n changePercent5m: nullable(number()),\n change1h: nullable(string()),\n changePercent1h: nullable(number()),\n funding: string(),\n volume24h: string(),\n openInterest: string(),\n category: nullable(string()),\n keywords: nullable(array(string())),\n tags: nullable(array(string())),\n listedAt: nullable(number()),\n trend: array(tuple([number(), string()])),\n});\n\nconst GlobalSnapshotStruct = type({\n schemaVersion: number(),\n provider: string(),\n network: string(),\n enabledDexes: array(string()),\n fingerprint: string(),\n generatedAt: number(),\n receivedAt: number(),\n maxAgeMs: number(),\n complete: boolean(),\n perDexErrors: array(\n object({\n dex: string(),\n error: string(),\n }),\n ),\n markets: array(GlobalSnapshotMarketStruct),\n});\n\ntype GlobalSnapshotMarket = Infer<typeof GlobalSnapshotMarketStruct>;\ntype GlobalSnapshot = Infer<typeof GlobalSnapshotStruct>;\n\n/**\n * Runtime validation schema for a single market item returned by\n * `GET {terminalApi.marketDataUrl}`.\n *\n * Uses `type()` (loose object matching) so that extra fields the API sends\n * (e.g. `price`, `iconUrl`, `trend`) are silently accepted.\n * Each item is individually validated; items that fail validation are\n * filtered out and logged rather than rejecting the entire response.\n */\nconst TerminalPerpetualItemStruct = type({\n symbol: string(),\n name: optional(nullable(string())),\n description: optional(nullable(string())),\n szDecimals: optional(number()),\n maxLeverage: optional(number()),\n marginTableId: optional(number()),\n onlyIsolated: optional(boolean()),\n isDelisted: optional(boolean()),\n minimumOrderSize: optional(number()),\n keywords: optional(nullable(array(string()))),\n tags: optional(nullable(array(string()))),\n categories: optional(nullable(array(string()))),\n marketType: optional(nullable(string())),\n listedAt: optional(nullable(union([number(), string()]))),\n});\n\ntype TerminalPerpetualItem = Infer<typeof TerminalPerpetualItemStruct>;\n\ntype CacheEntry = {\n markets: MarketInfo[];\n metadata: Map<string, TerminalAssetMetadata>;\n timestamp: number;\n};\n\n/**\n * TerminalMarketService\n *\n * Fetches structured market metadata from the MetaMask Terminal API.\n * Caches responses for {@link TERMINAL_API_CONFIG.CacheTtlMs} to avoid\n * redundant network calls across polling cycles.\n *\n * Instance-based service with constructor injection of platform dependencies.\n */\nexport class TerminalMarketService {\n readonly #deps: PerpsPlatformDependencies;\n\n #cache: CacheEntry | null = null;\n\n readonly #globalSnapshotCache = new Map<string, PerpsGlobalSnapshotResult>();\n\n readonly #globalSnapshotInFlight = new Map<\n string,\n Promise<PerpsGlobalSnapshotResult>\n >();\n\n #globalSnapshotGeneration = 0;\n\n constructor(deps: PerpsPlatformDependencies) {\n this.#deps = deps;\n }\n\n /**\n * Fetch markets from the Terminal API.\n * Returns cached data when available and within TTL.\n *\n * @returns Object with mapped MarketInfo array and per-symbol metadata.\n */\n async fetchMarkets(): Promise<{\n markets: MarketInfo[];\n metadata: Map<string, TerminalAssetMetadata>;\n }> {\n if (\n this.#cache &&\n Date.now() - this.#cache.timestamp < TERMINAL_API_CONFIG.CacheTtlMs\n ) {\n return {\n markets: this.#cache.markets,\n metadata: this.#cache.metadata,\n };\n }\n\n const marketDataUrl =\n this.#deps.terminalApi?.marketDataUrl ?? this.#deps.terminalApiUrl;\n if (!marketDataUrl) {\n throw new Error('Terminal API market-data URL not configured');\n }\n\n const url = marketDataUrl;\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new Error('Terminal API fetch timed out')),\n TERMINAL_API_CONFIG.FetchTimeoutMs,\n );\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n\n if (!response.ok) {\n throw new Error(\n `Terminal API returned ${String(response.status)}: ${response.statusText}`,\n );\n }\n\n const body: unknown = await response.json();\n\n if (!Array.isArray(body)) {\n throw new Error(`Terminal API returned non-array body: ${typeof body}`);\n }\n\n const items = this.#validateItems(body);\n const markets = this.#mapToMarketInfo(items);\n const metadata = this.#extractMetadata(items);\n\n this.#cache = { markets, metadata, timestamp: Date.now() };\n return { markets, metadata };\n }\n\n /**\n * Fetch, authenticate by exact identity, and map a schema-v4 atomic market\n * snapshot. Accepted entries remain inside the source freshness window;\n * rejected responses are never cached.\n *\n * @param request - Exact provider/network/DEX identity expected by the client.\n * @returns UI-ready market data and its source-bounded expiry.\n */\n async fetchGlobalSnapshot(\n request: PerpsGlobalSnapshotRequest,\n ): Promise<PerpsGlobalSnapshotResult> {\n const identity = this.#validateRequestedIdentity(request);\n if (!this.#deps.terminalApi?.globalSnapshotUrl) {\n throw new Error('Terminal global snapshot URL not configured');\n }\n\n const url = this.#buildGlobalSnapshotUrl(\n this.#deps.terminalApi.globalSnapshotUrl,\n identity,\n );\n const cacheKey = [\n url,\n String(GLOBAL_SNAPSHOT_SCHEMA_VERSION),\n identity.provider,\n identity.network,\n identity.enabledDexes.join(','),\n ].join('|');\n const now = Date.now();\n const cached = this.#globalSnapshotCache.get(cacheKey);\n if (cached && now < cached.expiresAt) {\n return this.#cloneGlobalSnapshotResult(cached);\n }\n if (cached) {\n this.#globalSnapshotCache.delete(cacheKey);\n }\n\n const existing = this.#globalSnapshotInFlight.get(cacheKey);\n if (existing) {\n return this.#cloneGlobalSnapshotResult(await existing);\n }\n\n const generation = this.#globalSnapshotGeneration;\n const pending = this.#fetchAndValidateGlobalSnapshot(identity, url).then(\n (result) => {\n if (this.#globalSnapshotGeneration !== generation) {\n return result;\n }\n this.#globalSnapshotCache.set(cacheKey, result);\n return result;\n },\n );\n this.#globalSnapshotInFlight.set(cacheKey, pending);\n try {\n return this.#cloneGlobalSnapshotResult(await pending);\n } finally {\n if (this.#globalSnapshotInFlight.get(cacheKey) === pending) {\n this.#globalSnapshotInFlight.delete(cacheKey);\n }\n }\n }\n\n async #fetchAndValidateGlobalSnapshot(\n identity: PerpsGlobalSnapshotRequest,\n url: string,\n ): Promise<PerpsGlobalSnapshotResult> {\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new Error('Terminal global snapshot timed out')),\n TERMINAL_API_CONFIG.FetchTimeoutMs,\n );\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(\n `Terminal global snapshot returned ${String(response.status)}: ${response.statusText}`,\n );\n }\n\n const declaredLength = response.headers?.get('content-length');\n if (\n declaredLength !== null &&\n declaredLength !== undefined &&\n /^\\d+$/u.test(declaredLength) &&\n Number(declaredLength) > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES\n ) {\n throw new Error('Terminal global snapshot payload exceeds 1 MiB');\n }\n // React Native fetch does not consistently expose a streaming reader.\n // Reject declared oversize bodies before allocation, then enforce the same\n // byte cap after text() for servers that omit Content-Length.\n const text = await response.text();\n if (stringToBytes(text).byteLength > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES) {\n throw new Error('Terminal global snapshot payload exceeds 1 MiB');\n }\n let body: unknown;\n try {\n body = JSON.parse(text) as unknown;\n } catch {\n throw new Error('Terminal global snapshot returned invalid JSON');\n }\n if (!is(body, GlobalSnapshotStruct)) {\n throw new Error('Terminal global snapshot failed schema validation');\n }\n return this.#validateAndMapGlobalSnapshot(body, identity, Date.now());\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #validateAndMapGlobalSnapshot(\n snapshot: GlobalSnapshot,\n identity: PerpsGlobalSnapshotRequest,\n now: number,\n ): Promise<PerpsGlobalSnapshotResult> {\n if (snapshot.schemaVersion !== GLOBAL_SNAPSHOT_SCHEMA_VERSION) {\n throw new Error('Terminal global snapshot schema version mismatch');\n }\n if (\n snapshot.provider !== identity.provider ||\n snapshot.network !== identity.network\n ) {\n throw new Error('Terminal global snapshot identity mismatch');\n }\n\n const responseDexes = this.#normalizeDexes(snapshot.enabledDexes);\n if (\n responseDexes.length !== identity.enabledDexes.length ||\n responseDexes.some((dex, index) => dex !== identity.enabledDexes[index])\n ) {\n throw new Error('Terminal global snapshot DEX mismatch');\n }\n const expectedFingerprint = await this.#createFingerprint(identity);\n if (snapshot.fingerprint !== expectedFingerprint) {\n throw new Error('Terminal global snapshot fingerprint mismatch');\n }\n if (!snapshot.complete || snapshot.perDexErrors.length > 0) {\n throw new Error('Terminal global snapshot is incomplete');\n }\n if (\n !this.#isNonNegativeSafeInteger(snapshot.generatedAt) ||\n !this.#isNonNegativeSafeInteger(snapshot.receivedAt) ||\n !this.#isPositiveSafeInteger(snapshot.maxAgeMs) ||\n snapshot.receivedAt > snapshot.generatedAt ||\n snapshot.generatedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS ||\n snapshot.receivedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS\n ) {\n throw new Error('Terminal global snapshot has invalid timestamps');\n }\n\n const trustedMaxAgeMs = Math.min(\n snapshot.maxAgeMs,\n GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS,\n );\n const expiresAt = snapshot.receivedAt + trustedMaxAgeMs;\n if (now >= expiresAt) {\n throw new Error('Terminal global snapshot is stale');\n }\n if (snapshot.markets.length === 0) {\n throw new Error('Terminal global snapshot has no markets');\n }\n\n const marketKeys = new Set<string>();\n const representedDexes = new Set<string>();\n const mapped = snapshot.markets\n .map((market, index) => {\n this.#validateSnapshotMarket(\n market,\n identity,\n index,\n snapshot.generatedAt,\n );\n const key = `${market.dex}:${market.symbol}`;\n if (marketKeys.has(key)) {\n throw new Error(`Terminal global snapshot duplicates market ${key}`);\n }\n marketKeys.add(key);\n representedDexes.add(market.dex);\n return market;\n })\n .map((market) => this.#mapSnapshotMarket(market, expiresAt));\n const markets = mapped.map((market) => market.marketData);\n const marketInfos = mapped.map((market) => market.marketInfo);\n if (identity.enabledDexes.some((dex) => !representedDexes.has(dex))) {\n throw new Error('Terminal global snapshot is missing a requested DEX');\n }\n if (markets.length === 0) {\n throw new Error('Terminal global snapshot has no tradable markets');\n }\n\n return { markets, marketInfos, expiresAt };\n }\n\n #validateRequestedIdentity(\n request: PerpsGlobalSnapshotRequest,\n ): PerpsGlobalSnapshotRequest {\n if (request.provider !== 'hyperliquid') {\n throw new Error('Terminal global snapshot provider is unsupported');\n }\n if (request.network !== 'mainnet' && request.network !== 'testnet') {\n throw new Error('Terminal global snapshot network is unsupported');\n }\n return {\n provider: request.provider,\n network: request.network,\n enabledDexes: this.#normalizeDexes(request.enabledDexes),\n };\n }\n\n #buildGlobalSnapshotUrl(\n baseUrl: string,\n identity: PerpsGlobalSnapshotRequest,\n ): string {\n const query = new URLSearchParams({\n provider: identity.provider,\n network: identity.network,\n dexes: identity.enabledDexes.join(','),\n });\n return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${query.toString()}`;\n }\n\n #normalizeDexes(dexes: string[]): string[] {\n if (!Array.isArray(dexes) || dexes.length === 0) {\n throw new Error('Terminal global snapshot requires at least one DEX');\n }\n const normalized = dexes.map((dex) => {\n if (typeof dex !== 'string' || !DEX_PATTERN.test(dex)) {\n throw new Error('Terminal global snapshot contains an invalid DEX');\n }\n return dex;\n });\n if (new Set(normalized).size !== normalized.length) {\n throw new Error('Terminal global snapshot contains duplicate DEXes');\n }\n if (!normalized.includes('main')) {\n throw new Error('Terminal global snapshot requires the main DEX');\n }\n return canonicalizeHyperLiquidDexes(normalized);\n }\n\n async #createFingerprint(\n identity: PerpsGlobalSnapshotRequest,\n ): Promise<string> {\n const canonicalIdentity = JSON.stringify({\n provider: identity.provider,\n network: identity.network,\n enabledDexes: identity.enabledDexes,\n });\n const digest = await sha256(stringToBytes(canonicalIdentity));\n return `sha256:${bytesToHex(digest).slice(2)}`;\n }\n\n #validateSnapshotMarket(\n market: GlobalSnapshotMarket,\n identity: PerpsGlobalSnapshotRequest,\n index: number,\n generatedAt: number,\n ): void {\n const invalid = (field: string): Error =>\n new Error(\n `Terminal global snapshot market ${String(index)} has invalid ${field}`,\n );\n if (market.id.length === 0) {\n throw invalid('id');\n }\n if (market.network !== identity.network) {\n throw invalid('network');\n }\n if (!identity.enabledDexes.includes(market.dex)) {\n throw invalid('dex');\n }\n // `provider` is the venue (Hyperliquid), including HIP-3 markets whose\n // DEX lives in `dex`. Terminal v3 emits `provider: \"hyperliquid\"` for\n // both `main` and `xyz` rows; HIP-3 identity is `dex`, not `provider`.\n if (market.provider !== identity.provider) {\n throw invalid('provider');\n }\n const expectedPrefix = market.dex === 'main' ? '' : `${market.dex}:`;\n if (\n market.symbol.length === 0 ||\n (expectedPrefix\n ? !market.symbol.startsWith(expectedPrefix)\n : market.symbol.includes(':'))\n ) {\n throw invalid('symbol');\n }\n if (\n !this.#isNonNegativeSafeInteger(market.szDecimals) ||\n !this.#isPositiveSafeInteger(market.maxLeverage) ||\n (market.listedAt !== null &&\n (!this.#isNonNegativeSafeInteger(market.listedAt) ||\n market.listedAt < MINIMUM_EPOCH_MILLISECONDS ||\n market.listedAt > generatedAt))\n ) {\n throw invalid('integer field');\n }\n\n const decimalFields: [string, string, boolean][] = [\n ['markPrice', market.markPrice, true],\n ['price', market.price, true],\n ['oraclePrice', market.oraclePrice, true],\n ['change24h', market.change24h, false],\n ['volume24h', market.volume24h, true],\n ['openInterest', market.openInterest, true],\n ['funding', market.funding, false],\n ];\n if (market.midPrice !== null) {\n decimalFields.push(['midPrice', market.midPrice, true]);\n }\n if (market.change5m !== null) {\n decimalFields.push(['change5m', market.change5m, false]);\n }\n if (market.change1h !== null) {\n decimalFields.push(['change1h', market.change1h, false]);\n }\n for (const [field, value, nonNegative] of decimalFields) {\n const pattern = nonNegative\n ? NON_NEGATIVE_DECIMAL_PATTERN\n : DECIMAL_PATTERN;\n if (!pattern.test(value) || !Number.isFinite(Number(value))) {\n throw invalid(field);\n }\n }\n if (market.price !== market.markPrice) {\n throw invalid('deprecated price alias');\n }\n if (\n Number(market.oraclePrice) <= 0 ||\n (market.midPrice !== null && Number(market.midPrice) <= 0)\n ) {\n throw invalid('reference price');\n }\n const price = Number(market.markPrice);\n const change24h = Number(market.change24h);\n const previousPrice = price - change24h;\n if (price <= 0 || previousPrice <= 0 || !Number.isFinite(previousPrice)) {\n throw invalid('mark/change coherence');\n }\n const derivedPercent = (change24h / previousPrice) * 100;\n if (\n !Number.isFinite(derivedPercent) ||\n !Number.isFinite(market.changePercent24h) ||\n Math.abs(market.changePercent24h - derivedPercent) >\n GLOBAL_SNAPSHOT_PERCENT_TOLERANCE\n ) {\n throw invalid('changePercent24h coherence');\n }\n this.#validateRollingPair(\n market.change5m,\n market.changePercent5m,\n 'change5m',\n invalid,\n );\n this.#validateRollingPair(\n market.change1h,\n market.changePercent1h,\n 'change1h',\n invalid,\n );\n for (const [field, values] of [\n ['keywords', market.keywords],\n ['tags', market.tags],\n ] as const) {\n if (\n values !== null &&\n (values.some((value) => value.length === 0) ||\n new Set(values).size !== values.length)\n ) {\n throw invalid(field);\n }\n }\n for (const [field, value] of [\n ['name', market.name],\n ['description', market.description],\n ['iconUrl', market.iconUrl],\n ['category', market.category],\n ] as const) {\n if (value?.length === 0) {\n throw invalid(field);\n }\n }\n let previousTrendTimestamp = -1;\n for (const [timestamp, trendPrice] of market.trend) {\n if (\n !this.#isNonNegativeSafeInteger(timestamp) ||\n timestamp < MINIMUM_EPOCH_MILLISECONDS ||\n timestamp > generatedAt ||\n timestamp <= previousTrendTimestamp ||\n !NON_NEGATIVE_DECIMAL_PATTERN.test(trendPrice) ||\n !Number.isFinite(Number(trendPrice)) ||\n Number(trendPrice) <= 0\n ) {\n throw invalid('trend');\n }\n previousTrendTimestamp = timestamp;\n }\n }\n\n #mapSnapshotMarket(\n market: GlobalSnapshotMarket,\n sourceExpiresAt: number,\n ): { marketData: PerpsMarketData; marketInfo: MarketInfo } {\n const formatters = this.#deps.marketDataFormatters;\n // Keep both provider price semantics explicit in the wire contract. Core\n // maps markPrice to its UI price while retaining validation of midPrice.\n const price = Number(market.markPrice);\n const change24h = Number(market.change24h);\n const volume = Number(market.volume24h);\n const openInterest = Number(market.openInterest);\n const isHip3 = market.dex !== 'main';\n const marketType = this.#marketTypeFor(market.dex, market.category);\n const change5m = this.#mapRollingWindow(\n market.change5m,\n market.changePercent5m,\n formatters,\n );\n const change1h = this.#mapRollingWindow(\n market.change1h,\n market.changePercent1h,\n formatters,\n );\n\n return {\n marketData: {\n id: market.id,\n symbol: market.symbol,\n name: market.name ?? market.symbol,\n ...(market.description !== null && {\n description: market.description,\n }),\n maxLeverage: `${String(market.maxLeverage)}x`,\n price: formatters.formatPerpsFiat(price, {\n ranges: formatters.priceRangesUniversal,\n }),\n change24h: formatChange(change24h, formatters),\n change24hPercent: formatters.formatPercentage(market.changePercent24h),\n change5m: change5m.change,\n changePercent5m: change5m.percent,\n change1h: change1h.change,\n changePercent1h: change1h.percent,\n volume: formatters.formatVolume(volume),\n openInterest: formatters.formatVolume(openInterest),\n fundingRate: Number(market.funding),\n marketSource: isHip3 ? market.dex : undefined,\n marketType,\n isHip3,\n isNewMarket: isHip3 && marketType === undefined,\n ...(market.keywords && { keywords: market.keywords }),\n ...(market.tags && { tags: market.tags }),\n ...(market.category && { categories: [market.category] }),\n ...(market.listedAt !== null && { listedAt: market.listedAt }),\n trend: market.trend,\n dataSource: 'terminal-global-snapshot-mark',\n sourceExpiresAt,\n },\n // v4 markets carry szDecimals and maxLeverage. They do not carry a margin table.\n marketInfo: {\n name: market.symbol,\n szDecimals: market.szDecimals,\n maxLeverage: market.maxLeverage,\n marginTableId: 0,\n },\n };\n }\n\n #validateRollingPair(\n absolute: string | null,\n percent: number | null,\n field: string,\n invalid: (name: string) => Error,\n ): void {\n if (\n (absolute === null) !== (percent === null) ||\n (percent !== null && !Number.isFinite(percent))\n ) {\n throw invalid(`${field} pair`);\n }\n }\n\n #mapRollingWindow(\n absolute: string | null,\n percent: number | null,\n formatters: PerpsPlatformDependencies['marketDataFormatters'],\n ): { change: string; percent: string } {\n if (absolute === null || percent === null) {\n return {\n change: PERPS_CONSTANTS.FallbackDataDisplay,\n percent: PERPS_CONSTANTS.FallbackPercentageDisplay,\n };\n }\n return {\n change: formatChange(Number(absolute), formatters),\n percent: formatters.formatPercentage(percent),\n };\n }\n\n #marketTypeFor(\n dex: string,\n category: string | null,\n ): TerminalAssetMetadata['marketType'] | undefined {\n if (dex === 'main') {\n return MarketCategory.CryptoCurrency;\n }\n if (category === 'stocks') {\n return MarketCategory.Stock;\n }\n if (category === 'pre_ipo') {\n return MarketCategory.PreIpo;\n }\n if (category && VALID_MARKET_TYPES.has(category)) {\n return category as TerminalAssetMetadata['marketType'];\n }\n return undefined;\n }\n\n #cloneGlobalSnapshotResult(\n result: PerpsGlobalSnapshotResult,\n ): PerpsGlobalSnapshotResult {\n return {\n expiresAt: result.expiresAt,\n markets: clonePerpsMarketData(result.markets),\n marketInfos: result.marketInfos.map((market) => ({ ...market })),\n };\n }\n\n #isNonNegativeSafeInteger(value: unknown): value is number {\n return (\n typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\n );\n }\n\n #isPositiveSafeInteger(value: unknown): value is number {\n return this.#isNonNegativeSafeInteger(value) && value > 0;\n }\n\n /**\n * Invalidate the internal cache so the next fetch hits the network.\n */\n clearCache(): void {\n this.#cache = null;\n this.#globalSnapshotGeneration += 1;\n this.#globalSnapshotCache.clear();\n this.#globalSnapshotInFlight.clear();\n }\n\n /**\n * Validate raw API response items against the expected schema.\n * Items that fail validation are filtered out and logged rather than\n * rejecting the entire response.\n *\n * @param raw - The raw array from the API response body.\n * @returns Array of validated items.\n */\n #validateItems(raw: unknown[]): TerminalPerpetualItem[] {\n const valid: TerminalPerpetualItem[] = [];\n for (const item of raw) {\n if (is(item, TerminalPerpetualItemStruct)) {\n valid.push(item);\n } else {\n this.#deps.logger.error(\n ensureError(\n new Error('Terminal API item failed schema validation'),\n 'TerminalMarketService.validateItems',\n ),\n {\n tags: {\n feature: PERPS_CONSTANTS.FeatureName,\n source: 'terminal-api',\n },\n context: {\n name: 'TerminalMarketService.validateItems',\n data: {\n symbol:\n typeof item === 'object' &&\n item !== null &&\n Object.prototype.hasOwnProperty.call(item, 'symbol')\n ? (item as Record<string, unknown>).symbol\n : undefined,\n },\n },\n },\n );\n }\n }\n return valid;\n }\n\n /**\n * Map Terminal API items to the protocol-agnostic MarketInfo shape.\n *\n * @param items - Raw items from the API response.\n * @returns Array of MarketInfo objects.\n */\n #mapToMarketInfo(items: TerminalPerpetualItem[]): MarketInfo[] {\n return items\n .filter(\n (item) => typeof item.symbol === 'string' && item.symbol.length > 0,\n )\n .map((item) => ({\n name: item.symbol,\n szDecimals: item.szDecimals ?? 0,\n maxLeverage: item.maxLeverage ?? 1,\n marginTableId: item.marginTableId ?? 0,\n ...(item.onlyIsolated === true && { onlyIsolated: true as const }),\n ...(item.isDelisted === true && { isDelisted: true as const }),\n ...(item.minimumOrderSize !== undefined && {\n minimumOrderSize: item.minimumOrderSize,\n }),\n }));\n }\n\n /**\n * Extract per-symbol metadata for downstream merge into PerpsMarketData.\n *\n * @param items - Raw items from the API response.\n * @returns Map keyed by symbol with enrichment metadata.\n */\n #extractMetadata(\n items: TerminalPerpetualItem[],\n ): Map<string, TerminalAssetMetadata> {\n const map = new Map<string, TerminalAssetMetadata>();\n\n for (const item of items) {\n if (typeof item.symbol !== 'string' || item.symbol.length === 0) {\n continue;\n }\n\n const entry: TerminalAssetMetadata = {};\n\n if (typeof item.name === 'string' && item.name.length > 0) {\n entry.name = item.name;\n }\n\n if (typeof item.description === 'string' && item.description.length > 0) {\n entry.description = item.description;\n }\n\n if (Array.isArray(item.keywords) && item.keywords.length > 0) {\n entry.keywords = item.keywords;\n }\n if (Array.isArray(item.tags) && item.tags.length > 0) {\n entry.tags = item.tags;\n }\n if (Array.isArray(item.categories) && item.categories.length > 0) {\n entry.categories = item.categories;\n }\n if (\n typeof item.marketType === 'string' &&\n VALID_MARKET_TYPES.has(item.marketType)\n ) {\n entry.marketType =\n item.marketType as TerminalAssetMetadata['marketType'];\n }\n\n if (item.listedAt !== null && item.listedAt !== undefined) {\n const listedAtMs =\n typeof item.listedAt === 'number'\n ? item.listedAt\n : Date.parse(item.listedAt);\n if (isFinite(listedAtMs)) {\n entry.listedAt = listedAtMs;\n }\n }\n\n map.set(item.symbol, entry);\n }\n\n return map;\n }\n\n /**\n * Log a Terminal API error to Sentry without surfacing it to the user.\n *\n * @param error - The caught error.\n * @param method - The calling method name for context.\n */\n logError(error: unknown, method: string): void {\n this.#deps.logger.error(\n ensureError(error, `TerminalMarketService.${method}`),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName, source: 'terminal-api' },\n context: {\n name: `TerminalMarketService.${method}`,\n data: {\n url: method.includes('globalSnapshot')\n ? this.#deps.terminalApi?.globalSnapshotUrl\n : (this.#deps.terminalApi?.marketDataUrl ??\n this.#deps.terminalApiUrl),\n },\n },\n },\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"TerminalMarketService.js","sourceRoot":"","sources":["../../src/services/TerminalMarketService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Infer } from '@metamask/superstruct';\nimport {\n array,\n boolean,\n enums,\n is,\n nullable,\n number,\n object,\n optional,\n string,\n tuple,\n type,\n union,\n} from '@metamask/superstruct';\nimport { bytesToHex, sha256, stringToBytes } from '@metamask/utils';\n\nimport { canonicalizeHyperLiquidDexes } from '../constants/hyperLiquidConfig.js';\nimport {\n PERPS_CONSTANTS,\n TERMINAL_API_CONFIG,\n} from '../constants/perpsConfig.js';\nimport type {\n MarketInfo,\n PerpsGlobalSnapshotRequest,\n PerpsGlobalSnapshotResult,\n PerpsMarketData,\n PerpsPlatformDependencies,\n TerminalAssetMetadata,\n} from '../types/index.js';\nimport { MarketCategory } from '../types/index.js';\nimport { ensureError } from '../utils/errorUtils.js';\nimport { formatChange } from '../utils/marketDataTransform.js';\nimport { clonePerpsMarketData } from '../utils/marketUtils.js';\n\nconst VALID_MARKET_TYPES = new Set<string>(Object.values(MarketCategory));\nconst GLOBAL_SNAPSHOT_SCHEMA_VERSION = 4;\nconst GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS = 30_000;\nconst GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES = 1_048_576;\nconst GLOBAL_SNAPSHOT_PERCENT_TOLERANCE = 0.01;\nconst GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS = 5_000;\nconst MINIMUM_EPOCH_MILLISECONDS = Date.UTC(2000, 0, 1);\nconst DECIMAL_PATTERN = /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$/u;\nconst NON_NEGATIVE_DECIMAL_PATTERN = /^(?:0|[1-9]\\d*)(?:\\.\\d+)?$/u;\nconst DEX_PATTERN = /^(?:main|[a-z0-9][a-z0-9-]*)$/u;\n\nconst GlobalSnapshotMarketStruct = type({\n id: string(),\n symbol: string(),\n network: string(),\n provider: string(),\n dex: string(),\n name: nullable(string()),\n description: nullable(string()),\n iconUrl: nullable(string()),\n szDecimals: number(),\n maxLeverage: number(),\n markPrice: string(),\n price: string(),\n midPrice: nullable(string()),\n oraclePrice: string(),\n change24h: string(),\n changePercent24h: number(),\n change5m: nullable(string()),\n changePercent5m: nullable(number()),\n change1h: nullable(string()),\n changePercent1h: nullable(number()),\n funding: string(),\n volume24h: string(),\n openInterest: string(),\n category: nullable(string()),\n keywords: nullable(array(string())),\n tags: nullable(array(string())),\n listedAt: nullable(number()),\n trend: array(tuple([number(), string()])),\n onlyIsolated: optional(nullable(boolean())),\n marginMode: optional(nullable(enums(['strictIsolated', 'noCross']))),\n});\n\nconst GlobalSnapshotStruct = type({\n schemaVersion: number(),\n provider: string(),\n network: string(),\n enabledDexes: array(string()),\n fingerprint: string(),\n generatedAt: number(),\n receivedAt: number(),\n maxAgeMs: number(),\n complete: boolean(),\n perDexErrors: array(\n object({\n dex: string(),\n error: string(),\n }),\n ),\n markets: array(GlobalSnapshotMarketStruct),\n});\n\ntype GlobalSnapshotMarket = Infer<typeof GlobalSnapshotMarketStruct>;\ntype GlobalSnapshot = Infer<typeof GlobalSnapshotStruct>;\n\n/**\n * Runtime validation schema for a single market item returned by\n * `GET {terminalApi.marketDataUrl}`.\n *\n * Uses `type()` (loose object matching) so that extra fields the API sends\n * (e.g. `price`, `iconUrl`, `trend`) are silently accepted.\n * Each item is individually validated; items that fail validation are\n * filtered out and logged rather than rejecting the entire response.\n */\nconst TerminalPerpetualItemStruct = type({\n symbol: string(),\n name: optional(nullable(string())),\n description: optional(nullable(string())),\n szDecimals: optional(number()),\n maxLeverage: optional(number()),\n marginTableId: optional(number()),\n onlyIsolated: optional(boolean()),\n isDelisted: optional(boolean()),\n minimumOrderSize: optional(number()),\n keywords: optional(nullable(array(string()))),\n tags: optional(nullable(array(string()))),\n categories: optional(nullable(array(string()))),\n marketType: optional(nullable(string())),\n listedAt: optional(nullable(union([number(), string()]))),\n});\n\ntype TerminalPerpetualItem = Infer<typeof TerminalPerpetualItemStruct>;\n\ntype CacheEntry = {\n markets: MarketInfo[];\n metadata: Map<string, TerminalAssetMetadata>;\n timestamp: number;\n};\n\n/**\n * TerminalMarketService\n *\n * Fetches structured market metadata from the MetaMask Terminal API.\n * Caches responses for {@link TERMINAL_API_CONFIG.CacheTtlMs} to avoid\n * redundant network calls across polling cycles.\n *\n * Instance-based service with constructor injection of platform dependencies.\n */\nexport class TerminalMarketService {\n readonly #deps: PerpsPlatformDependencies;\n\n #cache: CacheEntry | null = null;\n\n readonly #globalSnapshotCache = new Map<string, PerpsGlobalSnapshotResult>();\n\n readonly #globalSnapshotInFlight = new Map<\n string,\n Promise<PerpsGlobalSnapshotResult>\n >();\n\n #globalSnapshotGeneration = 0;\n\n constructor(deps: PerpsPlatformDependencies) {\n this.#deps = deps;\n }\n\n /**\n * Fetch markets from the Terminal API.\n * Returns cached data when available and within TTL.\n *\n * @returns Object with mapped MarketInfo array and per-symbol metadata.\n */\n async fetchMarkets(): Promise<{\n markets: MarketInfo[];\n metadata: Map<string, TerminalAssetMetadata>;\n }> {\n if (\n this.#cache &&\n Date.now() - this.#cache.timestamp < TERMINAL_API_CONFIG.CacheTtlMs\n ) {\n return {\n markets: this.#cache.markets,\n metadata: this.#cache.metadata,\n };\n }\n\n const marketDataUrl =\n this.#deps.terminalApi?.marketDataUrl ?? this.#deps.terminalApiUrl;\n if (!marketDataUrl) {\n throw new Error('Terminal API market-data URL not configured');\n }\n\n const url = marketDataUrl;\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new Error('Terminal API fetch timed out')),\n TERMINAL_API_CONFIG.FetchTimeoutMs,\n );\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n\n if (!response.ok) {\n throw new Error(\n `Terminal API returned ${String(response.status)}: ${response.statusText}`,\n );\n }\n\n const body: unknown = await response.json();\n\n if (!Array.isArray(body)) {\n throw new Error(`Terminal API returned non-array body: ${typeof body}`);\n }\n\n const items = this.#validateItems(body);\n const markets = this.#mapToMarketInfo(items);\n const metadata = this.#extractMetadata(items);\n\n this.#cache = { markets, metadata, timestamp: Date.now() };\n return { markets, metadata };\n }\n\n /**\n * Fetch, authenticate by exact identity, and map a schema-v4 atomic market\n * snapshot. Accepted entries remain inside the source freshness window;\n * rejected responses are never cached.\n *\n * @param request - Exact provider/network/DEX identity expected by the client.\n * @returns UI-ready market data and its source-bounded expiry.\n */\n async fetchGlobalSnapshot(\n request: PerpsGlobalSnapshotRequest,\n ): Promise<PerpsGlobalSnapshotResult> {\n const identity = this.#validateRequestedIdentity(request);\n if (!this.#deps.terminalApi?.globalSnapshotUrl) {\n throw new Error('Terminal global snapshot URL not configured');\n }\n\n const url = this.#buildGlobalSnapshotUrl(\n this.#deps.terminalApi.globalSnapshotUrl,\n identity,\n );\n const cacheKey = [\n url,\n String(GLOBAL_SNAPSHOT_SCHEMA_VERSION),\n identity.provider,\n identity.network,\n identity.enabledDexes.join(','),\n ].join('|');\n const now = Date.now();\n const cached = this.#globalSnapshotCache.get(cacheKey);\n if (cached && now < cached.expiresAt) {\n return this.#cloneGlobalSnapshotResult(cached);\n }\n if (cached) {\n this.#globalSnapshotCache.delete(cacheKey);\n }\n\n const existing = this.#globalSnapshotInFlight.get(cacheKey);\n if (existing) {\n return this.#cloneGlobalSnapshotResult(await existing);\n }\n\n const generation = this.#globalSnapshotGeneration;\n const pending = this.#fetchAndValidateGlobalSnapshot(identity, url).then(\n (result) => {\n if (this.#globalSnapshotGeneration !== generation) {\n return result;\n }\n this.#globalSnapshotCache.set(cacheKey, result);\n return result;\n },\n );\n this.#globalSnapshotInFlight.set(cacheKey, pending);\n try {\n return this.#cloneGlobalSnapshotResult(await pending);\n } finally {\n if (this.#globalSnapshotInFlight.get(cacheKey) === pending) {\n this.#globalSnapshotInFlight.delete(cacheKey);\n }\n }\n }\n\n async #fetchAndValidateGlobalSnapshot(\n identity: PerpsGlobalSnapshotRequest,\n url: string,\n ): Promise<PerpsGlobalSnapshotResult> {\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new Error('Terminal global snapshot timed out')),\n TERMINAL_API_CONFIG.FetchTimeoutMs,\n );\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(\n `Terminal global snapshot returned ${String(response.status)}: ${response.statusText}`,\n );\n }\n\n const declaredLength = response.headers?.get('content-length');\n if (\n declaredLength !== null &&\n declaredLength !== undefined &&\n /^\\d+$/u.test(declaredLength) &&\n Number(declaredLength) > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES\n ) {\n throw new Error('Terminal global snapshot payload exceeds 1 MiB');\n }\n // React Native fetch does not consistently expose a streaming reader.\n // Reject declared oversize bodies before allocation, then enforce the same\n // byte cap after text() for servers that omit Content-Length.\n const text = await response.text();\n if (stringToBytes(text).byteLength > GLOBAL_SNAPSHOT_MAX_PAYLOAD_BYTES) {\n throw new Error('Terminal global snapshot payload exceeds 1 MiB');\n }\n let body: unknown;\n try {\n body = JSON.parse(text) as unknown;\n } catch {\n throw new Error('Terminal global snapshot returned invalid JSON');\n }\n if (!is(body, GlobalSnapshotStruct)) {\n throw new Error('Terminal global snapshot failed schema validation');\n }\n return this.#validateAndMapGlobalSnapshot(body, identity, Date.now());\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #validateAndMapGlobalSnapshot(\n snapshot: GlobalSnapshot,\n identity: PerpsGlobalSnapshotRequest,\n now: number,\n ): Promise<PerpsGlobalSnapshotResult> {\n if (snapshot.schemaVersion !== GLOBAL_SNAPSHOT_SCHEMA_VERSION) {\n throw new Error('Terminal global snapshot schema version mismatch');\n }\n if (\n snapshot.provider !== identity.provider ||\n snapshot.network !== identity.network\n ) {\n throw new Error('Terminal global snapshot identity mismatch');\n }\n\n const responseDexes = this.#normalizeDexes(snapshot.enabledDexes);\n if (\n responseDexes.length !== identity.enabledDexes.length ||\n responseDexes.some((dex, index) => dex !== identity.enabledDexes[index])\n ) {\n throw new Error('Terminal global snapshot DEX mismatch');\n }\n const expectedFingerprint = await this.#createFingerprint(identity);\n if (snapshot.fingerprint !== expectedFingerprint) {\n throw new Error('Terminal global snapshot fingerprint mismatch');\n }\n if (!snapshot.complete || snapshot.perDexErrors.length > 0) {\n throw new Error('Terminal global snapshot is incomplete');\n }\n if (\n !this.#isNonNegativeSafeInteger(snapshot.generatedAt) ||\n !this.#isNonNegativeSafeInteger(snapshot.receivedAt) ||\n !this.#isPositiveSafeInteger(snapshot.maxAgeMs) ||\n snapshot.receivedAt > snapshot.generatedAt ||\n snapshot.generatedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS ||\n snapshot.receivedAt > now + GLOBAL_SNAPSHOT_MAX_FUTURE_CLOCK_SKEW_MS\n ) {\n throw new Error('Terminal global snapshot has invalid timestamps');\n }\n\n const trustedMaxAgeMs = Math.min(\n snapshot.maxAgeMs,\n GLOBAL_SNAPSHOT_CONSUMER_MAX_AGE_MS,\n );\n const expiresAt = snapshot.receivedAt + trustedMaxAgeMs;\n if (now >= expiresAt) {\n throw new Error('Terminal global snapshot is stale');\n }\n if (snapshot.markets.length === 0) {\n throw new Error('Terminal global snapshot has no markets');\n }\n\n const marketKeys = new Set<string>();\n const representedDexes = new Set<string>();\n const mapped = snapshot.markets\n .map((market, index) => {\n this.#validateSnapshotMarket(\n market,\n identity,\n index,\n snapshot.generatedAt,\n );\n const key = `${market.dex}:${market.symbol}`;\n if (marketKeys.has(key)) {\n throw new Error(`Terminal global snapshot duplicates market ${key}`);\n }\n marketKeys.add(key);\n representedDexes.add(market.dex);\n return market;\n })\n .map((market) => this.#mapSnapshotMarket(market, expiresAt));\n const markets = mapped.map((market) => market.marketData);\n const marketInfos = mapped.map((market) => market.marketInfo);\n if (identity.enabledDexes.some((dex) => !representedDexes.has(dex))) {\n throw new Error('Terminal global snapshot is missing a requested DEX');\n }\n if (markets.length === 0) {\n throw new Error('Terminal global snapshot has no tradable markets');\n }\n\n return { markets, marketInfos, expiresAt };\n }\n\n #validateRequestedIdentity(\n request: PerpsGlobalSnapshotRequest,\n ): PerpsGlobalSnapshotRequest {\n if (request.provider !== 'hyperliquid') {\n throw new Error('Terminal global snapshot provider is unsupported');\n }\n if (request.network !== 'mainnet' && request.network !== 'testnet') {\n throw new Error('Terminal global snapshot network is unsupported');\n }\n return {\n provider: request.provider,\n network: request.network,\n enabledDexes: this.#normalizeDexes(request.enabledDexes),\n };\n }\n\n #buildGlobalSnapshotUrl(\n baseUrl: string,\n identity: PerpsGlobalSnapshotRequest,\n ): string {\n const query = new URLSearchParams({\n provider: identity.provider,\n network: identity.network,\n dexes: identity.enabledDexes.join(','),\n });\n return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${query.toString()}`;\n }\n\n #normalizeDexes(dexes: string[]): string[] {\n if (!Array.isArray(dexes) || dexes.length === 0) {\n throw new Error('Terminal global snapshot requires at least one DEX');\n }\n const normalized = dexes.map((dex) => {\n if (typeof dex !== 'string' || !DEX_PATTERN.test(dex)) {\n throw new Error('Terminal global snapshot contains an invalid DEX');\n }\n return dex;\n });\n if (new Set(normalized).size !== normalized.length) {\n throw new Error('Terminal global snapshot contains duplicate DEXes');\n }\n if (!normalized.includes('main')) {\n throw new Error('Terminal global snapshot requires the main DEX');\n }\n return canonicalizeHyperLiquidDexes(normalized);\n }\n\n async #createFingerprint(\n identity: PerpsGlobalSnapshotRequest,\n ): Promise<string> {\n const canonicalIdentity = JSON.stringify({\n provider: identity.provider,\n network: identity.network,\n enabledDexes: identity.enabledDexes,\n });\n const digest = await sha256(stringToBytes(canonicalIdentity));\n return `sha256:${bytesToHex(digest).slice(2)}`;\n }\n\n #validateSnapshotMarket(\n market: GlobalSnapshotMarket,\n identity: PerpsGlobalSnapshotRequest,\n index: number,\n generatedAt: number,\n ): void {\n const invalid = (field: string): Error =>\n new Error(\n `Terminal global snapshot market ${String(index)} has invalid ${field}`,\n );\n if (market.id.length === 0) {\n throw invalid('id');\n }\n if (market.network !== identity.network) {\n throw invalid('network');\n }\n if (!identity.enabledDexes.includes(market.dex)) {\n throw invalid('dex');\n }\n // `provider` is the venue (Hyperliquid), including HIP-3 markets whose\n // DEX lives in `dex`. Terminal v3 emits `provider: \"hyperliquid\"` for\n // both `main` and `xyz` rows; HIP-3 identity is `dex`, not `provider`.\n if (market.provider !== identity.provider) {\n throw invalid('provider');\n }\n const expectedPrefix = market.dex === 'main' ? '' : `${market.dex}:`;\n if (\n market.symbol.length === 0 ||\n (expectedPrefix\n ? !market.symbol.startsWith(expectedPrefix)\n : market.symbol.includes(':'))\n ) {\n throw invalid('symbol');\n }\n if (\n !this.#isNonNegativeSafeInteger(market.szDecimals) ||\n !this.#isPositiveSafeInteger(market.maxLeverage) ||\n (market.listedAt !== null &&\n (!this.#isNonNegativeSafeInteger(market.listedAt) ||\n market.listedAt < MINIMUM_EPOCH_MILLISECONDS ||\n market.listedAt > generatedAt))\n ) {\n throw invalid('integer field');\n }\n\n const decimalFields: [string, string, boolean][] = [\n ['markPrice', market.markPrice, true],\n ['price', market.price, true],\n ['oraclePrice', market.oraclePrice, true],\n ['change24h', market.change24h, false],\n ['volume24h', market.volume24h, true],\n ['openInterest', market.openInterest, true],\n ['funding', market.funding, false],\n ];\n if (market.midPrice !== null) {\n decimalFields.push(['midPrice', market.midPrice, true]);\n }\n if (market.change5m !== null) {\n decimalFields.push(['change5m', market.change5m, false]);\n }\n if (market.change1h !== null) {\n decimalFields.push(['change1h', market.change1h, false]);\n }\n for (const [field, value, nonNegative] of decimalFields) {\n const pattern = nonNegative\n ? NON_NEGATIVE_DECIMAL_PATTERN\n : DECIMAL_PATTERN;\n if (!pattern.test(value) || !Number.isFinite(Number(value))) {\n throw invalid(field);\n }\n }\n if (market.price !== market.markPrice) {\n throw invalid('deprecated price alias');\n }\n if (\n Number(market.oraclePrice) <= 0 ||\n (market.midPrice !== null && Number(market.midPrice) <= 0)\n ) {\n throw invalid('reference price');\n }\n const price = Number(market.markPrice);\n const change24h = Number(market.change24h);\n const previousPrice = price - change24h;\n if (price <= 0 || previousPrice <= 0 || !Number.isFinite(previousPrice)) {\n throw invalid('mark/change coherence');\n }\n const derivedPercent = (change24h / previousPrice) * 100;\n if (\n !Number.isFinite(derivedPercent) ||\n !Number.isFinite(market.changePercent24h) ||\n Math.abs(market.changePercent24h - derivedPercent) >\n GLOBAL_SNAPSHOT_PERCENT_TOLERANCE\n ) {\n throw invalid('changePercent24h coherence');\n }\n this.#validateRollingPair(\n market.change5m,\n market.changePercent5m,\n 'change5m',\n invalid,\n );\n this.#validateRollingPair(\n market.change1h,\n market.changePercent1h,\n 'change1h',\n invalid,\n );\n for (const [field, values] of [\n ['keywords', market.keywords],\n ['tags', market.tags],\n ] as const) {\n if (\n values !== null &&\n (values.some((value) => value.length === 0) ||\n new Set(values).size !== values.length)\n ) {\n throw invalid(field);\n }\n }\n for (const [field, value] of [\n ['name', market.name],\n ['description', market.description],\n ['iconUrl', market.iconUrl],\n ['category', market.category],\n ] as const) {\n if (value?.length === 0) {\n throw invalid(field);\n }\n }\n let previousTrendTimestamp = -1;\n for (const [timestamp, trendPrice] of market.trend) {\n if (\n !this.#isNonNegativeSafeInteger(timestamp) ||\n timestamp < MINIMUM_EPOCH_MILLISECONDS ||\n timestamp > generatedAt ||\n timestamp <= previousTrendTimestamp ||\n !NON_NEGATIVE_DECIMAL_PATTERN.test(trendPrice) ||\n !Number.isFinite(Number(trendPrice)) ||\n Number(trendPrice) <= 0\n ) {\n throw invalid('trend');\n }\n previousTrendTimestamp = timestamp;\n }\n }\n\n #mapSnapshotMarket(\n market: GlobalSnapshotMarket,\n sourceExpiresAt: number,\n ): { marketData: PerpsMarketData; marketInfo: MarketInfo } {\n const formatters = this.#deps.marketDataFormatters;\n // Keep both provider price semantics explicit in the wire contract. Core\n // maps markPrice to its UI price while retaining validation of midPrice.\n const price = Number(market.markPrice);\n const change24h = Number(market.change24h);\n const volume = Number(market.volume24h);\n const openInterest = Number(market.openInterest);\n const isHip3 = market.dex !== 'main';\n const marketType = this.#marketTypeFor(market.dex, market.category);\n const change5m = this.#mapRollingWindow(\n market.change5m,\n market.changePercent5m,\n formatters,\n );\n const change1h = this.#mapRollingWindow(\n market.change1h,\n market.changePercent1h,\n formatters,\n );\n\n return {\n marketData: {\n id: market.id,\n symbol: market.symbol,\n name: market.name ?? market.symbol,\n ...(market.description !== null && {\n description: market.description,\n }),\n maxLeverage: `${String(market.maxLeverage)}x`,\n price: formatters.formatPerpsFiat(price, {\n ranges: formatters.priceRangesUniversal,\n }),\n change24h: formatChange(change24h, formatters),\n change24hPercent: formatters.formatPercentage(market.changePercent24h),\n change5m: change5m.change,\n changePercent5m: change5m.percent,\n change1h: change1h.change,\n changePercent1h: change1h.percent,\n volume: formatters.formatVolume(volume),\n openInterest: formatters.formatVolume(openInterest),\n fundingRate: Number(market.funding),\n marketSource: isHip3 ? market.dex : undefined,\n marketType,\n isHip3,\n isNewMarket: isHip3 && marketType === undefined,\n ...(market.keywords && { keywords: market.keywords }),\n ...(market.tags && { tags: market.tags }),\n ...(market.category && { categories: [market.category] }),\n ...(market.listedAt !== null && { listedAt: market.listedAt }),\n trend: market.trend,\n dataSource: 'terminal-global-snapshot-mark',\n sourceExpiresAt,\n },\n // v4 markets carry szDecimals and maxLeverage. They do not carry a margin table.\n marketInfo: {\n name: market.symbol,\n szDecimals: market.szDecimals,\n maxLeverage: market.maxLeverage,\n marginTableId: 0,\n ...(market.onlyIsolated === true && { onlyIsolated: true as const }),\n ...(market.marginMode && { marginMode: market.marginMode }),\n },\n };\n }\n\n #validateRollingPair(\n absolute: string | null,\n percent: number | null,\n field: string,\n invalid: (name: string) => Error,\n ): void {\n if (\n (absolute === null) !== (percent === null) ||\n (percent !== null && !Number.isFinite(percent))\n ) {\n throw invalid(`${field} pair`);\n }\n }\n\n #mapRollingWindow(\n absolute: string | null,\n percent: number | null,\n formatters: PerpsPlatformDependencies['marketDataFormatters'],\n ): { change: string; percent: string } {\n if (absolute === null || percent === null) {\n return {\n change: PERPS_CONSTANTS.FallbackDataDisplay,\n percent: PERPS_CONSTANTS.FallbackPercentageDisplay,\n };\n }\n return {\n change: formatChange(Number(absolute), formatters),\n percent: formatters.formatPercentage(percent),\n };\n }\n\n #marketTypeFor(\n dex: string,\n category: string | null,\n ): TerminalAssetMetadata['marketType'] | undefined {\n if (dex === 'main') {\n return MarketCategory.CryptoCurrency;\n }\n if (category === 'stocks') {\n return MarketCategory.Stock;\n }\n if (category === 'pre_ipo') {\n return MarketCategory.PreIpo;\n }\n if (category && VALID_MARKET_TYPES.has(category)) {\n return category as TerminalAssetMetadata['marketType'];\n }\n return undefined;\n }\n\n #cloneGlobalSnapshotResult(\n result: PerpsGlobalSnapshotResult,\n ): PerpsGlobalSnapshotResult {\n return {\n expiresAt: result.expiresAt,\n markets: clonePerpsMarketData(result.markets),\n marketInfos: result.marketInfos.map((market) => ({ ...market })),\n };\n }\n\n #isNonNegativeSafeInteger(value: unknown): value is number {\n return (\n typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\n );\n }\n\n #isPositiveSafeInteger(value: unknown): value is number {\n return this.#isNonNegativeSafeInteger(value) && value > 0;\n }\n\n /**\n * Invalidate the internal cache so the next fetch hits the network.\n */\n clearCache(): void {\n this.#cache = null;\n this.#globalSnapshotGeneration += 1;\n this.#globalSnapshotCache.clear();\n this.#globalSnapshotInFlight.clear();\n }\n\n /**\n * Validate raw API response items against the expected schema.\n * Items that fail validation are filtered out and logged rather than\n * rejecting the entire response.\n *\n * @param raw - The raw array from the API response body.\n * @returns Array of validated items.\n */\n #validateItems(raw: unknown[]): TerminalPerpetualItem[] {\n const valid: TerminalPerpetualItem[] = [];\n for (const item of raw) {\n if (is(item, TerminalPerpetualItemStruct)) {\n valid.push(item);\n } else {\n this.#deps.logger.error(\n ensureError(\n new Error('Terminal API item failed schema validation'),\n 'TerminalMarketService.validateItems',\n ),\n {\n tags: {\n feature: PERPS_CONSTANTS.FeatureName,\n source: 'terminal-api',\n },\n context: {\n name: 'TerminalMarketService.validateItems',\n data: {\n symbol:\n typeof item === 'object' &&\n item !== null &&\n Object.prototype.hasOwnProperty.call(item, 'symbol')\n ? (item as Record<string, unknown>).symbol\n : undefined,\n },\n },\n },\n );\n }\n }\n return valid;\n }\n\n /**\n * Map Terminal API items to the protocol-agnostic MarketInfo shape.\n *\n * @param items - Raw items from the API response.\n * @returns Array of MarketInfo objects.\n */\n #mapToMarketInfo(items: TerminalPerpetualItem[]): MarketInfo[] {\n return items\n .filter(\n (item) => typeof item.symbol === 'string' && item.symbol.length > 0,\n )\n .map((item) => ({\n name: item.symbol,\n szDecimals: item.szDecimals ?? 0,\n maxLeverage: item.maxLeverage ?? 1,\n marginTableId: item.marginTableId ?? 0,\n ...(item.onlyIsolated === true && { onlyIsolated: true as const }),\n ...(item.isDelisted === true && { isDelisted: true as const }),\n ...(item.minimumOrderSize !== undefined && {\n minimumOrderSize: item.minimumOrderSize,\n }),\n }));\n }\n\n /**\n * Extract per-symbol metadata for downstream merge into PerpsMarketData.\n *\n * @param items - Raw items from the API response.\n * @returns Map keyed by symbol with enrichment metadata.\n */\n #extractMetadata(\n items: TerminalPerpetualItem[],\n ): Map<string, TerminalAssetMetadata> {\n const map = new Map<string, TerminalAssetMetadata>();\n\n for (const item of items) {\n if (typeof item.symbol !== 'string' || item.symbol.length === 0) {\n continue;\n }\n\n const entry: TerminalAssetMetadata = {};\n\n if (typeof item.name === 'string' && item.name.length > 0) {\n entry.name = item.name;\n }\n\n if (typeof item.description === 'string' && item.description.length > 0) {\n entry.description = item.description;\n }\n\n if (Array.isArray(item.keywords) && item.keywords.length > 0) {\n entry.keywords = item.keywords;\n }\n if (Array.isArray(item.tags) && item.tags.length > 0) {\n entry.tags = item.tags;\n }\n if (Array.isArray(item.categories) && item.categories.length > 0) {\n entry.categories = item.categories;\n }\n if (\n typeof item.marketType === 'string' &&\n VALID_MARKET_TYPES.has(item.marketType)\n ) {\n entry.marketType =\n item.marketType as TerminalAssetMetadata['marketType'];\n }\n\n if (item.listedAt !== null && item.listedAt !== undefined) {\n const listedAtMs =\n typeof item.listedAt === 'number'\n ? item.listedAt\n : Date.parse(item.listedAt);\n if (isFinite(listedAtMs)) {\n entry.listedAt = listedAtMs;\n }\n }\n\n map.set(item.symbol, entry);\n }\n\n return map;\n }\n\n /**\n * Log a Terminal API error to Sentry without surfacing it to the user.\n *\n * @param error - The caught error.\n * @param method - The calling method name for context.\n */\n logError(error: unknown, method: string): void {\n this.#deps.logger.error(\n ensureError(error, `TerminalMarketService.${method}`),\n {\n tags: { feature: PERPS_CONSTANTS.FeatureName, source: 'terminal-api' },\n context: {\n name: `TerminalMarketService.${method}`,\n data: {\n url: method.includes('globalSnapshot')\n ? this.#deps.terminalApi?.globalSnapshotUrl\n : (this.#deps.terminalApi?.marketDataUrl ??\n this.#deps.terminalApiUrl),\n },\n },\n },\n );\n }\n}\n"]}
|
|
@@ -430,7 +430,8 @@ export function adaptPositionFromLighter(position, maxLeverage = LIGHTER_MAX_LEV
|
|
|
430
430
|
? null
|
|
431
431
|
: position.liquidationPrice,
|
|
432
432
|
maxLeverage,
|
|
433
|
-
|
|
433
|
+
// A fraction (0.1 = 10%), the unit Hyperliquid positions use.
|
|
434
|
+
returnOnEquity: marginUsed > 0 ? String(unrealizedPnl / marginUsed) : '0',
|
|
434
435
|
cumulativeFunding: {
|
|
435
436
|
allTime: '0',
|
|
436
437
|
sinceOpen: '0',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lighterAdapter.js","sourceRoot":"","sources":["../../src/utils/lighterAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Lighter API Adapter Utilities\n *\n * Adapters transforming zkLighter REST payloads into the MetaMask Perps API\n * canonical types. Portable: no mobile-specific imports; formatters are\n * injected via the MarketDataFormatters interface.\n *\n * Key differences from HyperLiquid:\n * - Prices/sizes are human-readable decimal strings in REST responses, but\n * integers scaled by `supported_*_decimals` on the signing path.\n * - Position side is a `sign` field (1 = long, -1 = short).\n * - USDC collateral, single margin mode per account in the POC (cross).\n */\n\nimport {\n LIGHTER_DATA_INTEGRITY_PREFIX,\n LIGHTER_MAX_LEVERAGE,\n LIGHTER_UNSUPPORTED_CAPABILITY_PREFIX,\n parseLighterStrictDecimal,\n} from '../constants/lighterConfig.js';\nimport type {\n AccountState,\n MarketDataFormatters,\n MarketInfo,\n Order,\n OrderFill,\n PerpsMarketData,\n Position,\n PriceUpdate,\n TriggerOrderType,\n} from '../types/index.js';\nimport type {\n LighterApiOrder,\n LighterApiPosition,\n LighterOrderBookDetail,\n LighterOrderBookMeta,\n LighterRestTrade,\n LighterWsTrade,\n LighterSubAccount,\n LighterWsMarketStat,\n LighterWsUserStats,\n} from '../types/lighter-types.js';\n\n/**\n * Parse an account-state number at the untrusted venue boundary. Account\n * balances feed trading availability and must never accept prefix parses or\n * propagate NaN/Infinity into canonical state.\n *\n * @param value - Raw venue decimal string.\n * @param field - Field identity for the integrity error.\n * @returns A finite, fully parsed number.\n */\nfunction parseStrictAccountDecimal(value: string, field: string): number {\n const parsed = parseLighterStrictDecimal(value);\n if (parsed === null || !Number.isFinite(parsed)) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} ${field} '${String(value)}'`,\n );\n }\n return parsed;\n}\n\n/**\n * Format a price change value with sign prefix.\n *\n * @param change - The price change value to format.\n * @param formatters - Injectable formatters for platform-agnostic formatting.\n * @returns The formatted change string with sign and dollar symbol.\n */\nfunction formatChange(\n change: number,\n formatters: MarketDataFormatters,\n): string {\n if (isNaN(change) || !isFinite(change) || change === 0) {\n return '$0.00';\n }\n\n const formatted = formatters.formatPerpsFiat(Math.abs(change), {\n ranges: formatters.priceRangesUniversal,\n });\n const valueWithoutDollar = formatted.replace('$', '');\n return change > 0 ? `+$${valueWithoutDollar}` : `-$${valueWithoutDollar}`;\n}\n\n// ============================================================================\n// Market Transformation\n// ============================================================================\n\n/**\n * Transform a Lighter order book meta entry into canonical MarketInfo.\n *\n * @param market - Market metadata from `GET /api/v1/orderBooks`.\n * @param maxLeverage - Verified per-market leverage from margin metadata.\n * @returns MetaMask Perps API market info object.\n */\nexport function adaptMarketFromLighter(\n market: LighterOrderBookMeta,\n maxLeverage: number,\n): MarketInfo {\n if (!Number.isSafeInteger(maxLeverage) || maxLeverage <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} missing authoritative leverage for ${market.symbol}`,\n );\n }\n return {\n name: market.symbol,\n szDecimals: market.supportedSizeDecimals,\n priceDecimals: market.supportedPriceDecimals,\n maxLeverage,\n marginTableId: 0, // Lighter does not use margin tables\n minimumOrderSize: parseFloat(market.minQuoteAmount),\n providerId: 'lighter',\n ...(market.status === 'active' ? {} : { isDelisted: true as const }),\n };\n}\n\n/**\n * Transform a Lighter order book detail into UI-ready PerpsMarketData.\n *\n * @param detail - Market stats from `GET /api/v1/orderBookDetails`.\n * @param formatters - Injectable formatters for platform-agnostic formatting.\n * @returns MetaMask Perps API market data object.\n */\nexport function adaptMarketDataFromLighter(\n detail: LighterOrderBookDetail,\n formatters: MarketDataFormatters,\n): PerpsMarketData {\n const { minInitialMarginFraction } = detail;\n if (\n !Number.isFinite(minInitialMarginFraction) ||\n minInitialMarginFraction === undefined ||\n minInitialMarginFraction <= 0\n ) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} missing authoritative leverage for ${detail.symbol}`,\n );\n }\n const price = detail.lastTradePrice ?? 0;\n const changePercent = detail.dailyPriceChange ?? 0;\n // dailyPriceChange is a percentage; recover the absolute change.\n const changeAbs =\n changePercent === 0 ? 0 : (price * changePercent) / (100 + changePercent);\n\n const maxLeverage = Math.floor(10_000 / minInitialMarginFraction);\n if (!Number.isSafeInteger(maxLeverage) || maxLeverage <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} invalid authoritative leverage for ${detail.symbol}`,\n );\n }\n return {\n symbol: detail.symbol,\n name: detail.symbol,\n maxLeverage: `${maxLeverage}x`,\n price: formatters.formatPerpsFiat(price, {\n ranges: formatters.priceRangesUniversal,\n }),\n change24h: formatChange(changeAbs, formatters),\n change24hPercent: `${changePercent >= 0 ? '+' : ''}${changePercent.toFixed(2)}%`,\n volume: formatters.formatVolume(detail.dailyQuoteTokenVolume ?? 0),\n openInterest: formatters.formatVolume(detail.openInterest ?? 0),\n };\n}\n\n/**\n * Transform a Lighter order book detail into a canonical PriceUpdate for\n * price-stream subscribers (REST polling stands in for a WS feed in the POC).\n *\n * @param detail - Market stats from `GET /api/v1/orderBookDetails`.\n * @param timestamp - Update timestamp (injected for determinism in tests).\n * @returns MetaMask Perps API price update object.\n */\nexport function adaptPriceUpdateFromLighter(\n detail: LighterOrderBookDetail,\n timestamp: number,\n): PriceUpdate {\n return {\n symbol: detail.symbol,\n price: String(detail.lastTradePrice ?? 0),\n timestamp,\n percentChange24h: String(detail.dailyPriceChange ?? 0),\n volume24h: detail.dailyQuoteTokenVolume ?? 0,\n openInterest: detail.openInterest ?? 0,\n isTradable: detail.status === 'active',\n };\n}\n\n/**\n * Transform a `market_stats` WebSocket entry into a canonical PriceUpdate.\n * Richer than the REST fallback: carries mid/bid/ask, mark price, and funding.\n *\n * @param stat - Market stats entry from the `market_stats/all` WS channel.\n * @param timestamp - Update timestamp (injected for determinism in tests).\n * @returns MetaMask Perps API price update object.\n */\nexport function adaptPriceUpdateFromLighterWsStat(\n stat: LighterWsMarketStat,\n timestamp: number,\n): PriceUpdate {\n const bestBid = parseFloat(stat.bestBidPrice);\n const bestAsk = parseFloat(stat.bestAskPrice);\n const spread =\n Number.isFinite(bestBid) && Number.isFinite(bestAsk)\n ? String(bestAsk - bestBid)\n : undefined;\n return {\n symbol: stat.symbol,\n price: stat.midPrice,\n timestamp,\n percentChange24h: String(stat.dailyPriceChange ?? 0),\n bestBid: stat.bestBidPrice,\n bestAsk: stat.bestAskPrice,\n spread,\n markPrice: stat.markPrice,\n funding: parseFloat(stat.currentFundingRate ?? stat.fundingRate ?? '0'),\n openInterest: parseFloat(stat.openInterest ?? '0'),\n volume24h: stat.dailyQuoteTokenVolume ?? 0,\n isTradable: true,\n };\n}\n\n/**\n * Transform a `user_stats` WebSocket stats block into canonical AccountState.\n *\n * @param stats - Stats block from the `user_stats/{account_index}` channel.\n * @returns MetaMask Perps API account state object.\n */\nexport function adaptAccountStateFromLighterUserStats(\n stats: LighterWsUserStats,\n): AccountState {\n const collateral = parseStrictAccountDecimal(\n stats.collateral,\n 'WebSocket collateral',\n );\n const available = parseStrictAccountDecimal(\n stats.availableBalance,\n 'WebSocket available balance',\n );\n const portfolioValue = parseStrictAccountDecimal(\n stats.portfolioValue,\n 'WebSocket portfolio value',\n );\n return {\n totalBalance: String(portfolioValue),\n spendableBalance: String(available),\n withdrawableBalance: String(available),\n marginUsed: String(Math.max(collateral - available, 0)),\n unrealizedPnl: String(portfolioValue - collateral),\n returnOnEquity:\n collateral > 0\n ? String(((portfolioValue - collateral) / collateral) * 100)\n : '0',\n };\n}\n\n/**\n * Transform a Lighter trade (REST `/trades` or WS `account_all_trades`) into\n * a canonical OrderFill from the perspective of `accountIndex`.\n *\n * @param trade - Trade entry (post-camelization).\n * @param symbol - Market symbol resolved from the market id.\n * @param accountIndex - The account whose perspective determines the side.\n * @returns MetaMask Perps API order fill object.\n */\n/**\n * Derive the lifecycle direction of a fill from the venue's\n * position-before context, in the vocabulary client transforms consume\n * (`Open Long`, `Close Short`, `Long > Short`, ...).\n *\n * The venue reports the side's ABSOLUTE position size before the trade and\n * whether its sign changed. Combined with the trade side that is enough:\n * buying reduces shorts and opens longs; selling reduces longs and opens\n * shorts. A partial fill with no sign change is disambiguated by realized\n * pnl (closing realizes pnl, opening does not). Without position context\n * the side-only `Buy`/`Sell` vocabulary is used.\n *\n * @param context - Trade side, size, and position-before data.\n * @param context.isBuy - Whether our side bought.\n * @param context.size - Trade size (base units, absolute).\n * @param context.positionBefore - Our side's absolute position size before.\n * @param context.signChanged - Whether our side's position sign changed.\n * @param context.pnl - Realized pnl for our side, or undefined when omitted.\n * @returns Client-facing direction string.\n */\nexport function deriveLighterFillDirection(context: {\n isBuy: boolean;\n size: number;\n positionBefore: number;\n signChanged: boolean | undefined;\n pnl: number | undefined;\n}): string {\n const { isBuy, size, positionBefore, signChanged, pnl } = context;\n if (!Number.isFinite(positionBefore)) {\n return isBuy ? 'Buy' : 'Sell';\n }\n if (positionBefore === 0) {\n return isBuy ? 'Open Long' : 'Open Short';\n }\n // A flat baseline proves an open. On an existing position, nonzero\n // realized PnL proves reduction; otherwise an omitted flag is ambiguous.\n if (signChanged === undefined && (pnl === undefined || pnl === 0)) {\n return isBuy ? 'Buy' : 'Sell';\n }\n if (\n signChanged ||\n (signChanged === undefined && pnl !== undefined && pnl !== 0)\n ) {\n // Crossed past zero → flipped; landed exactly on zero → full close.\n if (size > positionBefore * 1.000001) {\n return isBuy ? 'Short > Long' : 'Long > Short';\n }\n return isBuy ? 'Close Short' : 'Close Long';\n }\n // Partial fill on an existing position: realized pnl proves it reduced.\n if (pnl !== undefined && pnl !== 0) {\n return isBuy ? 'Close Short' : 'Close Long';\n }\n // Zero or unknown pnl with no sign change is ambiguous from this\n // payload (a break-even partial close and an add both fit): fall back to\n // the side-only vocabulary instead of asserting Open without evidence.\n return isBuy ? 'Buy' : 'Sell';\n}\n\n/**\n * Parse one optional venue fee without treating malformed supplied values as\n * an omitted zero.\n *\n * @param value - Raw maker or taker fee.\n * @param tradeId - Trade identity for error context.\n * @param role - Fee role for error context.\n * @returns The finite nonnegative fee, with undefined mapped to venue-zero.\n */\nfunction parseLighterTradeFee(\n value: unknown,\n tradeId: number,\n role: 'maker' | 'taker',\n): number {\n let parsed: number | null;\n if (value === undefined) {\n parsed = 0;\n } else if (typeof value === 'number') {\n parsed = value;\n } else if (typeof value === 'string') {\n parsed = parseLighterStrictDecimal(value);\n } else {\n parsed = null;\n }\n if (parsed === null || !Number.isFinite(parsed) || parsed < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${tradeId} has invalid ${role} fee`,\n );\n }\n return parsed;\n}\n\nexport function adaptFillFromLighterTrade(\n trade: LighterRestTrade | LighterWsTrade,\n symbol: string,\n accountIndex: number,\n): OrderFill {\n const identifiers = [\n ['trade id', trade.tradeId],\n ['market id', trade.marketId],\n ['ask id', trade.askId],\n ['bid id', trade.bidId],\n ['ask account id', trade.askAccountId],\n ['bid account id', trade.bidAccountId],\n ] as const;\n for (const [field, value] of identifiers) {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${String(trade.tradeId)} has invalid ${field}`,\n );\n }\n }\n const accountIsAsk = trade.askAccountId === accountIndex;\n const accountIsBid = trade.bidAccountId === accountIndex;\n if (accountIsAsk === accountIsBid) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} account ${accountIndex} is not an unambiguous participant in trade ${trade.tradeId}`,\n );\n }\n const size = parseLighterStrictDecimal(trade.size);\n const price = parseLighterStrictDecimal(trade.price);\n if (size === null || !Number.isFinite(size) || size <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} has invalid size`,\n );\n }\n if (price === null || !Number.isFinite(price) || price <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} has invalid price`,\n );\n }\n if (!Number.isSafeInteger(trade.timestamp) || trade.timestamp < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} has invalid timestamp`,\n );\n }\n if (typeof trade.isMakerAsk !== 'boolean') {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} is missing maker-role context`,\n );\n }\n // Our side's role decides which fee applies; the venue includes the fee\n // fields only when nonzero (zero is the current standard-account truth).\n const accountIsMaker = accountIsAsk === trade.isMakerAsk;\n // Standard accounts (the only supported type — the provider gates\n // Premium at account resolution) pay zero fees, so zero is venue truth.\n // A PRESENT nonzero fee ON OUR SIDE contradicts that gate and its wire\n // unit is unverified: refusing loudly beats silently coercing a real fee\n // to $0. A valid nonzero counterparty fee is allowed, but malformed\n // supplied counterparty data still invalidates the venue row.\n const makerFee = parseLighterTradeFee(trade.makerFee, trade.tradeId, 'maker');\n const takerFee = parseLighterTradeFee(trade.takerFee, trade.tradeId, 'taker');\n const ourFeeNumeric = accountIsMaker ? makerFee : takerFee;\n if (ourFeeNumeric !== 0) {\n throw new Error(\n `${LIGHTER_UNSUPPORTED_CAPABILITY_PREFIX} nonzero fee in trade ${trade.tradeId}: fee unit is unverified`,\n );\n }\n const fee = '0';\n const isBuy = !accountIsAsk;\n // The account's maker/taker role selects the matching pre-trade position\n // context. Omitted sign-change flags retain an unknown direction for\n // existing positions; malformed supplied context still fails closed.\n const positionBeforeRaw = accountIsMaker\n ? trade.makerPositionSizeBefore\n : trade.takerPositionSizeBefore;\n const positionBefore = parseLighterStrictDecimal(positionBeforeRaw);\n const signChanged = accountIsMaker\n ? trade.makerPositionSignChanged\n : trade.takerPositionSignChanged;\n if (\n positionBefore === null ||\n !Number.isFinite(positionBefore) ||\n positionBefore < 0 ||\n (signChanged !== undefined && typeof signChanged !== 'boolean')\n ) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} is missing valid position context`,\n );\n }\n const pnl = accountIsAsk ? trade.askAccountPnl : trade.bidAccountPnl;\n // Omitted amounts remain unknown, including closes and flips. Position\n // context can establish direction without establishing the realized amount.\n const parsedPnl =\n pnl === undefined ? undefined : parseLighterStrictDecimal(pnl);\n if (\n parsedPnl === null ||\n (pnl !== undefined &&\n (typeof pnl !== 'string' || !Number.isFinite(parsedPnl)))\n ) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} is missing valid account pnl`,\n );\n }\n const direction = deriveLighterFillDirection({\n isBuy,\n size,\n positionBefore,\n signChanged,\n pnl: parsedPnl,\n });\n // Signed pre-trade position, derivable whenever the direction proved the\n // orientation: closing/flipping a long means it was +before, a short\n // -before; opens start from zero. Clients size flip displays from this.\n let startPosition: string | undefined;\n if (direction.startsWith('Open')) {\n startPosition = '0';\n } else if (direction === 'Close Long' || direction === 'Long > Short') {\n startPosition = String(positionBefore);\n } else if (direction === 'Close Short' || direction === 'Short > Long') {\n startPosition = String(-positionBefore);\n }\n return {\n orderId: String(accountIsAsk ? trade.askId : trade.bidId),\n // Lighter's unique execution id, validated as a safe non-negative\n // integer above. Order id alone cannot separate two fills of one order.\n fillId: String(trade.tradeId),\n symbol,\n side: accountIsAsk ? 'sell' : 'buy',\n size: trade.size,\n price: trade.price,\n // The venue reports realized pnl per side of the trade.\n ...(pnl === undefined ? {} : { pnl }),\n direction,\n ...(startPosition === undefined ? {} : { startPosition }),\n fee,\n feeToken: 'USDC',\n timestamp: trade.timestamp,\n // Lets clients apply venue-specific presentation rules (e.g. the\n // ambiguous side-only vocabulary) without guessing the source.\n providerId: 'lighter',\n };\n}\n\n// ============================================================================\n// Position Transformation\n// ============================================================================\n\n/**\n * Transform a Lighter account position into canonical Position.\n *\n * @param position - Position entry from an account payload.\n * @param maxLeverage - Per-market max leverage (venue margin fractions).\n * @returns MetaMask Perps API position object.\n */\nexport function adaptPositionFromLighter(\n position: LighterApiPosition,\n maxLeverage: number = LIGHTER_MAX_LEVERAGE,\n): Position {\n // Venue-input integrity boundary: the REST layer type-casts JSON without\n // runtime validation, and a prefix-parsed '0.1oops' would become a\n // canonical '0.1' that TP/SL cover-sizing and close paths then SIGN.\n // The documented representation is a NONNEGATIVE magnitude with sign\n // exactly 1 or -1: a negative magnitude with sign 1 would flip the\n // canonical direction and make close/TPSL act opposite the real\n // position; sign 0/2/'1' would be silently coerced by a > 0 ternary.\n const magnitude = parseLighterStrictDecimal(position.position);\n if (magnitude === null || !Number.isFinite(magnitude) || magnitude < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} position size '${position.position}' for ${position.symbol}`,\n );\n }\n // The documented contract is sign EXACTLY 1 or -1, including for flat\n // positions (zero magnitudes are filtered downstream); anything else is\n // malformed venue data, never something to coerce.\n if (position.sign !== 1 && position.sign !== -1) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} position sign '${String(position.sign)}' for ${position.symbol}`,\n );\n }\n const size = magnitude * position.sign;\n const positionValue = parseFloat(position.positionValue);\n const marginFraction = parseFloat(position.initialMarginFraction);\n // initialMarginFraction is a percentage (e.g. \"20\" => 5x leverage).\n const leverageValue =\n marginFraction > 0 ? Math.round(100 / marginFraction) : 1;\n const marginUsed =\n marginFraction > 0 ? (positionValue * marginFraction) / 100 : positionValue;\n const unrealizedPnl = parseFloat(position.unrealizedPnl);\n const liquidationPrice = parseFloat(position.liquidationPrice);\n\n return {\n symbol: position.symbol,\n size: String(size),\n entryPrice: position.avgEntryPrice,\n positionValue: position.positionValue,\n unrealizedPnl: position.unrealizedPnl,\n marginUsed: String(marginUsed),\n leverage: {\n // Older venue captures omit marginMode and therefore retain the\n // historical cross default. Current payloads use 1 for isolated.\n type: position.marginMode === 1 ? 'isolated' : 'cross',\n value: leverageValue,\n },\n liquidationPrice:\n isNaN(liquidationPrice) || liquidationPrice === 0\n ? null\n : position.liquidationPrice,\n maxLeverage,\n returnOnEquity:\n marginUsed > 0 ? String((unrealizedPnl / marginUsed) * 100) : '0',\n cumulativeFunding: {\n allTime: '0',\n sinceOpen: '0',\n sinceChange: '0',\n },\n takeProfitCount: 0,\n stopLossCount: 0,\n providerId: 'lighter',\n };\n}\n\n// ============================================================================\n// Account Transformation\n// ============================================================================\n\n/**\n * Transform a Lighter sub-account into canonical AccountState.\n *\n * @param account - Sub-account payload from `account`/`accountsByL1Address`.\n * @returns MetaMask Perps API account state object.\n */\nexport function adaptAccountStateFromLighter(\n account: LighterSubAccount,\n): AccountState {\n const collateral = parseStrictAccountDecimal(\n account.collateral,\n 'REST collateral',\n );\n const available = parseStrictAccountDecimal(\n account.availableBalance,\n 'REST available balance',\n );\n const positions = account.positions ?? [];\n const unrealizedPnl = positions.reduce(\n (sum, position) =>\n sum +\n parseStrictAccountDecimal(\n position.unrealizedPnl,\n `REST unrealized PnL for ${position.symbol}`,\n ),\n 0,\n );\n const marginUsed = Math.max(collateral - available, 0);\n const totalBalance = collateral + unrealizedPnl;\n\n return {\n totalBalance: String(totalBalance),\n spendableBalance: String(available),\n withdrawableBalance: String(available),\n marginUsed: String(marginUsed),\n unrealizedPnl: String(unrealizedPnl),\n returnOnEquity:\n marginUsed > 0 ? String((unrealizedPnl / marginUsed) * 100) : '0',\n providerId: 'lighter',\n };\n}\n\n// ============================================================================\n// Order Transformation\n// ============================================================================\n\n/**\n * Map a Lighter order status string onto the canonical status union.\n *\n * @param status - Raw status from the Lighter API.\n * @returns Canonical order status.\n */\nexport function adaptOrderStatus(status: string): Order['status'] {\n switch (status) {\n case 'open':\n case 'pending':\n case 'in-progress':\n return 'open';\n case 'filled':\n return 'filled';\n case 'canceled':\n case 'cancelled':\n case 'canceled-post-only':\n case 'canceled-reduce-only':\n case 'canceled-position-not-allowed':\n case 'canceled-margin-not-allowed':\n case 'canceled-too-much-slippage':\n case 'canceled-not-enough-liquidity':\n case 'canceled-self-trade':\n case 'canceled-expired':\n case 'canceled-oco':\n case 'canceled-child':\n case 'canceled-liquidation':\n case 'canceled-invalid-balance':\n return 'canceled';\n default:\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} unknown order status '${status}'`,\n );\n }\n}\n\n/**\n * Transform a Lighter active order into canonical Order.\n *\n * @param order - Order entry from `GET /api/v1/accountActiveOrders`.\n * @param symbol - Market symbol for the order's `marketIndex`.\n * @returns MetaMask Perps API order object.\n */\nexport function adaptOrderFromLighter(\n order: LighterApiOrder,\n symbol: string,\n): Order {\n const original = parseFloat(order.initialBaseAmount);\n const remaining = parseFloat(order.remainingBaseAmount);\n // Canceled orders have zero remaining size even when nothing filled.\n const filled =\n order.filledBaseAmount === undefined\n ? Math.max(original - remaining, 0)\n : parseFloat(order.filledBaseAmount);\n\n const isTrigger = !['market', 'limit'].includes(order.type);\n const triggerPrice =\n order.triggerPrice !== undefined && parseFloat(order.triggerPrice) > 0\n ? order.triggerPrice\n : undefined;\n // Semantic trigger typing: without it, a TP/SL renders as a generic\n // Limit order in clients. Venue trigger orders execute market-on-trigger\n // (IOC with a protection price), the -limit variants rest at a price.\n const triggerTypeMeta: Record<\n string,\n {\n orderType: 'market' | 'limit';\n triggerOrderType: TriggerOrderType;\n detailed: string;\n }\n > = {\n 'take-profit': {\n orderType: 'market',\n triggerOrderType: 'take_profit_market',\n detailed: 'Take Profit Market',\n },\n 'stop-loss': {\n orderType: 'market',\n triggerOrderType: 'stop_market',\n detailed: 'Stop Market',\n },\n 'take-profit-limit': {\n orderType: 'limit',\n triggerOrderType: 'take_profit_limit',\n detailed: 'Take Profit Limit',\n },\n 'stop-loss-limit': {\n orderType: 'limit',\n triggerOrderType: 'stop_limit',\n detailed: 'Stop Limit',\n },\n };\n const triggerMeta = triggerTypeMeta[order.type];\n\n return {\n orderId: String(order.orderIndex),\n symbol,\n side: order.isAsk ? 'sell' : 'buy',\n orderType:\n triggerMeta?.orderType ?? (order.type === 'market' ? 'market' : 'limit'),\n ...(triggerMeta\n ? {\n triggerOrderType: triggerMeta.triggerOrderType,\n detailedOrderType: triggerMeta.detailed,\n }\n : {}),\n isTrigger,\n size: order.remainingBaseAmount,\n originalSize: order.initialBaseAmount,\n // On trigger orders `price` is the ±5% protection EXECUTION price;\n // the user-facing TP/SL level is `triggerPrice`.\n price: order.price,\n ...(triggerPrice === undefined ? {} : { triggerPrice }),\n filledSize: String(filled),\n remainingSize: order.remainingBaseAmount,\n status: adaptOrderStatus(order.status),\n // Order endpoints report seconds; preserve already-normalized millisecond\n // inputs. Trade timestamps are a separate millisecond wire contract.\n timestamp:\n order.timestamp < 1e12 ? order.timestamp * 1000 : order.timestamp,\n reduceOnly: Boolean(order.reduceOnly),\n providerId: 'lighter',\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lighterAdapter.js","sourceRoot":"","sources":["../../src/utils/lighterAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Lighter API Adapter Utilities\n *\n * Adapters transforming zkLighter REST payloads into the MetaMask Perps API\n * canonical types. Portable: no mobile-specific imports; formatters are\n * injected via the MarketDataFormatters interface.\n *\n * Key differences from HyperLiquid:\n * - Prices/sizes are human-readable decimal strings in REST responses, but\n * integers scaled by `supported_*_decimals` on the signing path.\n * - Position side is a `sign` field (1 = long, -1 = short).\n * - USDC collateral, single margin mode per account in the POC (cross).\n */\n\nimport {\n LIGHTER_DATA_INTEGRITY_PREFIX,\n LIGHTER_MAX_LEVERAGE,\n LIGHTER_UNSUPPORTED_CAPABILITY_PREFIX,\n parseLighterStrictDecimal,\n} from '../constants/lighterConfig.js';\nimport type {\n AccountState,\n MarketDataFormatters,\n MarketInfo,\n Order,\n OrderFill,\n PerpsMarketData,\n Position,\n PriceUpdate,\n TriggerOrderType,\n} from '../types/index.js';\nimport type {\n LighterApiOrder,\n LighterApiPosition,\n LighterOrderBookDetail,\n LighterOrderBookMeta,\n LighterRestTrade,\n LighterWsTrade,\n LighterSubAccount,\n LighterWsMarketStat,\n LighterWsUserStats,\n} from '../types/lighter-types.js';\n\n/**\n * Parse an account-state number at the untrusted venue boundary. Account\n * balances feed trading availability and must never accept prefix parses or\n * propagate NaN/Infinity into canonical state.\n *\n * @param value - Raw venue decimal string.\n * @param field - Field identity for the integrity error.\n * @returns A finite, fully parsed number.\n */\nfunction parseStrictAccountDecimal(value: string, field: string): number {\n const parsed = parseLighterStrictDecimal(value);\n if (parsed === null || !Number.isFinite(parsed)) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} ${field} '${String(value)}'`,\n );\n }\n return parsed;\n}\n\n/**\n * Format a price change value with sign prefix.\n *\n * @param change - The price change value to format.\n * @param formatters - Injectable formatters for platform-agnostic formatting.\n * @returns The formatted change string with sign and dollar symbol.\n */\nfunction formatChange(\n change: number,\n formatters: MarketDataFormatters,\n): string {\n if (isNaN(change) || !isFinite(change) || change === 0) {\n return '$0.00';\n }\n\n const formatted = formatters.formatPerpsFiat(Math.abs(change), {\n ranges: formatters.priceRangesUniversal,\n });\n const valueWithoutDollar = formatted.replace('$', '');\n return change > 0 ? `+$${valueWithoutDollar}` : `-$${valueWithoutDollar}`;\n}\n\n// ============================================================================\n// Market Transformation\n// ============================================================================\n\n/**\n * Transform a Lighter order book meta entry into canonical MarketInfo.\n *\n * @param market - Market metadata from `GET /api/v1/orderBooks`.\n * @param maxLeverage - Verified per-market leverage from margin metadata.\n * @returns MetaMask Perps API market info object.\n */\nexport function adaptMarketFromLighter(\n market: LighterOrderBookMeta,\n maxLeverage: number,\n): MarketInfo {\n if (!Number.isSafeInteger(maxLeverage) || maxLeverage <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} missing authoritative leverage for ${market.symbol}`,\n );\n }\n return {\n name: market.symbol,\n szDecimals: market.supportedSizeDecimals,\n priceDecimals: market.supportedPriceDecimals,\n maxLeverage,\n marginTableId: 0, // Lighter does not use margin tables\n minimumOrderSize: parseFloat(market.minQuoteAmount),\n providerId: 'lighter',\n ...(market.status === 'active' ? {} : { isDelisted: true as const }),\n };\n}\n\n/**\n * Transform a Lighter order book detail into UI-ready PerpsMarketData.\n *\n * @param detail - Market stats from `GET /api/v1/orderBookDetails`.\n * @param formatters - Injectable formatters for platform-agnostic formatting.\n * @returns MetaMask Perps API market data object.\n */\nexport function adaptMarketDataFromLighter(\n detail: LighterOrderBookDetail,\n formatters: MarketDataFormatters,\n): PerpsMarketData {\n const { minInitialMarginFraction } = detail;\n if (\n !Number.isFinite(minInitialMarginFraction) ||\n minInitialMarginFraction === undefined ||\n minInitialMarginFraction <= 0\n ) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} missing authoritative leverage for ${detail.symbol}`,\n );\n }\n const price = detail.lastTradePrice ?? 0;\n const changePercent = detail.dailyPriceChange ?? 0;\n // dailyPriceChange is a percentage; recover the absolute change.\n const changeAbs =\n changePercent === 0 ? 0 : (price * changePercent) / (100 + changePercent);\n\n const maxLeverage = Math.floor(10_000 / minInitialMarginFraction);\n if (!Number.isSafeInteger(maxLeverage) || maxLeverage <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} invalid authoritative leverage for ${detail.symbol}`,\n );\n }\n return {\n symbol: detail.symbol,\n name: detail.symbol,\n maxLeverage: `${maxLeverage}x`,\n price: formatters.formatPerpsFiat(price, {\n ranges: formatters.priceRangesUniversal,\n }),\n change24h: formatChange(changeAbs, formatters),\n change24hPercent: `${changePercent >= 0 ? '+' : ''}${changePercent.toFixed(2)}%`,\n volume: formatters.formatVolume(detail.dailyQuoteTokenVolume ?? 0),\n openInterest: formatters.formatVolume(detail.openInterest ?? 0),\n };\n}\n\n/**\n * Transform a Lighter order book detail into a canonical PriceUpdate for\n * price-stream subscribers (REST polling stands in for a WS feed in the POC).\n *\n * @param detail - Market stats from `GET /api/v1/orderBookDetails`.\n * @param timestamp - Update timestamp (injected for determinism in tests).\n * @returns MetaMask Perps API price update object.\n */\nexport function adaptPriceUpdateFromLighter(\n detail: LighterOrderBookDetail,\n timestamp: number,\n): PriceUpdate {\n return {\n symbol: detail.symbol,\n price: String(detail.lastTradePrice ?? 0),\n timestamp,\n percentChange24h: String(detail.dailyPriceChange ?? 0),\n volume24h: detail.dailyQuoteTokenVolume ?? 0,\n openInterest: detail.openInterest ?? 0,\n isTradable: detail.status === 'active',\n };\n}\n\n/**\n * Transform a `market_stats` WebSocket entry into a canonical PriceUpdate.\n * Richer than the REST fallback: carries mid/bid/ask, mark price, and funding.\n *\n * @param stat - Market stats entry from the `market_stats/all` WS channel.\n * @param timestamp - Update timestamp (injected for determinism in tests).\n * @returns MetaMask Perps API price update object.\n */\nexport function adaptPriceUpdateFromLighterWsStat(\n stat: LighterWsMarketStat,\n timestamp: number,\n): PriceUpdate {\n const bestBid = parseFloat(stat.bestBidPrice);\n const bestAsk = parseFloat(stat.bestAskPrice);\n const spread =\n Number.isFinite(bestBid) && Number.isFinite(bestAsk)\n ? String(bestAsk - bestBid)\n : undefined;\n return {\n symbol: stat.symbol,\n price: stat.midPrice,\n timestamp,\n percentChange24h: String(stat.dailyPriceChange ?? 0),\n bestBid: stat.bestBidPrice,\n bestAsk: stat.bestAskPrice,\n spread,\n markPrice: stat.markPrice,\n funding: parseFloat(stat.currentFundingRate ?? stat.fundingRate ?? '0'),\n openInterest: parseFloat(stat.openInterest ?? '0'),\n volume24h: stat.dailyQuoteTokenVolume ?? 0,\n isTradable: true,\n };\n}\n\n/**\n * Transform a `user_stats` WebSocket stats block into canonical AccountState.\n *\n * @param stats - Stats block from the `user_stats/{account_index}` channel.\n * @returns MetaMask Perps API account state object.\n */\nexport function adaptAccountStateFromLighterUserStats(\n stats: LighterWsUserStats,\n): AccountState {\n const collateral = parseStrictAccountDecimal(\n stats.collateral,\n 'WebSocket collateral',\n );\n const available = parseStrictAccountDecimal(\n stats.availableBalance,\n 'WebSocket available balance',\n );\n const portfolioValue = parseStrictAccountDecimal(\n stats.portfolioValue,\n 'WebSocket portfolio value',\n );\n return {\n totalBalance: String(portfolioValue),\n spendableBalance: String(available),\n withdrawableBalance: String(available),\n marginUsed: String(Math.max(collateral - available, 0)),\n unrealizedPnl: String(portfolioValue - collateral),\n returnOnEquity:\n collateral > 0\n ? String(((portfolioValue - collateral) / collateral) * 100)\n : '0',\n };\n}\n\n/**\n * Transform a Lighter trade (REST `/trades` or WS `account_all_trades`) into\n * a canonical OrderFill from the perspective of `accountIndex`.\n *\n * @param trade - Trade entry (post-camelization).\n * @param symbol - Market symbol resolved from the market id.\n * @param accountIndex - The account whose perspective determines the side.\n * @returns MetaMask Perps API order fill object.\n */\n/**\n * Derive the lifecycle direction of a fill from the venue's\n * position-before context, in the vocabulary client transforms consume\n * (`Open Long`, `Close Short`, `Long > Short`, ...).\n *\n * The venue reports the side's ABSOLUTE position size before the trade and\n * whether its sign changed. Combined with the trade side that is enough:\n * buying reduces shorts and opens longs; selling reduces longs and opens\n * shorts. A partial fill with no sign change is disambiguated by realized\n * pnl (closing realizes pnl, opening does not). Without position context\n * the side-only `Buy`/`Sell` vocabulary is used.\n *\n * @param context - Trade side, size, and position-before data.\n * @param context.isBuy - Whether our side bought.\n * @param context.size - Trade size (base units, absolute).\n * @param context.positionBefore - Our side's absolute position size before.\n * @param context.signChanged - Whether our side's position sign changed.\n * @param context.pnl - Realized pnl for our side, or undefined when omitted.\n * @returns Client-facing direction string.\n */\nexport function deriveLighterFillDirection(context: {\n isBuy: boolean;\n size: number;\n positionBefore: number;\n signChanged: boolean | undefined;\n pnl: number | undefined;\n}): string {\n const { isBuy, size, positionBefore, signChanged, pnl } = context;\n if (!Number.isFinite(positionBefore)) {\n return isBuy ? 'Buy' : 'Sell';\n }\n if (positionBefore === 0) {\n return isBuy ? 'Open Long' : 'Open Short';\n }\n // A flat baseline proves an open. On an existing position, nonzero\n // realized PnL proves reduction; otherwise an omitted flag is ambiguous.\n if (signChanged === undefined && (pnl === undefined || pnl === 0)) {\n return isBuy ? 'Buy' : 'Sell';\n }\n if (\n signChanged ||\n (signChanged === undefined && pnl !== undefined && pnl !== 0)\n ) {\n // Crossed past zero → flipped; landed exactly on zero → full close.\n if (size > positionBefore * 1.000001) {\n return isBuy ? 'Short > Long' : 'Long > Short';\n }\n return isBuy ? 'Close Short' : 'Close Long';\n }\n // Partial fill on an existing position: realized pnl proves it reduced.\n if (pnl !== undefined && pnl !== 0) {\n return isBuy ? 'Close Short' : 'Close Long';\n }\n // Zero or unknown pnl with no sign change is ambiguous from this\n // payload (a break-even partial close and an add both fit): fall back to\n // the side-only vocabulary instead of asserting Open without evidence.\n return isBuy ? 'Buy' : 'Sell';\n}\n\n/**\n * Parse one optional venue fee without treating malformed supplied values as\n * an omitted zero.\n *\n * @param value - Raw maker or taker fee.\n * @param tradeId - Trade identity for error context.\n * @param role - Fee role for error context.\n * @returns The finite nonnegative fee, with undefined mapped to venue-zero.\n */\nfunction parseLighterTradeFee(\n value: unknown,\n tradeId: number,\n role: 'maker' | 'taker',\n): number {\n let parsed: number | null;\n if (value === undefined) {\n parsed = 0;\n } else if (typeof value === 'number') {\n parsed = value;\n } else if (typeof value === 'string') {\n parsed = parseLighterStrictDecimal(value);\n } else {\n parsed = null;\n }\n if (parsed === null || !Number.isFinite(parsed) || parsed < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${tradeId} has invalid ${role} fee`,\n );\n }\n return parsed;\n}\n\nexport function adaptFillFromLighterTrade(\n trade: LighterRestTrade | LighterWsTrade,\n symbol: string,\n accountIndex: number,\n): OrderFill {\n const identifiers = [\n ['trade id', trade.tradeId],\n ['market id', trade.marketId],\n ['ask id', trade.askId],\n ['bid id', trade.bidId],\n ['ask account id', trade.askAccountId],\n ['bid account id', trade.bidAccountId],\n ] as const;\n for (const [field, value] of identifiers) {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${String(trade.tradeId)} has invalid ${field}`,\n );\n }\n }\n const accountIsAsk = trade.askAccountId === accountIndex;\n const accountIsBid = trade.bidAccountId === accountIndex;\n if (accountIsAsk === accountIsBid) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} account ${accountIndex} is not an unambiguous participant in trade ${trade.tradeId}`,\n );\n }\n const size = parseLighterStrictDecimal(trade.size);\n const price = parseLighterStrictDecimal(trade.price);\n if (size === null || !Number.isFinite(size) || size <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} has invalid size`,\n );\n }\n if (price === null || !Number.isFinite(price) || price <= 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} has invalid price`,\n );\n }\n if (!Number.isSafeInteger(trade.timestamp) || trade.timestamp < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} has invalid timestamp`,\n );\n }\n if (typeof trade.isMakerAsk !== 'boolean') {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} is missing maker-role context`,\n );\n }\n // Our side's role decides which fee applies; the venue includes the fee\n // fields only when nonzero (zero is the current standard-account truth).\n const accountIsMaker = accountIsAsk === trade.isMakerAsk;\n // Standard accounts (the only supported type — the provider gates\n // Premium at account resolution) pay zero fees, so zero is venue truth.\n // A PRESENT nonzero fee ON OUR SIDE contradicts that gate and its wire\n // unit is unverified: refusing loudly beats silently coercing a real fee\n // to $0. A valid nonzero counterparty fee is allowed, but malformed\n // supplied counterparty data still invalidates the venue row.\n const makerFee = parseLighterTradeFee(trade.makerFee, trade.tradeId, 'maker');\n const takerFee = parseLighterTradeFee(trade.takerFee, trade.tradeId, 'taker');\n const ourFeeNumeric = accountIsMaker ? makerFee : takerFee;\n if (ourFeeNumeric !== 0) {\n throw new Error(\n `${LIGHTER_UNSUPPORTED_CAPABILITY_PREFIX} nonzero fee in trade ${trade.tradeId}: fee unit is unverified`,\n );\n }\n const fee = '0';\n const isBuy = !accountIsAsk;\n // The account's maker/taker role selects the matching pre-trade position\n // context. Omitted sign-change flags retain an unknown direction for\n // existing positions; malformed supplied context still fails closed.\n const positionBeforeRaw = accountIsMaker\n ? trade.makerPositionSizeBefore\n : trade.takerPositionSizeBefore;\n const positionBefore = parseLighterStrictDecimal(positionBeforeRaw);\n const signChanged = accountIsMaker\n ? trade.makerPositionSignChanged\n : trade.takerPositionSignChanged;\n if (\n positionBefore === null ||\n !Number.isFinite(positionBefore) ||\n positionBefore < 0 ||\n (signChanged !== undefined && typeof signChanged !== 'boolean')\n ) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} is missing valid position context`,\n );\n }\n const pnl = accountIsAsk ? trade.askAccountPnl : trade.bidAccountPnl;\n // Omitted amounts remain unknown, including closes and flips. Position\n // context can establish direction without establishing the realized amount.\n const parsedPnl =\n pnl === undefined ? undefined : parseLighterStrictDecimal(pnl);\n if (\n parsedPnl === null ||\n (pnl !== undefined &&\n (typeof pnl !== 'string' || !Number.isFinite(parsedPnl)))\n ) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} trade ${trade.tradeId} is missing valid account pnl`,\n );\n }\n const direction = deriveLighterFillDirection({\n isBuy,\n size,\n positionBefore,\n signChanged,\n pnl: parsedPnl,\n });\n // Signed pre-trade position, derivable whenever the direction proved the\n // orientation: closing/flipping a long means it was +before, a short\n // -before; opens start from zero. Clients size flip displays from this.\n let startPosition: string | undefined;\n if (direction.startsWith('Open')) {\n startPosition = '0';\n } else if (direction === 'Close Long' || direction === 'Long > Short') {\n startPosition = String(positionBefore);\n } else if (direction === 'Close Short' || direction === 'Short > Long') {\n startPosition = String(-positionBefore);\n }\n return {\n orderId: String(accountIsAsk ? trade.askId : trade.bidId),\n // Lighter's unique execution id, validated as a safe non-negative\n // integer above. Order id alone cannot separate two fills of one order.\n fillId: String(trade.tradeId),\n symbol,\n side: accountIsAsk ? 'sell' : 'buy',\n size: trade.size,\n price: trade.price,\n // The venue reports realized pnl per side of the trade.\n ...(pnl === undefined ? {} : { pnl }),\n direction,\n ...(startPosition === undefined ? {} : { startPosition }),\n fee,\n feeToken: 'USDC',\n timestamp: trade.timestamp,\n // Lets clients apply venue-specific presentation rules (e.g. the\n // ambiguous side-only vocabulary) without guessing the source.\n providerId: 'lighter',\n };\n}\n\n// ============================================================================\n// Position Transformation\n// ============================================================================\n\n/**\n * Transform a Lighter account position into canonical Position.\n *\n * @param position - Position entry from an account payload.\n * @param maxLeverage - Per-market max leverage (venue margin fractions).\n * @returns MetaMask Perps API position object.\n */\nexport function adaptPositionFromLighter(\n position: LighterApiPosition,\n maxLeverage: number = LIGHTER_MAX_LEVERAGE,\n): Position {\n // Venue-input integrity boundary: the REST layer type-casts JSON without\n // runtime validation, and a prefix-parsed '0.1oops' would become a\n // canonical '0.1' that TP/SL cover-sizing and close paths then SIGN.\n // The documented representation is a NONNEGATIVE magnitude with sign\n // exactly 1 or -1: a negative magnitude with sign 1 would flip the\n // canonical direction and make close/TPSL act opposite the real\n // position; sign 0/2/'1' would be silently coerced by a > 0 ternary.\n const magnitude = parseLighterStrictDecimal(position.position);\n if (magnitude === null || !Number.isFinite(magnitude) || magnitude < 0) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} position size '${position.position}' for ${position.symbol}`,\n );\n }\n // The documented contract is sign EXACTLY 1 or -1, including for flat\n // positions (zero magnitudes are filtered downstream); anything else is\n // malformed venue data, never something to coerce.\n if (position.sign !== 1 && position.sign !== -1) {\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} position sign '${String(position.sign)}' for ${position.symbol}`,\n );\n }\n const size = magnitude * position.sign;\n const positionValue = parseFloat(position.positionValue);\n const marginFraction = parseFloat(position.initialMarginFraction);\n // initialMarginFraction is a percentage (e.g. \"20\" => 5x leverage).\n const leverageValue =\n marginFraction > 0 ? Math.round(100 / marginFraction) : 1;\n const marginUsed =\n marginFraction > 0 ? (positionValue * marginFraction) / 100 : positionValue;\n const unrealizedPnl = parseFloat(position.unrealizedPnl);\n const liquidationPrice = parseFloat(position.liquidationPrice);\n\n return {\n symbol: position.symbol,\n size: String(size),\n entryPrice: position.avgEntryPrice,\n positionValue: position.positionValue,\n unrealizedPnl: position.unrealizedPnl,\n marginUsed: String(marginUsed),\n leverage: {\n // Older venue captures omit marginMode and therefore retain the\n // historical cross default. Current payloads use 1 for isolated.\n type: position.marginMode === 1 ? 'isolated' : 'cross',\n value: leverageValue,\n },\n liquidationPrice:\n isNaN(liquidationPrice) || liquidationPrice === 0\n ? null\n : position.liquidationPrice,\n maxLeverage,\n // A fraction (0.1 = 10%), the unit Hyperliquid positions use.\n returnOnEquity: marginUsed > 0 ? String(unrealizedPnl / marginUsed) : '0',\n cumulativeFunding: {\n allTime: '0',\n sinceOpen: '0',\n sinceChange: '0',\n },\n takeProfitCount: 0,\n stopLossCount: 0,\n providerId: 'lighter',\n };\n}\n\n// ============================================================================\n// Account Transformation\n// ============================================================================\n\n/**\n * Transform a Lighter sub-account into canonical AccountState.\n *\n * @param account - Sub-account payload from `account`/`accountsByL1Address`.\n * @returns MetaMask Perps API account state object.\n */\nexport function adaptAccountStateFromLighter(\n account: LighterSubAccount,\n): AccountState {\n const collateral = parseStrictAccountDecimal(\n account.collateral,\n 'REST collateral',\n );\n const available = parseStrictAccountDecimal(\n account.availableBalance,\n 'REST available balance',\n );\n const positions = account.positions ?? [];\n const unrealizedPnl = positions.reduce(\n (sum, position) =>\n sum +\n parseStrictAccountDecimal(\n position.unrealizedPnl,\n `REST unrealized PnL for ${position.symbol}`,\n ),\n 0,\n );\n const marginUsed = Math.max(collateral - available, 0);\n const totalBalance = collateral + unrealizedPnl;\n\n return {\n totalBalance: String(totalBalance),\n spendableBalance: String(available),\n withdrawableBalance: String(available),\n marginUsed: String(marginUsed),\n unrealizedPnl: String(unrealizedPnl),\n returnOnEquity:\n marginUsed > 0 ? String((unrealizedPnl / marginUsed) * 100) : '0',\n providerId: 'lighter',\n };\n}\n\n// ============================================================================\n// Order Transformation\n// ============================================================================\n\n/**\n * Map a Lighter order status string onto the canonical status union.\n *\n * @param status - Raw status from the Lighter API.\n * @returns Canonical order status.\n */\nexport function adaptOrderStatus(status: string): Order['status'] {\n switch (status) {\n case 'open':\n case 'pending':\n case 'in-progress':\n return 'open';\n case 'filled':\n return 'filled';\n case 'canceled':\n case 'cancelled':\n case 'canceled-post-only':\n case 'canceled-reduce-only':\n case 'canceled-position-not-allowed':\n case 'canceled-margin-not-allowed':\n case 'canceled-too-much-slippage':\n case 'canceled-not-enough-liquidity':\n case 'canceled-self-trade':\n case 'canceled-expired':\n case 'canceled-oco':\n case 'canceled-child':\n case 'canceled-liquidation':\n case 'canceled-invalid-balance':\n return 'canceled';\n default:\n throw new Error(\n `${LIGHTER_DATA_INTEGRITY_PREFIX} unknown order status '${status}'`,\n );\n }\n}\n\n/**\n * Transform a Lighter active order into canonical Order.\n *\n * @param order - Order entry from `GET /api/v1/accountActiveOrders`.\n * @param symbol - Market symbol for the order's `marketIndex`.\n * @returns MetaMask Perps API order object.\n */\nexport function adaptOrderFromLighter(\n order: LighterApiOrder,\n symbol: string,\n): Order {\n const original = parseFloat(order.initialBaseAmount);\n const remaining = parseFloat(order.remainingBaseAmount);\n // Canceled orders have zero remaining size even when nothing filled.\n const filled =\n order.filledBaseAmount === undefined\n ? Math.max(original - remaining, 0)\n : parseFloat(order.filledBaseAmount);\n\n const isTrigger = !['market', 'limit'].includes(order.type);\n const triggerPrice =\n order.triggerPrice !== undefined && parseFloat(order.triggerPrice) > 0\n ? order.triggerPrice\n : undefined;\n // Semantic trigger typing: without it, a TP/SL renders as a generic\n // Limit order in clients. Venue trigger orders execute market-on-trigger\n // (IOC with a protection price), the -limit variants rest at a price.\n const triggerTypeMeta: Record<\n string,\n {\n orderType: 'market' | 'limit';\n triggerOrderType: TriggerOrderType;\n detailed: string;\n }\n > = {\n 'take-profit': {\n orderType: 'market',\n triggerOrderType: 'take_profit_market',\n detailed: 'Take Profit Market',\n },\n 'stop-loss': {\n orderType: 'market',\n triggerOrderType: 'stop_market',\n detailed: 'Stop Market',\n },\n 'take-profit-limit': {\n orderType: 'limit',\n triggerOrderType: 'take_profit_limit',\n detailed: 'Take Profit Limit',\n },\n 'stop-loss-limit': {\n orderType: 'limit',\n triggerOrderType: 'stop_limit',\n detailed: 'Stop Limit',\n },\n };\n const triggerMeta = triggerTypeMeta[order.type];\n\n return {\n orderId: String(order.orderIndex),\n symbol,\n side: order.isAsk ? 'sell' : 'buy',\n orderType:\n triggerMeta?.orderType ?? (order.type === 'market' ? 'market' : 'limit'),\n ...(triggerMeta\n ? {\n triggerOrderType: triggerMeta.triggerOrderType,\n detailedOrderType: triggerMeta.detailed,\n }\n : {}),\n isTrigger,\n size: order.remainingBaseAmount,\n originalSize: order.initialBaseAmount,\n // On trigger orders `price` is the ±5% protection EXECUTION price;\n // the user-facing TP/SL level is `triggerPrice`.\n price: order.price,\n ...(triggerPrice === undefined ? {} : { triggerPrice }),\n filledSize: String(filled),\n remainingSize: order.remainingBaseAmount,\n status: adaptOrderStatus(order.status),\n // Order endpoints report seconds; preserve already-normalized millisecond\n // inputs. Trade timestamps are a separate millisecond wire contract.\n timestamp:\n order.timestamp < 1e12 ? order.timestamp * 1000 : order.timestamp,\n reduceOnly: Boolean(order.reduceOnly),\n providerId: 'lighter',\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/perps-controller",
|
|
3
|
-
"version": "22.0.0-preview-
|
|
3
|
+
"version": "22.0.0-preview-060b37d94",
|
|
4
4
|
"description": "Controller for perpetual trading functionality in MetaMask",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -79,14 +79,14 @@
|
|
|
79
79
|
"@metamask/controller-utils": "^13.0.0",
|
|
80
80
|
"@metamask/messenger": "^3.0.0",
|
|
81
81
|
"@metamask/superstruct": "^3.4.1",
|
|
82
|
-
"@metamask/utils": "^12.0.
|
|
82
|
+
"@metamask/utils": "^12.0.1",
|
|
83
83
|
"@nktkas/hyperliquid": "^0.33.3",
|
|
84
84
|
"bignumber.js": "^9.1.2",
|
|
85
85
|
"reselect": "^5.3.0",
|
|
86
86
|
"uuid": "^11.1.1"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@metamask/account-tree-controller": "^11.
|
|
89
|
+
"@metamask/account-tree-controller": "^11.2.0",
|
|
90
90
|
"@metamask/authenticated-user-storage": "^4.1.0",
|
|
91
91
|
"@metamask/auto-changelog": "^6.2.1",
|
|
92
92
|
"@metamask/geolocation-controller": "^2.0.0",
|
|
@@ -94,9 +94,9 @@
|
|
|
94
94
|
"@metamask/keyring-controller": "^28.2.0",
|
|
95
95
|
"@metamask/keyring-internal-api": "^12.1.2",
|
|
96
96
|
"@metamask/network-controller": "^37.1.1",
|
|
97
|
-
"@metamask/profile-sync-controller": "^
|
|
97
|
+
"@metamask/profile-sync-controller": "^36.0.0",
|
|
98
98
|
"@metamask/remote-feature-flag-controller": "^7.0.0",
|
|
99
|
-
"@metamask/subscription-controller": "^15.
|
|
99
|
+
"@metamask/subscription-controller": "^15.1.0",
|
|
100
100
|
"@metamask/transaction-controller": "^72.2.1",
|
|
101
101
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
102
102
|
"rimraf": "^6.1.3",
|