@basedone/core 0.1.10 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/chunk-4GAKANLT.mjs +1987 -0
  2. package/dist/chunk-4UEJOM6W.mjs +1 -3
  3. package/dist/chunk-VBC6EQ7Q.mjs +235 -0
  4. package/dist/client-CgmiTuEX.d.mts +179 -0
  5. package/dist/client-CgmiTuEX.d.ts +179 -0
  6. package/dist/ecommerce.d.mts +3732 -0
  7. package/dist/ecommerce.d.ts +3732 -0
  8. package/dist/ecommerce.js +2031 -0
  9. package/dist/ecommerce.mjs +2 -0
  10. package/dist/index.d.mts +51 -43
  11. package/dist/index.d.ts +51 -43
  12. package/dist/index.js +2691 -205
  13. package/dist/index.mjs +68 -90
  14. package/dist/{meta-FVJIMALT.mjs → meta-JB5ITE27.mjs} +4 -10
  15. package/dist/meta-UOGUG3OW.mjs +3 -7
  16. package/dist/{perpDexs-GGL32HT4.mjs → perpDexs-3LRJ5ZHM.mjs} +37 -8
  17. package/dist/{perpDexs-G7V2QIM6.mjs → perpDexs-4ISLD7NX.mjs} +177 -32
  18. package/dist/react.d.mts +39 -0
  19. package/dist/react.d.ts +39 -0
  20. package/dist/react.js +268 -0
  21. package/dist/react.mjs +31 -0
  22. package/dist/{spotMeta-OD7S6HGW.mjs → spotMeta-GHXX7C5M.mjs} +24 -9
  23. package/dist/{spotMeta-PCN4Z4R3.mjs → spotMeta-IBBUP2SG.mjs} +54 -6
  24. package/dist/staticMeta-GM7T3OYL.mjs +3 -6
  25. package/dist/staticMeta-QV2KMX57.mjs +3 -6
  26. package/ecommerce.ts +15 -0
  27. package/index.ts +6 -0
  28. package/lib/ecommerce/QUICK_REFERENCE.md +211 -0
  29. package/lib/ecommerce/README.md +385 -0
  30. package/lib/ecommerce/USAGE_EXAMPLES.md +704 -0
  31. package/lib/ecommerce/client/base.ts +272 -0
  32. package/lib/ecommerce/client/customer.ts +522 -0
  33. package/lib/ecommerce/client/merchant.ts +1341 -0
  34. package/lib/ecommerce/index.ts +51 -0
  35. package/lib/ecommerce/types/entities.ts +722 -0
  36. package/lib/ecommerce/types/enums.ts +270 -0
  37. package/lib/ecommerce/types/index.ts +18 -0
  38. package/lib/ecommerce/types/requests.ts +525 -0
  39. package/lib/ecommerce/types/responses.ts +805 -0
  40. package/lib/ecommerce/utils/errors.ts +113 -0
  41. package/lib/ecommerce/utils/helpers.ts +131 -0
  42. package/lib/hip3/market-info.ts +1 -1
  43. package/lib/instrument/client.ts +351 -0
  44. package/lib/meta/data/mainnet/perpDexs.json +34 -4
  45. package/lib/meta/data/mainnet/spotMeta.json +21 -3
  46. package/lib/meta/data/testnet/meta.json +1 -3
  47. package/lib/meta/data/testnet/perpDexs.json +174 -28
  48. package/lib/meta/data/testnet/spotMeta.json +51 -0
  49. package/lib/react/InstrumentProvider.tsx +69 -0
  50. package/lib/utils/flooredDateTime.ts +55 -0
  51. package/lib/utils/time.ts +51 -0
  52. package/package.json +37 -11
  53. package/react.ts +1 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Ecommerce API Error Utilities
