@basedone/core 0.0.1 → 0.0.7

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 (52) hide show
  1. package/dist/chunk-4UEJOM6W.mjs +9 -0
  2. package/dist/index.d.mts +488 -0
  3. package/dist/index.d.ts +488 -2
  4. package/dist/index.js +37574 -2
  5. package/dist/index.mjs +1097 -0
  6. package/dist/lib/cloid.d.ts.map +1 -1
  7. package/dist/lib/cloid.js +11 -1
  8. package/dist/lib/cloid.js.map +1 -1
  9. package/dist/meta-52Q5UUQ4.mjs +1474 -0
  10. package/dist/meta-FTWJX4LV.mjs +1445 -0
  11. package/dist/meta-IKWYLG3Q.mjs +1316 -0
  12. package/dist/meta-UUXKK7IB.mjs +1355 -0
  13. package/dist/perpDexs-PSE3LEVV.mjs +9 -0
  14. package/dist/perpDexs-S3TK25EU.mjs +17 -0
  15. package/dist/perpDexs-TZIQ57IW.mjs +537 -0
  16. package/dist/perpDexs-YNEAJ3R5.mjs +7 -0
  17. package/dist/perpDexs-YS3QQSHW.mjs +338 -0
  18. package/dist/spotMeta-7IJT3W6H.mjs +6442 -0
  19. package/dist/spotMeta-LEO5QFNS.mjs +26392 -0
  20. package/dist/spotMeta-MC5UYLQ7.mjs +6335 -0
  21. package/dist/spotMeta-TXJWYTKI.mjs +26403 -0
  22. package/dist/spotMeta-VAANYV77.mjs +6346 -0
  23. package/dist/spotMeta-ZVBZNUUE.mjs +26559 -0
  24. package/dist/staticMeta-HRXST42O.mjs +24 -0
  25. package/dist/staticMeta-QWPQK3MD.mjs +22 -0
  26. package/index.ts +6 -0
  27. package/lib/cloid/README.md +233 -0
  28. package/lib/cloid/cloid.ts +368 -0
  29. package/lib/cloid/encoder.ts +60 -0
  30. package/lib/constants/fee.ts +2 -0
  31. package/lib/constants/tokens.ts +28 -0
  32. package/lib/fee.ts +105 -0
  33. package/lib/hip3/market-info.ts +25 -0
  34. package/lib/hip3/utils.ts +9 -0
  35. package/lib/meta/README.md +471 -0
  36. package/lib/meta/data/mainnet/dexs/xyz.json +26 -0
  37. package/lib/meta/data/mainnet/meta.json +1462 -0
  38. package/lib/meta/data/mainnet/perpDexs.json +11 -0
  39. package/lib/meta/data/mainnet/spotMeta.json +6432 -0
  40. package/lib/meta/data/mainnet/staticMeta.json +14 -0
  41. package/lib/meta/data/testnet/dexs/rrrrr.json +33 -0
  42. package/lib/meta/data/testnet/meta.json +1343 -0
  43. package/lib/meta/data/testnet/perpDexs.json +531 -0
  44. package/lib/meta/data/testnet/spotMeta.json +26547 -0
  45. package/lib/meta/data/testnet/staticMeta.json +12 -0
  46. package/lib/meta/metadata.ts +717 -0
  47. package/lib/pup/calculator.ts +221 -0
  48. package/lib/pup/index.ts +9 -0
  49. package/lib/pup/types.ts +94 -0
  50. package/lib/utils/formatter.ts +97 -0
  51. package/package.json +21 -17
  52. package/readme.md +0 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,1097 @@