3
+ *
4
+ * This module contains error handling utilities for the ecommerce API.
5
+ */
6
+
7
+ /**
8
+ * Ecommerce API error class
9
+ */
10
+ export class EcommerceApiError extends Error {
11
+ /** HTTP status code */
12
+ public statusCode?: number;
13
+
14
+ /** Response data */
15
+ public data?: any;
16
+
17
+ /** Is network error */
18
+ public isNetworkError: boolean;
19
+
20
+ /** Is timeout error */
21
+ public isTimeoutError: boolean;
22
+
23
+ /** Is authentication error */
24
+ public isAuthError: boolean;
25
+
26
+ constructor(
27
+ message: string,
28
+ statusCode?: number,
29
+ data?: any,
30
+ isNetworkError = false,
31
+ isTimeoutError = false
32
+ ) {
33
+ super(message);
34
+ this.name = "EcommerceApiError";
35
+ this.statusCode = statusCode;
36
+ this.data = data;
37
+ this.isNetworkError = isNetworkError;
38
+ this.isTimeoutError = isTimeoutError;
39
+ this.isAuthError = statusCode === 401 || statusCode === 403;
40
+
41
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
42
+ if (Error.captureStackTrace) {
43
+ Error.captureStackTrace(this, EcommerceApiError);
44
+ }
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Parse error from axios error or API response
50
+ */
51
+ export function parseError(error: any): EcommerceApiError {
52
+ // Network error
53
+ if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") {
54
+ return new EcommerceApiError(
55
+ "Request timeout",
56
+ undefined,
57
+ undefined,
58
+ false,
59
+ true
60
+ );
61
+ }
62
+
63
+ if (error.code === "ERR_NETWORK" || !error.response) {
64
+ return new EcommerceApiError(
65
+ error.message || "Network error",
66
+ undefined,
67
+ undefined,
68
+ true,
69
+ false
70
+ );
71
+ }
72
+
73
+ // API error
74
+ const response = error.response;
75
+ const statusCode = response?.status;
76
+ const data = response?.data;
77
+
78
+ const message =
79
+ data?.error ||
80
+ data?.message ||
81
+ error.message ||
82
+ `API error (${statusCode})`;
83
+
84
+ return new EcommerceApiError(message, statusCode, data);
85
+ }
86
+
87
+ /**
88
+ * Check if error is retryable
89
+ */
90
+ export function isRetryableError(error: EcommerceApiError): boolean {
91
+ // Retry on network errors
92
+ if (error.isNetworkError) {
93
+ return true;
94
+ }
95
+
96
+ // Retry on timeout
97
+ if (error.isTimeoutError) {
98
+ return true;
99
+ }
100
+
101
+ // Retry on 5xx errors
102
+ if (error.statusCode && error.statusCode >= 500) {
103
+ return true;
104
+ }
105
+
106
+ // Retry on 429 (rate limit)
107
+ if (error.statusCode === 429) {
108
+ return true;
109
+ }
110
+
111
+ return false;
112
+ }
113
+
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Ecommerce API Helper Utilities
3
+ *
4
+ * This module contains helper functions for the ecommerce API.
5
+ */
6
+
7
+ /**
8
+ * Build query string from params object
9
+ */
10
+ export function buildQueryString(params: Record<string, any>): string {
11
+ const searchParams = new URLSearchParams();
12
+
13
+ Object.entries(params).forEach(([key, value]) => {
14
+ if (value !== undefined && value !== null) {
15
+ if (Array.isArray(value)) {
16
+ // Handle arrays (e.g., ids, tags)
17
+ searchParams.append(key, value.join(","));
18
+ } else {
19
+ searchParams.append(key, String(value));
20
+ }
21
+ }
22
+ });
23
+
24
+ const queryString = searchParams.toString();
25
+ return queryString ? `?${queryString}` : "";
26
+ }
27
+
28
+ /**
29
+ * Sleep for specified milliseconds
30
+ */
31
+ export function sleep(ms: number): Promise<void> {
32
+ return new Promise((resolve) => setTimeout(resolve, ms));
33
+ }
34
+
35
+ /**
36
+ * Calculate exponential backoff delay
37
+ */
38
+ export function getBackoffDelay(attempt: number, baseDelay = 1000): number {
39
+ return Math.min(baseDelay * Math.pow(2, attempt), 30000);
40
+ }
41
+
42
+ /**
43
+ * Retry function with exponential backoff
44
+ */
45
+ export async function retryWithBackoff<T>(
46
+ fn: () => Promise<T>,
47
+ maxRetries = 3,
48
+ baseDelay = 1000,
49
+ shouldRetry?: (error: any) => boolean
50
+ ): Promise<T> {
51
+ let lastError: any;
52
+
53
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
54
+ try {
55
+ return await fn();
56
+ } catch (error) {
57
+ lastError = error;
58
+
59
+ // Check if we should retry
60
+ if (attempt < maxRetries && (!shouldRetry || shouldRetry(error))) {
61
+ const delay = getBackoffDelay(attempt, baseDelay);
62
+ await sleep(delay);
63
+ continue;
64
+ }
65
+
66
+ throw error;
67
+ }
68
+ }
69
+
70
+ throw lastError;
71
+ }
72
+
73
+ /**
74
+ * Format price for display
75
+ */
76
+ export function formatPrice(price: string | number, decimals = 2): string {
77
+ const num = typeof price === "string" ? parseFloat(price) : price;
78
+ return num.toFixed(decimals);
79
+ }
80
+
81
+ /**
82
+ * Validate email address
83
+ */
84
+ export function isValidEmail(email: string): boolean {
85
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
86
+ return emailRegex.test(email);
87
+ }
88
+
89
+ /**
90
+ * Validate Ethereum address
91
+ */
92
+ export function isValidAddress(address: string): boolean {
93
+ return /^0x[a-fA-F0-9]{40}$/.test(address);
94
+ }
95
+
96
+ /**
97
+ * Truncate address for display
98
+ */
99
+ export function truncateAddress(address: string, start = 6, end = 4): string {
100
+ if (!address || address.length < start + end) {
101
+ return address;
102
+ }
103
+ return `${address.slice(0, start)}...${address.slice(-end)}`;
104
+ }
105
+
106
+ /**
107
+ * Calculate discount amount
108
+ */
109
+ export function calculateDiscountAmount(
110
+ price: number,
111
+ discountType: "PERCENTAGE" | "FIXED_AMOUNT",
112
+ discountValue: number
113
+ ): number {
114
+ if (discountType === "PERCENTAGE") {
115
+ return (price * discountValue) / 100;
116
+ }
117
+ return Math.min(discountValue, price);
118
+ }
119
+
120
+ /**
121
+ * Calculate final price after discount
122
+ */
123
+ export function calculateFinalPrice(
124
+ price: number,
125
+ discountType: "PERCENTAGE" | "FIXED_AMOUNT",
126
+ discountValue: number
127
+ ): number {
128
+ const discountAmount = calculateDiscountAmount(price, discountType, discountValue);
129
+ return Math.max(0, price - discountAmount);
130
+ }
131
+
@@ -29,7 +29,7 @@ export interface PerpsUniverse {
29
29
  /** Indicates if the universe is delisted. */
30
30
  isDelisted?: true;
31
31
  /** Indicates if the universe is in growth mode, eligible for discounted fees */
32
- growthMode?: true;
32
+ growthMode?: "enabled";
33
33
  /** Margin mode for the universe. */
34
34
  marginMode?: "strictIsolated" | "noCross";
35
35
  }