1
+ import {
2
+ __glob
3
+ } from "./chunk-4UEJOM6W.mjs";
4
+
5
+ // lib/cloid/encoder.ts
6
+ var mask = (bits) => (1n << bits) - 1n;
7
+ function getEncodingLength(nbits, alphabet) {
8
+ return Math.floor(Number(nbits) / Math.log2(Number(alphabet.length)));
9
+ }
10
+ function encodeValue(value, nbits, alphabet) {
11
+ const encodingLength = getEncodingLength(nbits, alphabet);
12
+ if (value.length > encodingLength) {
13
+ value = value.slice(0, encodingLength);
14
+ }
15
+ if (value.length < encodingLength) {
16
+ value = value.padEnd(encodingLength, alphabet[alphabet.length - 1]);
17
+ }
18
+ const base = BigInt(alphabet.length);
19
+ let encoded = 0n;
20
+ for (const ch of value) {
21
+ const idx = alphabet.indexOf(ch);
22
+ if (idx === -1) throw new Error(`Invalid slug character: ${ch}`);
23
+ encoded = encoded * base + BigInt(idx);
24
+ }
25
+ if (encoded > Number(mask(nbits))) {
26
+ throw new Error(`Encoded value exceeds ${nbits} bits`);
27
+ }
28
+ return encoded;
29
+ }
30
+ function decodeValue(value, nbits, alphabet) {
31
+ if (value < 0 || value > Number(mask(nbits))) {
32
+ throw new Error(`Slug value out of range (must fit in ${nbits} bits)`);
33
+ }
34
+ const base = BigInt(alphabet.length);
35
+ let decoded = "";
36
+ for (let i = 0; i < getEncodingLength(nbits, alphabet); i++) {
37
+ const idx = value % base;
38
+ decoded = alphabet[Number(idx)] + decoded;
39
+ value = value / base;
40
+ }
41
+ return decoded.trim();
42
+ }
43
+
44
+ // lib/cloid/cloid.ts
45
+ var LEGACY_CLOID = "0x62baee7262baee7262baee7262baee72";
46
+ var BASED_VERSION = 1;
47
+ var DEFAULT_TENANT_CODE = "BASED";
48
+ var DEFAULT_OID = 0xba5ed10000ba5ed1n;
49
+ var BASED_HEX_PREFIX = 12213969;
50
+ var BASED_HEX_PREFIX_STR = "0xba5ed1";
51
+ var PREFIX_BITS = 24n;
52
+ var VERSION_BITS = 4n;
53
+ var SLUG_BITS = 26n;
54
+ var CLIENT_BITS = 5n;
55
+ var IS_MINI_APP_BITS = 1n;
56
+ var MINI_APP_TRIGGERED_BITS = 1n;
57
+ var WIDGET_TYPE_BITS = 3n;
58
+ var OID_BITS = 64n;
59
+ var TOTAL_BITS = 128n;
60
+ var SLUG_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
61
+ var OID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789|_- ";
62
+ var mask2 = (bits) => (1n << bits) - 1n;
63
+ function encodeSlug(slug) {
64
+ if (!slug) slug = DEFAULT_TENANT_CODE;
65
+ return encodeValue(slug, SLUG_BITS, SLUG_ALPHABET);
66
+ }
67
+ function decodeSlug(value) {
68
+ return decodeValue(value, SLUG_BITS, SLUG_ALPHABET);
69
+ }
70
+ function buildCloid(version, slug, clientId, oid, options) {
71
+ if (version > 15) version = BASED_VERSION;
72
+ if (clientId > Number(mask2(CLIENT_BITS))) {
73
+ clientId = CloidClientCode.Unset;
74
+ }
75
+ const isMiniApp = options?.isMiniApp ? 1 : 0;
76
+ const miniAppTriggered = options?.miniAppTriggered ? 1 : 0;
77
+ const widgetType = typeof options?.widgetType === "number" ? options.widgetType : WidgetType[options?.widgetType ?? "Unset"];
78
+ if (widgetType > Number(mask2(WIDGET_TYPE_BITS))) {
79
+ throw new Error(
80
+ `Component ID ${widgetType} exceeds maximum value ${Number(mask2(WIDGET_TYPE_BITS))}`
81
+ );
82
+ }
83
+ let oidBigInt;
84
+ if (typeof oid === "string") {
85
+ if (oid.startsWith("0x") || !isNaN(Number(oid))) {
86
+ oidBigInt = BigInt(oid);
87
+ } else {
88
+ oidBigInt = encodeValue(oid.toLowerCase(), OID_BITS, OID_ALPHABET);
89
+ }
90
+ } else {
91
+ oidBigInt = oid;
92
+ }
93
+ if (oidBigInt > mask2(OID_BITS)) {
94
+ oidBigInt = DEFAULT_OID;
95
+ }
96
+ const slugVal = encodeSlug(slug.toUpperCase());
97
+ let cloid = BigInt(BASED_HEX_PREFIX) << TOTAL_BITS - PREFIX_BITS;
98
+ cloid |= BigInt(version & 15) << TOTAL_BITS - PREFIX_BITS - VERSION_BITS;
99
+ cloid |= BigInt(slugVal) << TOTAL_BITS - PREFIX_BITS - VERSION_BITS - SLUG_BITS;
100
+ cloid |= BigInt(clientId) << OID_BITS;
101
+ cloid |= BigInt(isMiniApp) << OID_BITS + CLIENT_BITS;
102
+ cloid |= BigInt(miniAppTriggered) << OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS;
103
+ cloid |= BigInt(widgetType) << OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS + MINI_APP_TRIGGERED_BITS;
104
+ cloid |= oidBigInt & mask2(OID_BITS);
105
+ return `0x${cloid.toString(16)}`;
106
+ }
107
+ function parseCloid(cloidHex) {
108
+ if (cloidHex === LEGACY_CLOID) {
109
+ return {
110
+ prefix: LEGACY_CLOID,
111
+ version: 0,
112
+ slug: "BASED",
113
+ clientId: CloidClientCode.Unset,
114
+ isMiniApp: false,
115
+ miniAppTriggered: false,
116
+ widgetTypeId: WidgetType.Unset,
117
+ oid: 0xba5ed10000ba5ed1n,
118
+ decodedOid: decodeValue(0xba5ed10000ba5ed1n, OID_BITS, OID_ALPHABET),
119
+ clientName: "Unset",
120
+ widgetTypeName: "Unset"
121
+ };
122
+ }
123
+ try {
124
+ const cloid = BigInt(cloidHex);
125
+ const prefix = Number(cloid >> TOTAL_BITS - PREFIX_BITS);
126
+ const version = Number(
127
+ cloid >> TOTAL_BITS - PREFIX_BITS - VERSION_BITS & mask2(VERSION_BITS)
128
+ );
129
+ const slugVal = Number(
130
+ cloid >> OID_BITS + WIDGET_TYPE_BITS + MINI_APP_TRIGGERED_BITS + IS_MINI_APP_BITS + CLIENT_BITS & mask2(SLUG_BITS)
131
+ );
132
+ const clientId = Number(cloid >> OID_BITS & mask2(CLIENT_BITS));
133
+ const isMiniApp = Number(cloid >> OID_BITS + CLIENT_BITS & mask2(IS_MINI_APP_BITS)) === 1;
134
+ const miniAppTriggered = Number(
135
+ cloid >> OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS & mask2(MINI_APP_TRIGGERED_BITS)
136
+ ) === 1;
137
+ const widgetType = Number(
138
+ cloid >> OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS + MINI_APP_TRIGGERED_BITS & mask2(WIDGET_TYPE_BITS)
139
+ );
140
+ const oid = cloid & mask2(OID_BITS);
141
+ return {
142
+ prefix: `0x${prefix.toString(16)}`,
143
+ // should equal 0xBA5ED1
144
+ version,
145
+ slug: decodeSlug(BigInt(slugVal)),
146
+ clientId,
147
+ isMiniApp,
148
+ miniAppTriggered,
149
+ widgetTypeId: widgetType,
150
+ oid,
151
+ decodedOid: decodeValue(oid, OID_BITS, OID_ALPHABET),
152
+ clientName: getClientCodeNameById(clientId),
153
+ widgetTypeName: getWidgetTypeById(widgetType)
154
+ };
155
+ } catch (error) {
156
+ console.error("Invalid cloid", { cloidHex });
157
+ return null;
158
+ }
159
+ }
160
+ function isBasedCloid(cloidHex) {
161
+ if (!cloidHex) return false;
162
+ if (cloidHex === LEGACY_CLOID) return true;
163
+ return cloidHex.toLowerCase().startsWith(BASED_HEX_PREFIX_STR);
164
+ }
165
+ function isTenantCloid(tenantTrackingSlug, cloidHex) {
166
+ if (!cloidHex || !isBasedCloid(cloidHex)) return false;
167
+ const cloidData = parseCloid(cloidHex);
168
+ if (!cloidData) return false;
169
+ const { slug } = cloidData;
170
+ if (tenantTrackingSlug.length > 5) {
171
+ tenantTrackingSlug = tenantTrackingSlug.slice(0, 5);
172
+ }
173
+ const normalisedSlug = decodeSlug(encodeSlug(tenantTrackingSlug));
174
+ return slug === normalisedSlug;
175
+ }
176
+ function isTrackingIdCloid(trackingId, cloidHex) {
177
+ if (!cloidHex || !isBasedCloid(cloidHex)) return false;
178
+ const cloidData = parseCloid(cloidHex);
179
+ if (!cloidData) return false;
180
+ if (typeof trackingId === "string") {
181
+ const encodedTrackingId = normaliseTrackingId(trackingId);
182
+ return encodedTrackingId === cloidData.decodedOid;
183
+ } else {
184
+ const { oid } = cloidData;
185
+ return oid === trackingId;
186
+ }
187
+ }
188
+ function normaliseSlug(slug) {
189
+ if (!slug) return "";
190
+ return decodeSlug(encodeSlug(slug.toUpperCase()));
191
+ }
192
+ function normaliseTrackingId(trackingId) {
193
+ if (!trackingId) return "";
194
+ return decodeValue(
195
+ encodeValue(trackingId.toLowerCase(), OID_BITS, OID_ALPHABET),
196
+ OID_BITS,
197
+ OID_ALPHABET
198
+ );
199
+ }
200
+ var CloidClientCode = {
201
+ Unset: 0,
202
+ // 0x00
203
+ Web: 1,
204
+ App: 2,
205
+ TgBot: 3,
206
+ TSL: 4,
207
+ // Trailing Stop Loss
208
+ Grid: 5,
209
+ Chase: 6,
210
+ Desktop: 7,
211
+ API: 8
212
+ };
213
+ var CloidClientCodeNameById = {
214
+ [CloidClientCode.Unset]: "Unset",
215
+ [CloidClientCode.Web]: "Web",
216
+ [CloidClientCode.App]: "App",
217
+ [CloidClientCode.TgBot]: "TgBot",
218
+ [CloidClientCode.TSL]: "TSL",
219
+ [CloidClientCode.Grid]: "Grid",
220
+ [CloidClientCode.Chase]: "Chase",
221
+ [CloidClientCode.Desktop]: "Desktop",
222
+ [CloidClientCode.API]: "API"
223
+ };
224
+ function getClientCodeNameById(id) {
225
+ return CloidClientCodeNameById[id] ?? `client_${id}`;
226
+ }
227
+ var WidgetType = {
228
+ Unset: 0,
229
+ // 0x00
230
+ SidePanel: 1,
231
+ Widget: 2,
232
+ FloatingWidget: 3
233
+ };
234
+ var WidgetTypeById = {
235
+ [WidgetType.Unset]: "Unset",
236
+ [WidgetType.SidePanel]: "SidePanel",
237
+ [WidgetType.Widget]: "Widget",
238
+ [WidgetType.FloatingWidget]: "FloatingWidget"
239
+ };
240
+ function getWidgetTypeById(id) {
241
+ return WidgetTypeById[id] ?? `widget_${id}`;
242
+ }
243
+ function getCloid(tenantCode, clientCode, oid, attribution) {
244
+ try {
245
+ const clientIdx = typeof clientCode === "number" ? clientCode : CloidClientCode[clientCode ?? "Unset"];
246
+ return buildCloid(
247
+ BASED_VERSION,
248
+ tenantCode ?? DEFAULT_TENANT_CODE,
249
+ clientIdx,
250
+ oid ?? DEFAULT_OID,
251
+ attribution
252
+ );
253
+ } catch (error) {
254
+ console.error(
255
+ "Invalid cloid parameters, defaulting to legacy cloid",
256
+ error,
257
+ { tenantCode, clientCode, oid, options: attribution }
258
+ );
259
+ return LEGACY_CLOID;
260
+ }
261
+ }
262
+ function isClientCode(clientCode, cloidHex) {
263
+ const cloidData = parseCloid(cloidHex);
264
+ if (!cloidData) return false;
265
+ return cloidData.clientId === clientCode;
266
+ }
267
+ function isWidgetType(widgetType, cloidHex) {
268
+ const cloidData = parseCloid(cloidHex);
269
+ if (!cloidData) return false;
270
+ return cloidData.widgetTypeId === widgetType;
271
+ }
272
+ function isMiniAppCloid(cloidHex) {
273
+ const cloidData = parseCloid(cloidHex);
274
+ if (!cloidData) return false;
275
+ return cloidData.isMiniApp;
276
+ }
277
+ function isMiniAppTriggeredCloid(cloidHex) {
278
+ const cloidData = parseCloid(cloidHex);
279
+ if (!cloidData) return false;
280
+ return cloidData.miniAppTriggered;
281
+ }
282
+
283
+ // lib/constants/fee.ts
284
+ var BASED_FEE_WALLET = "0x1924b8561eeF20e70Ede628A296175D358BE80e5";
285
+ var BASED_REFERRAL_CODE = "SHIFU";
286
+
287
+ // lib/fee.ts
288
+ var TARGET_SPOT_BUILDER_FEE = 100;
289
+ var TARGET_FUTURES_BUILDER_FEE = 25;
290
+ var TARGET_APPROVED_MAX_BUILDER_FEE = Math.max(
291
+ TARGET_SPOT_BUILDER_FEE,
292
+ TARGET_FUTURES_BUILDER_FEE
293
+ );
294
+ var TARGET_APPROVED_MAX_BUILDER_FEE_PERCENT = `0.1%`;
295
+ var getApprovalAmount = ({
296
+ customFeeEnabled,
297
+ perpetualTradingFee,
298
+ spotTradingFee
299
+ }) => {
300
+ if (!customFeeEnabled) {
301
+ return {
302
+ approvalAmount: TARGET_APPROVED_MAX_BUILDER_FEE,
303
+ perpFee: TARGET_FUTURES_BUILDER_FEE,
304
+ spotFee: TARGET_SPOT_BUILDER_FEE,
305
+ approvalPercent: TARGET_APPROVED_MAX_BUILDER_FEE_PERCENT,
306
+ builder: BASED_FEE_WALLET,
307
+ referralCode: BASED_REFERRAL_CODE
308
+ };
309
+ }
310
+ let validatedPerpFeePct = perpetualTradingFee;
311
+ if (validatedPerpFeePct === void 0) {
312
+ validatedPerpFeePct = TARGET_FUTURES_BUILDER_FEE / 1e3;
313
+ }
314
+ if (validatedPerpFeePct > 0 && validatedPerpFeePct < 0.01) {
315
+ console.warn("Perp fee is less than 0.01%, setting to 0.01%");
316
+ validatedPerpFeePct = 0.01;
317
+ }
318
+ if (validatedPerpFeePct < 0) {
319
+ console.warn("Perp fee is less than 0, setting to 0");
320
+ validatedPerpFeePct = 0;
321
+ }
322
+ if (validatedPerpFeePct > 0.1) {
323
+ console.warn("Perp fee is greater than 0.1%, setting to 0.1%");
324
+ validatedPerpFeePct = 0.1;
325
+ }
326
+ let validatedSpotFeePct = spotTradingFee;
327
+ if (validatedSpotFeePct === void 0) {
328
+ validatedSpotFeePct = TARGET_SPOT_BUILDER_FEE / 1e3;
329
+ }
330
+ if (validatedSpotFeePct > 0 && validatedSpotFeePct < 0.025) {
331
+ console.warn("Spot fee is less than 0.025%, setting to 0.025%");
332
+ validatedSpotFeePct = 0.025;
333
+ }
334
+ if (validatedSpotFeePct < 0) {
335
+ console.warn("Spot fee is less than 0, setting to 0");
336
+ validatedSpotFeePct = 0;
337
+ }
338
+ if (validatedSpotFeePct > 1) {
339
+ console.warn("Spot fee is greater than 1%, setting to 1%");
340
+ validatedSpotFeePct = 1;
341
+ }
342
+ const perpFee = Math.floor(validatedPerpFeePct * 1e3);
343
+ const spotFee = Math.floor(validatedSpotFeePct * 1e3);
344
+ const requiredPercent = validatedPerpFeePct > validatedSpotFeePct ? validatedPerpFeePct : validatedSpotFeePct;
345
+ const requiredAmount = Math.max(Math.floor(requiredPercent * 1e3), 1);
346
+ const requiredPercentString = `${requiredAmount / 1e3}%`;
347
+ return {
348
+ approvalAmount: requiredAmount,
349
+ approvalPercent: requiredPercentString,
350
+ perpFee,
351
+ spotFee,
352
+ builder: BASED_FEE_WALLET,
353
+ referralCode: BASED_REFERRAL_CODE
354
+ };
355
+ };
356
+
357
+ // lib/pup/types.ts
358
+ var PUP_TOKEN_ADDRESS = "0x876e7f2f30935118a654fc0e1f807afc49efe500";
359
+ var PUP_TOKEN_THRESHOLDS = {
360
+ AIRDROP_70_PERCENT: 0.7,
361
+ AIRDROP_35_PERCENT: 0.35,
362
+ AIRDROP_110_PERCENT: 1.1,
363
+ NON_AIRDROP_TOKENS: 2e6
364
+ };
365
+ var XP_BOOST_PERCENTAGES = {
366
+ NO_BOOST: 0,
367
+ TIER_1: 25,
368
+ TIER_2: 50,
369
+ TIER_3: 60
370
+ };
371
+
372
+ // lib/pup/calculator.ts
373
+ function calculateTotalPupAmount(positions) {
374
+ let totalPupAmount = 0;
375
+ const pupAddress = PUP_TOKEN_ADDRESS.toLowerCase();
376
+ for (const position of positions) {
377
+ try {
378
+ if (position.version === "erc20" && position.pair === "PUP") {
379
+ const amount = parseFloat(position.amount) / 1e18;
380
+ totalPupAmount += amount;
381
+ console.log(`Found pure PUP position: ${amount} PUP`);
382
+ } else if (position.version === "v3" && position.v3LPTokenInfo) {
383
+ const { token0, token1 } = position.v3LPTokenInfo;
384
+ if (token0.address.toLowerCase() === pupAddress || token0.symbol === "PUP") {
385
+ totalPupAmount += token0.amount;
386
+ console.log(`Found V3 LP position with PUP as token0: ${token0.amount} PUP`);
387
+ } else if (token1.address.toLowerCase() === pupAddress || token1.symbol === "PUP") {
388
+ totalPupAmount += token1.amount;
389
+ console.log(`Found V3 LP position with PUP as token1: ${token1.amount} PUP`);
390
+ }
391
+ }
392
+ } catch (error) {
393
+ console.error(`Error processing position ${position.pair}:`, error);
394
+ }
395
+ }
396
+ console.log(`Total PUP amount calculated: ${totalPupAmount}`);
397
+ return totalPupAmount;
398
+ }
399
+ function calculateBoostPercentage(pupTokenAmount, normalizedAirDropAmount, isAirdropRecipient) {
400
+ if (isAirdropRecipient && normalizedAirDropAmount > 0) {
401
+ const retentionRatio = pupTokenAmount / normalizedAirDropAmount;
402
+ if (retentionRatio >= PUP_TOKEN_THRESHOLDS.AIRDROP_110_PERCENT) {
403
+ return XP_BOOST_PERCENTAGES.TIER_3;
404
+ }
405
+ if (retentionRatio >= PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT) {
406
+ return XP_BOOST_PERCENTAGES.TIER_2;
407
+ }
408
+ if (retentionRatio >= PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT) {
409
+ return XP_BOOST_PERCENTAGES.TIER_1;
410
+ }
411
+ return XP_BOOST_PERCENTAGES.NO_BOOST;
412
+ } else {
413
+ if (pupTokenAmount >= PUP_TOKEN_THRESHOLDS.NON_AIRDROP_TOKENS) {
414
+ return XP_BOOST_PERCENTAGES.TIER_1;
415
+ }
416
+ return XP_BOOST_PERCENTAGES.NO_BOOST;
417
+ }
418
+ }
419
+ function normalizeAirdropAmount(amount) {
420
+ if (!amount) return 0;
421
+ if (typeof amount === "bigint") {
422
+ return Number(amount) / 1e18;
423
+ } else if (amount && typeof amount.div === "function") {
424
+ return amount.div(1e18).toNumber();
425
+ }
426
+ return 0;
427
+ }
428
+ function getNextTierInfo(pupTokenAmount, normalizedAirDropAmount, isAirdropRecipient) {
429
+ const currentBoost = calculateBoostPercentage(pupTokenAmount, normalizedAirDropAmount, isAirdropRecipient);
430
+ let currentTier = 0;
431
+ if (currentBoost === XP_BOOST_PERCENTAGES.TIER_3) currentTier = 3;
432
+ else if (currentBoost === XP_BOOST_PERCENTAGES.TIER_2) currentTier = 2;
433
+ else if (currentBoost === XP_BOOST_PERCENTAGES.TIER_1) currentTier = 1;
434
+ if (isAirdropRecipient && normalizedAirDropAmount > 0) {
435
+ const retentionRatio = pupTokenAmount / normalizedAirDropAmount;
436
+ if (currentTier === 0) {
437
+ const threshold = normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT;
438
+ return {
439
+ currentTier: 0,
440
+ currentBoost: XP_BOOST_PERCENTAGES.NO_BOOST,
441
+ nextTier: 1,
442
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_1,
443
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
444
+ nextTierThreshold: threshold,
445
+ progressPercentage: Math.min(100, pupTokenAmount / threshold * 100)
446
+ };
447
+ } else if (currentTier === 1) {
448
+ const threshold = normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT;
449
+ return {
450
+ currentTier: 1,
451
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_1,
452
+ nextTier: 2,
453
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_2,
454
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
455
+ nextTierThreshold: threshold,
456
+ progressPercentage: Math.min(100, (pupTokenAmount - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT) / (threshold - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT) * 100)
457
+ };
458
+ } else if (currentTier === 2) {
459
+ const threshold = normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_110_PERCENT;
460
+ return {
461
+ currentTier: 2,
462
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_2,
463
+ nextTier: 3,
464
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_3,
465
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
466
+ nextTierThreshold: threshold,
467
+ progressPercentage: Math.min(100, (pupTokenAmount - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT) / (threshold - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT) * 100)
468
+ };
469
+ } else {
470
+ return {
471
+ currentTier: 3,
472
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_3,
473
+ nextTier: null,
474
+ nextBoost: null,
475
+ amountToNextTier: null,
476
+ nextTierThreshold: null,
477
+ progressPercentage: 100
478
+ };
479
+ }
480
+ } else {
481
+ const threshold = PUP_TOKEN_THRESHOLDS.NON_AIRDROP_TOKENS;
482
+ if (currentTier === 0) {
483
+ return {
484
+ currentTier: 0,
485
+ currentBoost: XP_BOOST_PERCENTAGES.NO_BOOST,
486
+ nextTier: 1,
487
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_1,
488
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
489
+ nextTierThreshold: threshold,
490
+ progressPercentage: Math.min(100, pupTokenAmount / threshold * 100)
491
+ };
492
+ } else {
493
+ return {
494
+ currentTier: 1,
495
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_1,
496
+ nextTier: null,
497
+ nextBoost: null,
498
+ amountToNextTier: null,
499
+ nextTierThreshold: null,
500
+ progressPercentage: 100
501
+ };
502
+ }
503
+ }
504
+ }
505
+
506
+ // lib/constants/tokens.ts
507
+ var USDC_SPOT_TOKEN = {
508
+ name: "USDC",
509
+ szDecimals: 8,
510
+ weiDecimals: 8,
511
+ index: 0,
512
+ tokenId: "0x6d1e7cde53ba9467b783cb7c530ce054",
513
+ isCanonical: true,
514
+ evmContract: null,
515
+ fullName: null,
516
+ deployerTradingFeeShare: "0.0"
517
+ };
518
+ var TESTNET_USDC_SPOT_TOKEN = {
519
+ name: "USDC",
520
+ szDecimals: 8,
521
+ weiDecimals: 8,
522
+ index: 0,
523
+ tokenId: "0xeb62eee3685fc4c43992febcd9e75443",
524
+ isCanonical: true,
525
+ evmContract: {
526
+ address: "0xd9cbec81df392a88aeff575e962d149d57f4d6bc",
527
+ evm_extra_wei_decimals: 0
528
+ },
529
+ fullName: null,
530
+ deployerTradingFeeShare: "0.0"
531
+ };
532
+
533
+ // lib/meta/metadata.ts
534
+ import {
535
+ HttpTransport,
536
+ InfoClient
537
+ } from "@nktkas/hyperliquid";
538
+
539
+ // lib/hip3/utils.ts
540
+ function isHip3Symbol(symbol) {
541
+ if (!symbol) return false;
542
+ return symbol.includes(":");
543
+ }
544
+
545
+ // import("./data/**/*/staticMeta.json") in lib/meta/metadata.ts
546
+ var globImport_data_staticMeta_json = __glob({
547
+ "./data/mainnet/staticMeta.json": () => import("./staticMeta-HRXST42O.mjs"),
548
+ "./data/testnet/staticMeta.json": () => import("./staticMeta-QWPQK3MD.mjs")
549
+ });
550
+
551
+ // import("./data/**/*/spotMeta.json") in lib/meta/metadata.ts
552
+ var globImport_data_spotMeta_json = __glob({
553
+ "./data/mainnet/spotMeta.json": () => import("./spotMeta-7IJT3W6H.mjs"),
554
+ "./data/testnet/spotMeta.json": () => import("./spotMeta-ZVBZNUUE.mjs")
555
+ });
556
+
557
+ // import("./data/**/*/meta.json") in lib/meta/metadata.ts
558
+ var globImport_data_meta_json = __glob({
559
+ "./data/mainnet/meta.json": () => import("./meta-52Q5UUQ4.mjs"),
560
+ "./data/testnet/meta.json": () => import("./meta-UUXKK7IB.mjs")
561
+ });
562
+
563
+ // import("./data/**/*/perpDexs.json") in lib/meta/metadata.ts
564
+ var globImport_data_perpDexs_json = __glob({
565
+ "./data/mainnet/perpDexs.json": () => import("./perpDexs-S3TK25EU.mjs"),
566
+ "./data/testnet/perpDexs.json": () => import("./perpDexs-TZIQ57IW.mjs")
567
+ });
568
+
569
+ // lib/meta/metadata.ts
570
+ var ROOT_DEX = "hyperliquid";
571
+ var MetadataClient = class {
572
+ constructor(config = {}) {
573
+ // Core metadata
574
+ this.spotMeta = null;
575
+ this.perpsMeta = null;
576
+ this.perpDexs = [];
577
+ this.staticMeta = null;
578
+ // HIP-3 metadata cache
579
+ this.hip3DexsMeta = /* @__PURE__ */ new Map();
580
+ // Pre-computed lookup maps (populated on initialize)
581
+ this.perpsSymbolToIndex = /* @__PURE__ */ new Map();
582
+ this.spotTokenNameToIndex = /* @__PURE__ */ new Map();
583
+ this.spotPairToMarket = /* @__PURE__ */ new Map();
584
+ this.baseTokenToMarkets = /* @__PURE__ */ new Map();
585
+ this.quoteAssets = [];
586
+ // Unified symbol lookup (used by getMarketBySymbol for O(1) access)
587
+ // Maps symbol to MarketInfo for quick lookups
588
+ this.coinToMarket = /* @__PURE__ */ new Map();
589
+ // HIP-3 optimized lookups
590
+ // Maps "dex:coin" symbol to MarketInfo
591
+ this.hip3SymbolToMarket = /* @__PURE__ */ new Map();
592
+ // Maps dex name to dex index for quick lookups
593
+ this.dexNameToIndex = /* @__PURE__ */ new Map();
594
+ // Lazy init flag
595
+ this.initialized = false;
596
+ const transport = new HttpTransport({
597
+ isTestnet: config.isTestnet ?? false
598
+ });
599
+ this.infoClient = new InfoClient({ transport });
600
+ this.config = {
601
+ ...config,
602
+ hip3Dexs: config.hip3Dexs?.filter((dex) => dex !== ROOT_DEX),
603
+ useStaticFallback: config.useStaticFallback ?? true
604
+ };
605
+ this.isTestnet = config.isTestnet ?? false;
606
+ this.initialize();
607
+ }
608
+ /**
609
+ * Initialize metadata by fetching from Hyperliquid
610
+ */
611
+ async initialize() {
612
+ if (this.initialized) return;
613
+ await this.loadStaticMetaOverrides();
614
+ if (this.config.onlyUseStaticFallback) {
615
+ await this.loadStaticMetadata();
616
+ this.buildLookupMaps();
617
+ if (this.config.hip3Dexs && this.config.hip3Dexs.length > 0) {
618
+ await Promise.all(
619
+ this.config.hip3Dexs.map((dex) => this.loadHip3Metadata(dex))
620
+ );
621
+ }
622
+ this.initialized = true;
623
+ return;
624
+ }
625
+ try {
626
+ [this.spotMeta, this.perpsMeta, this.perpDexs] = await Promise.all([
627
+ this.infoClient.spotMeta(),
628
+ this.infoClient.meta(),
629
+ this.infoClient.perpDexs()
630
+ ]);
631
+ this.buildLookupMaps();
632
+ if (this.config.hip3Dexs && this.config.hip3Dexs.length > 0) {
633
+ await Promise.all(
634
+ this.config.hip3Dexs.map((dex) => this.loadHip3Metadata(dex))
635
+ );
636
+ }
637
+ this.initialized = true;
638
+ } catch (error) {
639
+ if (this.config.useStaticFallback) {
640
+ console.warn(
641
+ "Failed to fetch metadata from API, using static fallback data",
642
+ error
643
+ );
644
+ await this.loadStaticMetadata();
645
+ this.buildLookupMaps();
646
+ this.initialized = true;
647
+ } else {
648
+ throw error;
649
+ }
650
+ }
651
+ }
652
+ /**
653
+ * Load staticMeta.json for display overrides
654
+ * This is always loaded regardless of config.useStaticFallback
655
+ */
656
+ async loadStaticMetaOverrides() {
657
+ const network = this.isTestnet ? "testnet" : "mainnet";
658
+ try {
659
+ const staticMetaModule = await globImport_data_staticMeta_json(`./data/${network}/staticMeta.json`);
660
+ this.staticMeta = staticMetaModule.default;
661
+ } catch (error) {
662
+ console.warn(`Failed to load staticMeta.json for ${network}:`, error);
663
+ this.staticMeta = null;
664
+ }
665
+ }
666
+ /**
667
+ * Load static metadata from bundled JSON files
668
+ */
669
+ async loadStaticMetadata() {
670
+ const network = this.isTestnet ? "testnet" : "mainnet";
671
+ try {
672
+ const [
673
+ spotMetaModule,
674
+ perpsMetaModule,
675
+ perpDexsModule,
676
+ staticMetaModule
677
+ ] = await Promise.all([
678
+ globImport_data_spotMeta_json(`./data/${network}/spotMeta.json`),
679
+ globImport_data_meta_json(`./data/${network}/meta.json`),
680
+ globImport_data_perpDexs_json(`./data/${network}/perpDexs.json`),
681
+ globImport_data_staticMeta_json(`./data/${network}/staticMeta.json`)
682
+ ]);
683
+ this.spotMeta = spotMetaModule.default;
684
+ this.perpsMeta = perpsMetaModule.default;
685
+ this.perpDexs = perpDexsModule.default;
686
+ this.staticMeta = staticMetaModule.default;
687
+ console.warn(`Using static ${network} metadata`);
688
+ } catch (error) {
689
+ console.error(`Failed to load static ${network} metadata:`, error);
690
+ throw new Error(`Could not load metadata for ${network}`);
691
+ }
692
+ }
693
+ /**
694
+ * Build optimized lookup maps from raw metadata
695
+ * Called after metadata is loaded (from API or static files)
696
+ */
697
+ buildLookupMaps() {
698
+ this.perpsSymbolToIndex.clear();
699
+ this.spotTokenNameToIndex.clear();
700
+ this.spotPairToMarket.clear();
701
+ this.baseTokenToMarkets.clear();
702
+ this.coinToMarket.clear();
703
+ this.hip3SymbolToMarket.clear();
704
+ this.dexNameToIndex.clear();
705
+ this.quoteAssets = [];
706
+ if (this.perpDexs) {
707
+ this.perpDexs.forEach((dex, index) => {
708
+ if (dex && dex.name) {
709
+ this.dexNameToIndex.set(dex.name.toLowerCase(), index);
710
+ }
711
+ });
712
+ }
713
+ if (this.perpsMeta) {
714
+ this.perpsMeta.universe.forEach((market, index) => {
715
+ const marketInfo = {
716
+ symbol: market.name,
717
+ coin: market.name,
718
+ assetId: index,
719
+ szDecimals: market.szDecimals,
720
+ type: "perps",
721
+ maxLeverage: market.maxLeverage
722
+ };
723
+ const staticOverrides = this.staticMeta?.coins?.[market.name];
724
+ if (staticOverrides) {
725
+ if (staticOverrides.displayName) {
726
+ marketInfo.displayName = staticOverrides.displayName;
727
+ }
728
+ if (staticOverrides.imageUrl) {
729
+ marketInfo.imageUrl = staticOverrides.imageUrl;
730
+ }
731
+ }
732
+ this.perpsSymbolToIndex.set(market.name.toUpperCase(), index);
733
+ this.coinToMarket.set(market.name, marketInfo);
734
+ });
735
+ }
736
+ if (this.spotMeta) {
737
+ this.spotMeta.tokens.forEach((token) => {
738
+ this.spotTokenNameToIndex.set(token.name.toUpperCase(), token.index);
739
+ });
740
+ const quoteIndices = /* @__PURE__ */ new Set();
741
+ this.spotMeta.universe.forEach((universe) => {
742
+ const baseToken = this.spotMeta.tokens[universe.tokens[0]];
743
+ const quoteToken = this.spotMeta.tokens[universe.tokens[1]];
744
+ if (!baseToken || !quoteToken) return;
745
+ const coin = universe.name;
746
+ quoteIndices.add(quoteToken.index);
747
+ const marketInfo = {
748
+ coin,
749
+ symbol: `${baseToken.name}/${quoteToken.name}`,
750
+ assetId: 1e4 + universe.index,
751
+ szDecimals: baseToken.szDecimals,
752
+ type: "spot",
753
+ baseToken,
754
+ quoteToken
755
+ };
756
+ const staticOverrides = this.staticMeta?.coins?.[coin];
757
+ if (staticOverrides) {
758
+ if (staticOverrides.displayName) {
759
+ marketInfo.displayName = staticOverrides.displayName;
760
+ }
761
+ if (staticOverrides.imageUrl) {
762
+ marketInfo.imageUrl = staticOverrides.imageUrl;
763
+ }
764
+ }
765
+ const pairKey = `${baseToken.name}/${quoteToken.name}`.toUpperCase();
766
+ this.spotPairToMarket.set(pairKey, marketInfo);
767
+ this.coinToMarket.set(pairKey, marketInfo);
768
+ this.coinToMarket.set(coin, marketInfo);
769
+ const baseKey = baseToken.name.toUpperCase();
770
+ const existing = this.baseTokenToMarkets.get(baseKey) || [];
771
+ existing.push(marketInfo);
772
+ this.baseTokenToMarkets.set(baseKey, existing);
773
+ });
774
+ this.quoteAssets = Array.from(quoteIndices).map((idx) => this.spotMeta.tokens[idx].name).sort();
775
+ }
776
+ }
777
+ /**
778
+ * Load metadata for a specific HIP-3 DEX
779
+ * Also builds optimized lookups for this DEX's markets
780
+ */
781
+ async loadHip3Metadata(dexName) {
782
+ if (this.hip3DexsMeta.has(dexName)) return this.hip3DexsMeta.get(dexName);
783
+ try {
784
+ const [meta, contexts] = await this.infoClient.metaAndAssetCtxs({
785
+ dex: dexName
786
+ });
787
+ let dexIndex = this.dexNameToIndex.get(dexName.toLowerCase());
788
+ if (dexIndex === void 0) {
789
+ dexIndex = this.perpDexs.findIndex(
790
+ (d) => d && d.name.toLowerCase() === dexName.toLowerCase()
791
+ );
792
+ }
793
+ if (dexIndex === -1 || dexIndex === void 0) {
794
+ throw new Error(`DEX ${dexName} not found`);
795
+ }
796
+ const dex = this.perpDexs[dexIndex];
797
+ const collateralTokenIndex = meta.collateralToken ?? 0;
798
+ const spotMetaTokens = this.spotMeta?.tokens;
799
+ const collateralTokenSymbol = spotMetaTokens?.[collateralTokenIndex]?.name ?? "USDC";
800
+ const dexInfo = {
801
+ meta,
802
+ assetContext: contexts,
803
+ collateralTokenSymbol,
804
+ dexFullName: dex?.fullName ?? dexName,
805
+ dexName: dex?.name ?? dexName,
806
+ dexIndex
807
+ };
808
+ const staticDexOverrides = this.staticMeta?.dexs?.[dexName];
809
+ if (staticDexOverrides) {
810
+ if (staticDexOverrides.displayName) {
811
+ dexInfo.displayName = staticDexOverrides.displayName;
812
+ }
813
+ if (staticDexOverrides.imageUrl) {
814
+ dexInfo.imageUrl = staticDexOverrides.imageUrl;
815
+ }
816
+ }
817
+ this.hip3DexsMeta.set(dexName, dexInfo);
818
+ this.buildHip3MarketsForDex(dexName, dexInfo);
819
+ return dexInfo;
820
+ } catch (error) {
821
+ console.error(`Failed to load HIP-3 metadata for ${dexName}:`, error);
822
+ throw error;
823
+ }
824
+ }
825
+ /**
826
+ * Build optimized lookups for HIP-3 markets of a specific DEX
827
+ */
828
+ buildHip3MarketsForDex(dexName, dexInfo) {
829
+ dexInfo.meta.universe.forEach((market, index) => {
830
+ const symbol = market.name;
831
+ const marketInfo = {
832
+ coin: symbol,
833
+ symbol,
834
+ assetId: 1e5 + dexInfo.dexIndex * 1e4 + index,
835
+ szDecimals: market.szDecimals,
836
+ type: "hip3",
837
+ maxLeverage: market.maxLeverage,
838
+ dexName,
839
+ dexIndex: dexInfo.dexIndex,
840
+ dexDisplayName: dexInfo.displayName,
841
+ dexImageUrl: dexInfo.imageUrl
842
+ };
843
+ const staticOverrides = this.staticMeta?.coins?.[symbol];
844
+ if (staticOverrides) {
845
+ if (staticOverrides.displayName) {
846
+ marketInfo.displayName = staticOverrides.displayName;
847
+ }
848
+ if (staticOverrides.imageUrl) {
849
+ marketInfo.imageUrl = staticOverrides.imageUrl;
850
+ }
851
+ }
852
+ this.coinToMarket.set(symbol, marketInfo);
853
+ this.hip3SymbolToMarket.set(symbol, marketInfo);
854
+ });
855
+ }
856
+ /**
857
+ * Ensure metadata is loaded (for lazy init)
858
+ */
859
+ async ensureInitialized() {
860
+ if (!this.initialized) {
861
+ await this.initialize();
862
+ }
863
+ }
864
+ /**
865
+ * Get market information by symbol
866
+ * Optimized: O(1) direct map lookup for most cases
867
+ * Lazily initialize hip-3 metadata if not already initialized
868
+ *
869
+ * @param symbol - Market symbol (e.g., "BTC", "PURR/USDC", "vntls:ABC")
870
+ * @param quoteAsset - Quote asset for spot markets (default: "USDC")
871
+ * @returns Market information or null if not found
872
+ */
873
+ async getMarketBySymbolAsync(symbol, quoteAsset = "USDC") {
874
+ await this.ensureInitialized();
875
+ if (symbol.includes(":")) {
876
+ return this.getHip3Market(symbol);
877
+ }
878
+ let lookupKey = symbol.toUpperCase();
879
+ if (!symbol.includes("/") && !symbol.includes("@")) {
880
+ const perpsMarket = this.coinToMarket.get(symbol);
881
+ if (perpsMarket?.type === "perps") {
882
+ return perpsMarket;
883
+ }
884
+ lookupKey = `${symbol}/${quoteAsset}`.toUpperCase();
885
+ }
886
+ return this.coinToMarket.get(lookupKey) || null;
887
+ }
888
+ getMarketByCoin(coin) {
889
+ return this.coinToMarket.get(coin) || null;
890
+ }
891
+ /**
892
+ * Get perpetuals market information
893
+ * Optimized: O(1) map lookup instead of O(n) array search
894
+ */
895
+ getPerpsMarket(symbol) {
896
+ if (!this.perpsMeta) return null;
897
+ if (isHip3Symbol(symbol)) {
898
+ const [dexName, coinName] = symbol.split(":");
899
+ if (!dexName || !coinName) return null;
900
+ let cachedMarket = this.hip3SymbolToMarket.get(symbol);
901
+ return cachedMarket || null;
902
+ }
903
+ const index = this.perpsSymbolToIndex.get(symbol.toUpperCase());
904
+ if (index === void 0) return null;
905
+ const market = this.perpsMeta.universe[index];
906
+ return {
907
+ coin: symbol,
908
+ symbol: market.name,
909
+ assetId: index,
910
+ // Perps asset ID is just the index
911
+ szDecimals: market.szDecimals,
912
+ type: "perps",
913
+ maxLeverage: market.maxLeverage
914
+ };
915
+ }
916
+ /**
917
+ * Get spot market information
918
+ * Optimized: O(1) map lookup instead of O(n) array searches
919
+ *
920
+ * @param baseSymbol - Base token symbol (e.g., "PURR", "UHYPE")
921
+ * @param quoteSymbol - Quote token symbol (default: "USDC")
922
+ */
923
+ getSpotMarket(baseSymbol, quoteSymbol = "USDC") {
924
+ if (!this.spotMeta) return null;
925
+ const pairKey = `${baseSymbol}/${quoteSymbol}`.toUpperCase();
926
+ const market = this.spotPairToMarket.get(pairKey);
927
+ return market || null;
928
+ }
929
+ /**
930
+ * Get HIP-3 market information
931
+ * Optimized: O(1) map lookup after DEX metadata is loaded
932
+ *
933
+ * @param symbol - HIP-3 market symbol (format: "dex:coin")
934
+ */
935
+ async getHip3Market(symbol) {
936
+ const [dexName, coinName] = symbol.split(":");
937
+ if (!dexName || !coinName) return null;
938
+ let cachedMarket = this.hip3SymbolToMarket.get(symbol);
939
+ if (cachedMarket) return cachedMarket;
940
+ const dexMeta = this.hip3DexsMeta.get(dexName);
941
+ if (!dexMeta && this.config.lazyInit) {
942
+ await this.loadHip3Metadata(dexName);
943
+ cachedMarket = this.hip3SymbolToMarket.get(symbol);
944
+ return cachedMarket || null;
945
+ }
946
+ return null;
947
+ }
948
+ async getHip3Dex(dexName) {
949
+ await this.ensureInitialized();
950
+ let dexInfo = this.hip3DexsMeta.get(dexName) ?? null;
951
+ if (this.config.lazyInit && !dexInfo) {
952
+ dexInfo = await this.loadHip3Metadata(dexName);
953
+ }
954
+ return dexInfo;
955
+ }
956
+ /**
957
+ * Get all available markets for a base token
958
+ * Optimized: O(1) map lookup instead of O(n) filter + map
959
+ * Useful for showing all quote asset options
960
+ */
961
+ getAllMarketsForBase(baseSymbol) {
962
+ if (!this.spotMeta) return [];
963
+ const baseKey = baseSymbol.toUpperCase();
964
+ return this.baseTokenToMarkets.get(baseKey) || [];
965
+ }
966
+ /**
967
+ * Get spot token information
968
+ * Optimized: O(1) map lookup instead of O(n) array search
969
+ */
970
+ getSpotTokenInfo(tokenSymbol) {
971
+ if (!this.spotMeta) return null;
972
+ const tokenIndex = this.spotTokenNameToIndex.get(tokenSymbol.toUpperCase());
973
+ if (tokenIndex === void 0) return null;
974
+ const token = this.spotMeta.tokens[tokenIndex];
975
+ return {
976
+ name: token.name,
977
+ index: token.index,
978
+ szDecimals: token.szDecimals,
979
+ weiDecimals: token.weiDecimals,
980
+ tokenId: token.tokenId
981
+ };
982
+ }
983
+ /**
984
+ * Get all available quote assets
985
+ * Optimized: O(1) pre-computed array instead of O(n) computation
986
+ */
987
+ getAvailableQuoteAssets() {
988
+ return this.quoteAssets;
989
+ }
990
+ /**
991
+ * Get raw metadata (for advanced use cases)
992
+ */
993
+ getRawMetadata() {
994
+ return {
995
+ spotMeta: this.spotMeta,
996
+ perpsMeta: this.perpsMeta,
997
+ perpDexs: this.perpDexs,
998
+ hip3DexsMeta: Object.fromEntries(this.hip3DexsMeta)
999
+ };
1000
+ }
1001
+ /**
1002
+ * Get network configuration
1003
+ */
1004
+ getNetworkInfo() {
1005
+ return {
1006
+ isTestnet: this.isTestnet,
1007
+ useStaticFallback: this.config.useStaticFallback,
1008
+ initialized: this.initialized
1009
+ };
1010
+ }
1011
+ };
1012
+
1013
+ // lib/utils/formatter.ts
1014
+ import { Decimal } from "decimal.js";
1015
+ var formatPriceAndSize = ({
1016
+ px,
1017
+ sz,
1018
+ szDecimals,
1019
+ isSpot
1020
+ }) => {
1021
+ const priceDecimals = getPriceDecimals(px, szDecimals, isSpot);
1022
+ const price = new Decimal(px).toDP(priceDecimals).toNumber();
1023
+ const size = new Decimal(sz).toDP(szDecimals, Decimal.ROUND_DOWN).toNumber();
1024
+ return {
1025
+ price,
1026
+ size
1027
+ };
1028
+ };
1029
+ var formatPriceForOrder = ({
1030
+ px,
1031
+ szDecimals,
1032
+ isSpot
1033
+ }) => {
1034
+ const priceDecimals = getPriceDecimals(px, szDecimals, isSpot);
1035
+ const price = new Decimal(px).toDP(priceDecimals).toNumber();
1036
+ return price;
1037
+ };
1038
+ var formatSizeForOrder = ({
1039
+ sz,
1040
+ szDecimals
1041
+ }) => {
1042
+ return new Decimal(sz).toDP(szDecimals, Decimal.ROUND_DOWN).toNumber();
1043
+ };
1044
+ function getPriceDecimals(price, szDecimals, isSpot) {
1045
+ const baseDecimals = isSpot ? 8 : 6;
1046
+ const maxDP = Math.max(baseDecimals - szDecimals, 0);
1047
+ const maxSigFigs = 5;
1048
+ let minDecimals;
1049
+ if (price >= 1e5) {
1050
+ minDecimals = 0;
1051
+ } else {
1052
+ const exp = Math.floor(Math.log10(price));
1053
+ const dp = Math.max(maxSigFigs - exp - 1, 0);
1054
+ minDecimals = Math.min(dp, maxDP);
1055
+ }
1056
+ return minDecimals;
1057
+ }
1058
+ export {
1059
+ CloidClientCode,
1060
+ CloidClientCodeNameById,
1061
+ MetadataClient,
1062
+ PUP_TOKEN_ADDRESS,
1063
+ PUP_TOKEN_THRESHOLDS,
1064
+ ROOT_DEX,
1065
+ TARGET_APPROVED_MAX_BUILDER_FEE,
1066
+ TARGET_APPROVED_MAX_BUILDER_FEE_PERCENT,
1067
+ TESTNET_USDC_SPOT_TOKEN,
1068
+ USDC_SPOT_TOKEN,
1069
+ WidgetType,
1070
+ WidgetTypeById,
1071
+ XP_BOOST_PERCENTAGES,
1072
+ buildCloid,
1073
+ calculateBoostPercentage,
1074
+ calculateTotalPupAmount,
1075
+ decodeSlug,
1076
+ encodeSlug,
1077
+ formatPriceAndSize,
1078
+ formatPriceForOrder,
1079
+ formatSizeForOrder,
1080
+ getApprovalAmount,
1081
+ getClientCodeNameById,
1082
+ getCloid,
1083
+ getNextTierInfo,
1084
+ getPriceDecimals,
1085
+ getWidgetTypeById,
1086
+ isBasedCloid,
1087
+ isClientCode,
1088
+ isMiniAppCloid,
1089
+ isMiniAppTriggeredCloid,
1090
+ isTenantCloid,
1091
+ isTrackingIdCloid,
1092
+ isWidgetType,
1093
+ normaliseSlug,
1094
+ normaliseTrackingId,
1095
+ normalizeAirdropAmount,
1096
+ parseCloid
1097
+ };