@@ -0,0 +1,351 @@
1
+ import { SpotMeta, SpotToken } from "@nktkas/hyperliquid";
2
+ import { AllPerpsMeta, PerpsMeta } from "../hip3/market-info";
3
+
4
+ export interface BaseInstrument {
5
+ assetId: number;
6
+ symbol: string; // Display name (e.g., "BTC/USDC" for spot, "BTC" for perps)
7
+ coin: string; // Internal name used by Hyperliquid API (e.g., "@107" for spot, "BTC" for perps)
8
+ szDecimals: number; // Size decimals for formatting
9
+ type: "spot" | "futures";
10
+ isDelisted?: boolean;
11
+ }
12
+
13
+ // Futures-specific types (metadata only - no asset context data)
14
+ export interface PerpsInstrument extends BaseInstrument {
15
+ type: "futures";
16
+ leverage: number;
17
+ collateralTokenSymbol: string;
18
+ dex?: string; // HIP3 dex name (e.g., "xyz" for "xyz:MSTR")
19
+ collateralTokenIndex?: number;
20
+ }
21
+
22
+ // Spot-specific types (metadata only - no asset context data)
23
+ export interface SpotInstrument extends BaseInstrument {
24
+ type: "spot";
25
+ baseToken: SpotToken;
26
+ quoteToken: SpotToken;
27
+ }
28
+
29
+ export type MarketInstrument = PerpsInstrument | SpotInstrument;
30
+
31
+ /**
32
+ * Asset ID calculation utilities
33
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/asset-ids
34
+ */
35
+ export const AssetIdUtils = {
36
+ /**
37
+ * Calculate perp asset ID
38
+ * - Root dex: assetIndex (0, 1, 2, ...)
39
+ * - HIP3 dex: 100000 + dexIndex * 10000 + assetIndex
40
+ */
41
+ calcPerpAssetId(dexIndex: number, assetIndex: number): number {
42
+ if (dexIndex === 0) return assetIndex;
43
+ return 100000 + dexIndex * 10000 + assetIndex;
44
+ },
45
+
46
+ /**
47
+ * Calculate spot asset ID: 10000 + pairIndex
48
+ */
49
+ calcSpotAssetId(pairIndex: number): number {
50
+ return 10000 + pairIndex;
51
+ },
52
+
53
+ /**
54
+ * Check if symbol is HIP3 format (contains ":")
55
+ */
56
+ isHip3Symbol(symbol: string): boolean {
57
+ return symbol?.includes(":") ?? false;
58
+ },
59
+
60
+ /**
61
+ * Extract dex name from HIP3 symbol (e.g., "xyz:MSTR" -> "xyz")
62
+ */
63
+ extractDexName(symbol: string): string | undefined {
64
+ if (!this.isHip3Symbol(symbol)) return undefined;
65
+ return symbol.split(":")[0];
66
+ },
67
+ };
68
+
69
+ /**
70
+ * Hyperliquid Instrument Client
71
+ *
72
+ * Processes spotMeta and allPerpsMeta into a unified instrument registry
73
+ * with O(1) lookups by symbol, coin, or assetId.
74
+ *
75
+ * Usage:
76
+ * ```ts
77
+ * const client = new InstrumentClient(spotMeta, allPerpsMeta).init();
78
+ * const btc = client.getInstrument("BTC");
79
+ * const spot = client.getInstrumentByAssetId(10001);
80
+ * ```
81
+ */
82
+ export class InstrumentClient {
83
+ private instruments: MarketInstrument[] = [];
84
+
85
+ // O(1) lookup maps for efficient retrieval
86
+ private instrumentsBySymbol = new Map<string, MarketInstrument>();
87
+ private instrumentsByCoin = new Map<string, MarketInstrument>();
88
+ private instrumentsByAssetId = new Map<number, MarketInstrument>();
89
+
90
+ // Additional spot lookups (base token -> instrument)
91
+ private spotByBaseToken = new Map<string, SpotInstrument>();
92
+
93
+ // Dex metadata map (dex name -> PerpsMeta)
94
+ // Key: "" for root dex, dex name for HIP3 (e.g., "xyz")
95
+ private dexMetaMap = new Map<string, PerpsMeta>();
96
+
97
+ // Token index lookup for spot
98
+ private spotTokensByIndex = new Map<number, SpotToken>();
99
+
100
+ constructor(
101
+ public spotMeta: SpotMeta,
102
+ public allPerpsMeta: AllPerpsMeta,
103
+ ) {}
104
+
105
+ /**
106
+ * Initialize the client by processing meta into instruments.
107
+ * Call this after construction to populate the instrument registry.
108
+ * @returns this for chaining
109
+ */
110
+ init(): this {
111
+ if (!this.spotMeta || !this.allPerpsMeta) {
112
+ throw new Error("SpotMeta and allPerpsMeta are required");
113
+ }
114
+ // Pre-index spot tokens for O(1) lookup
115
+ this.indexSpotTokens();
116
+
117
+ // Process instruments
118
+ this.processPerpsInstruments();
119
+ this.processSpotInstruments();
120
+
121
+ return this;
122
+ }
123
+
124
+ // ===== Perps Meta Accessors =====
125
+
126
+ getAllPerpsMeta(): AllPerpsMeta {
127
+ return this.allPerpsMeta;
128
+ }
129
+
130
+ /**
131
+ * Get PerpsMeta for a specific dex
132
+ * @param dex - Dex name ("" for root dex, or HIP3 dex name)
133
+ */
134
+ getPerpDex(dex: string): PerpsMeta | undefined {
135
+ return this.dexMetaMap.get(dex);
136
+ }
137
+
138
+ /**
139
+ * Get PerpsMeta by dex index in allPerpsMeta array
140
+ */
141
+ getPerpDexByIndex(index: number): PerpsMeta | undefined {
142
+ return this.allPerpsMeta[index];
143
+ }
144
+
145
+ // ===== Instrument Accessors =====
146
+
147
+ /**
148
+ * Get all instruments
149
+ */
150
+ getAllInstruments(): MarketInstrument[] {
151
+ return this.instruments;
152
+ }
153
+
154
+ /**
155
+ * Get all perps instruments
156
+ */
157
+ getPerpsInstruments(): PerpsInstrument[] {
158
+ return this.instruments.filter(
159
+ (i): i is PerpsInstrument => i.type === "futures",
160
+ );
161
+ }
162
+
163
+ getHip3Instruments(): PerpsInstrument[] {
164
+ return this.instruments.filter(
165
+ (i): i is PerpsInstrument => i.type === "futures" && !!i.dex,
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Get all spot instruments
171
+ */
172
+ getSpotInstruments(): SpotInstrument[] {
173
+ return this.instruments.filter(
174
+ (i): i is SpotInstrument => i.type === "spot",
175
+ );
176
+ }
177
+
178
+ /**
179
+ * Get instrument by symbol or coin (tries both)
180
+ * @param coinOrSymbol - Symbol (e.g., "BTC", "BTC/USDC") or coin (e.g., "@107")
181
+ */
182
+ getInstrument(coinOrSymbol: string): MarketInstrument | undefined {
183
+ return (
184
+ this.instrumentsByCoin.get(coinOrSymbol) ??
185
+ this.instrumentsBySymbol.get(coinOrSymbol)
186
+ );
187
+ }
188
+
189
+ /**
190
+ * Get instrument by display symbol
191
+ * @param symbol - Display symbol (e.g., "BTC", "BTC/USDC", "xyz:MSTR")
192
+ */
193
+ getInstrumentBySymbol(symbol: string): MarketInstrument | undefined {
194
+ return this.instrumentsBySymbol.get(symbol);
195
+ }
196
+
197
+ /**
198
+ * Get instrument by Hyperliquid API coin format
199
+ * @param coin - API coin name (e.g., "BTC", "@107", "xyz:MSTR")
200
+ */
201
+ getInstrumentByCoin(coin: string): MarketInstrument | undefined {
202
+ return this.instrumentsByCoin.get(coin);
203
+ }
204
+
205
+ /**
206
+ * Get instrument by asset ID
207
+ * @param assetId - Numeric asset ID (e.g., 1 for perps, 10001 for spot)
208
+ */
209
+ getInstrumentByAssetId(assetId: number): MarketInstrument | undefined {
210
+ return this.instrumentsByAssetId.get(assetId);
211
+ }
212
+
213
+ /**
214
+ * Get spot instrument by base token symbol
215
+ * @param baseSymbol - Base token symbol (e.g., "HYPE" to find "HYPE/USDC")
216
+ */
217
+ getSpotInstrumentByBaseToken(baseSymbol: string): SpotInstrument | undefined {
218
+ return this.spotByBaseToken.get(baseSymbol);
219
+ }
220
+
221
+ /** Search instruments by symbol, coin, or assetId */
222
+ searchInstruments(
223
+ query: string,
224
+ type?: "spot" | "futures",
225
+ ): MarketInstrument[] {
226
+ return this.instruments.filter((i) => {
227
+ if (type && i.type !== type) return false;
228
+ return (
229
+ i.symbol.toLowerCase().includes(query.toLowerCase()) ||
230
+ i.coin.toLowerCase().includes(query.toLowerCase())
231
+ );
232
+ });
233
+ }
234
+
235
+ /**
236
+ * Get spot token by index
237
+ */
238
+ getSpotToken(index: number): SpotToken | undefined {
239
+ return this.spotTokensByIndex.get(index);
240
+ }
241
+
242
+ // ===== Internal Processing =====
243
+
244
+ private indexSpotTokens(): void {
245
+ for (const token of this.spotMeta.tokens) {
246
+ this.spotTokensByIndex.set(token.index, token);
247
+ }
248
+ }
249
+
250
+ private processPerpsInstruments(): void {
251
+ for (let dexIndex = 0; dexIndex < this.allPerpsMeta.length; dexIndex++) {
252
+ const perpMeta = this.allPerpsMeta[dexIndex];
253
+ const dexName = this.extractDexNameFromMeta(perpMeta, dexIndex);
254
+
255
+ // Store dex meta for later lookup
256
+ this.dexMetaMap.set(dexName, perpMeta);
257
+
258
+ // Get collateral token symbol for this dex
259
+ const collateralToken = this.spotTokensByIndex.get(
260
+ perpMeta.collateralToken,
261
+ );
262
+ const collateralTokenSymbol = collateralToken?.name ?? "USDC";
263
+
264
+ for (
265
+ let assetIndex = 0;
266
+ assetIndex < perpMeta.universe.length;
267
+ assetIndex++
268
+ ) {
269
+ const info = perpMeta.universe[assetIndex];
270
+ const assetId = AssetIdUtils.calcPerpAssetId(dexIndex, assetIndex);
271
+
272
+ const instrument: PerpsInstrument = {
273
+ assetId,
274
+ symbol: info.name,
275
+ coin: info.name,
276
+ szDecimals: info.szDecimals,
277
+ leverage: info.maxLeverage,
278
+ collateralTokenSymbol,
279
+ type: "futures",
280
+ isDelisted: info.isDelisted,
281
+ dex: AssetIdUtils.extractDexName(info.name),
282
+ collateralTokenIndex: perpMeta.collateralToken,
283
+ };
284
+
285
+ this.addInstrument(instrument);
286
+ }
287
+ }
288
+ }
289
+
290
+ private processSpotInstruments(): void {
291
+ const seenSymbols = new Set<string>();
292
+
293
+ for (const pair of this.spotMeta.universe) {
294
+ const [baseTokenIndex, quoteTokenIndex] = pair.tokens;
295
+
296
+ // O(1) token lookup using pre-indexed map
297
+ const baseToken = this.spotTokensByIndex.get(baseTokenIndex);
298
+ const quoteToken = this.spotTokensByIndex.get(quoteTokenIndex);
299
+
300
+ if (!baseToken || !quoteToken) continue;
301
+
302
+ const symbol = `${baseToken.name}/${quoteToken.name}`;
303
+
304
+ // Skip duplicate display symbols
305
+ if (seenSymbols.has(symbol)) continue;
306
+ seenSymbols.add(symbol);
307
+
308
+ const assetId = AssetIdUtils.calcSpotAssetId(pair.index);
309
+
310
+ const instrument: SpotInstrument = {
311
+ assetId,
312
+ symbol,
313
+ coin: pair.name, // e.g., "@107"
314
+ szDecimals: baseToken.szDecimals,
315
+ type: "spot",
316
+ baseToken,
317
+ quoteToken,
318
+ };
319
+
320
+ this.addInstrument(instrument);
321
+
322
+ // Index by base token for convenience lookups (first occurrence wins)
323
+ if (!this.spotByBaseToken.has(baseToken.name)) {
324
+ this.spotByBaseToken.set(baseToken.name, instrument);
325
+ }
326
+ }
327
+ }
328
+
329
+ private addInstrument(instrument: MarketInstrument): void {
330
+ this.instruments.push(instrument);
331
+ this.instrumentsBySymbol.set(instrument.symbol, instrument);
332
+ this.instrumentsByCoin.set(instrument.coin, instrument);
333
+ this.instrumentsByAssetId.set(instrument.assetId, instrument);
334
+ }
335
+
336
+ /**
337
+ * Extract dex name from PerpsMeta
338
+ * Root dex (index 0) returns "", HIP3 dexes return the dex name (e.g., "xyz")
339
+ */
340
+ private extractDexNameFromMeta(
341
+ perpMeta: PerpsMeta,
342
+ dexIndex: number,
343
+ ): string {
344
+ if (dexIndex === 0) return ""; // Root dex
345
+
346
+ const firstAsset = perpMeta.universe[0];
347
+ if (!firstAsset) return "";
348
+
349
+ return AssetIdUtils.extractDexName(firstAsset.name) ?? "";
350
+ }
351
+ }
@@ -73,7 +73,8 @@
73
73
  ]
74
74
  ],
75
75
  "deployerFeeScale": "1.0",
76
- "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00"
76
+ "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00",
77
+ "assetToFundingMultiplier": []
77
78
  },
78
79
  {
79
80
  "name": "flx",
@@ -167,7 +168,21 @@
167
168
  ]
168
169
  ],
169
170
  "deployerFeeScale": "1.0",
170
- "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00"
171
+ "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00",
172
+ "assetToFundingMultiplier": [
173
+ [
174
+ "flx:COIN",
175
+ "0.0396816138"
176
+ ],
177
+ [
178
+ "flx:CRCL",
179
+ "0.6849327969"
180
+ ],
181
+ [
182
+ "flx:TSLA",
183
+ "0.055534957"
184
+ ]
185
+ ]
171
186
  },
172
187
  {
173
188
  "name": "vntl",
@@ -217,7 +232,21 @@
217
232
  ]
218
233
  ],
219
234
  "deployerFeeScale": "1.0",
220
- "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00"
235
+ "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00",
236
+ "assetToFundingMultiplier": [
237
+ [
238
+ "vntl:ANTHROPIC",
239
+ "0.0053054031"
240
+ ],
241
+ [
242
+ "vntl:OPENAI",
243
+ "0.0050794237"
244
+ ],
245
+ [
246
+ "vntl:SPACEX",
247
+ "0.010663783"
248
+ ]
249
+ ]
221
250
  },
222
251
  {
223
252
  "name": "hyna",
@@ -248,6 +277,7 @@
248
277
  ]
249
278
  ],
250
279
  "deployerFeeScale": "1.0",
251
- "lastDeployerFeeScaleChangeTime": "2025-12-03T10:32:09.252520621"
280
+ "lastDeployerFeeScaleChangeTime": "2025-12-03T10:32:09.252520621",
281
+ "assetToFundingMultiplier": []
252
282
  }
253
283
  ]