@basedone/core 0.0.1 → 0.0.6

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 (47) hide show
  1. package/dist/chunk-4UEJOM6W.mjs +9 -0
  2. package/dist/index.d.mts +462 -0
  3. package/dist/index.d.ts +462 -2
  4. package/dist/index.js +37465 -2
  5. package/dist/index.mjs +1027 -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/index.ts +6 -0
  25. package/lib/cloid/README.md +233 -0
  26. package/lib/cloid/cloid.ts +368 -0
  27. package/lib/cloid/encoder.ts +60 -0
  28. package/lib/constants/fee.ts +2 -0
  29. package/lib/constants/tokens.ts +28 -0
  30. package/lib/fee.ts +105 -0
  31. package/lib/hip3/market-info.ts +25 -0
  32. package/lib/hip3/utils.ts +9 -0
  33. package/lib/meta/README.md +471 -0
  34. package/lib/meta/data/mainnet/meta.json +1462 -0
  35. package/lib/meta/data/mainnet/perpDexs.json +11 -0
  36. package/lib/meta/data/mainnet/spotMeta.json +6432 -0
  37. package/lib/meta/data/testnet/dexs/rrrrr.json +33 -0
  38. package/lib/meta/data/testnet/meta.json +1343 -0
  39. package/lib/meta/data/testnet/perpDexs.json +531 -0
  40. package/lib/meta/data/testnet/spotMeta.json +26547 -0
  41. package/lib/meta/metadata.ts +600 -0
  42. package/lib/pup/calculator.ts +221 -0
  43. package/lib/pup/index.ts +9 -0
  44. package/lib/pup/types.ts +94 -0
  45. package/lib/utils/formatter.ts +97 -0
  46. package/package.json +21 -17
  47. package/readme.md +0 -0
package/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./lib/cloid/cloid";
2
+ export * from "./lib/fee";
3
+ export * from "./lib/pup";
4
+ export * from "./lib/constants/tokens";
5
+ export * from "./lib/meta/metadata";
6
+ export * from "./lib/utils/formatter";
@@ -0,0 +1,233 @@
1
+ # CLOID (Client Order ID) System
2
+
3
+ ## Overview
4
+
5
+ CLOID (Client Order ID) is a 128-bit identifier system used for tracking clients, tenants, and orders/applications in the Based ecosystem. It provides a compact, efficient way to encode multiple pieces of information into a single hexadecimal string.
6
+
7
+ ## Structure
8
+
9
+ A CLOID is a 128-bit (32 hex character) value with the following bit layout:
10
+
11
+ ```
12
+ [ Prefix (24 bits) | Version (4 bits) | Slug (26 bits) | Client ID (5 bits) | isMiniApp (1 bit) | miniAppTriggered (1 bit) | Component ID (3 bits) | OID (64 bits) ]
13
+ ```
14
+
15
+ ### Components
16
+
17
+ 1. **Prefix (24 bits)**: `0xBA5ED1` - A fixed identifier for Based CLOIDs
18
+ 2. **Version (4 bits)**: Protocol version (currently version 1)
19
+ 3. **Slug (26 bits)**: Tenant/organization identifier (5 characters, uppercase alphanumeric)
20
+ 4. **Client ID (5 bits)**: Client type identifier (Web, App, Bot, etc.) - supports 32 client types
21
+ 5. **isMiniApp (1 bit)**: Boolean flag indicating if this is a mini-app order
22
+ 6. **miniAppTriggered (1 bit)**: Boolean flag indicating if the order was triggered by a mini-app
23
+ 7. **Component ID (3 bits)**: Component type (SidePanel, Widget, FloatingWidget, etc.) - supports 8 component types
24
+ 8. **OID (64 bits)**: Order ID or tracking identifier (supports both numeric and string encoding)
25
+
26
+ ## Example CLOID
27
+
28
+ ```
29
+ 0xba5ed11[version][encoded_slug][client_id][order_id]
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Creating a CLOID
35
+
36
+ ```typescript
37
+ import { getCloid, CloidClientCode, CloidComponentCode } from './cloid';
38
+
39
+ // Basic usage with defaults
40
+ const cloid1 = getCloid();
41
+ // Returns: CLOID with tenant="BASED", client=Unset, default OID
42
+
43
+ // With tenant code
44
+ const cloid2 = getCloid("ACME");
45
+
46
+ // With tenant and client type
47
+ const cloid3 = getCloid("ACME", "Web");
48
+
49
+ // With all basic parameters including numeric OID
50
+ const cloid4 = getCloid("ACME", "Web", 123456789n);
51
+
52
+ // With string tracking ID (up to 12 characters)
53
+ const cloid5 = getCloid("ACME", "App", "order-abc123");
54
+
55
+ // With mini-app attribution
56
+ const cloid6 = getCloid("ACME", CloidClientCode.Web, "order-123", {
57
+ isMiniApp: true,
58
+ miniAppTriggered: false,
59
+ component: CloidComponentCode.SidePanel
60
+ });
61
+
62
+ // Mini-app triggered from widget
63
+ const cloid7 = getCloid("TRADER", CloidClientCode.App, "trade-456", {
64
+ isMiniApp: true,
65
+ miniAppTriggered: true,
66
+ component: CloidComponentCode.Widget
67
+ });
68
+ ```
69
+
70
+ ### Parsing a CLOID
71
+
72
+ ```typescript
73
+ import { parseCloid } from './cloid';
74
+
75
+ const parsed = parseCloid("0xba5ed11...");
76
+ // Returns:
77
+ // {
78
+ // prefix: "0xba5ed1",
79
+ // version: 1,
80
+ // slug: "ACME",
81
+ // clientId: 1,
82
+ // isMiniApp: true,
83
+ // miniAppTriggered: false,
84
+ // widgetType: 1,
85
+ // oid: 123456789n,
86
+ // decodedOid: "order-abc123",
87
+ // clientName: "Web",
88
+ // widgetTypeName: "SidePanel"
89
+ // }
90
+ ```
91
+
92
+ ### Validation Functions
93
+
94
+ ```typescript
95
+ import {
96
+ isBasedCloid,
97
+ isTenantCloid,
98
+ isMiniAppCloid,
99
+ isMiniAppTriggeredCloid,
100
+ isComponentCode,
101
+ isClientCode
102
+ } from './cloid';
103
+
104
+ // Check if a hex string is a valid Based CLOID
105
+ const isValid = isBasedCloid("0xba5ed11...");
106
+
107
+ // Check if a CLOID belongs to a specific tenant
108
+ const isTenant = isTenantCloid("ACME", "0xba5ed11...");
109
+
110
+ // Check if a CLOID is from a mini-app
111
+ const isMiniApp = isMiniAppCloid("0xba5ed11...");
112
+
113
+ // Check if a CLOID was triggered by a mini-app
114
+ const isTriggered = isMiniAppTriggeredCloid("0xba5ed11...");
115
+
116
+ // Check if a CLOID has a specific component type
117
+ const isSidePanel = isWidgetType(WidgetType.SidePanel, "0xba5ed11...");
118
+
119
+ // Check if a CLOID has a specific client type
120
+ const isWebClient = isClientCode(CloidClientCode.Web, "0xba5ed11...");
121
+ ```
122
+
123
+ ## Client Types
124
+
125
+ The system supports the following client types (5-bit field supports 0-31):
126
+
127
+ | Code | Name | Description |
128
+ |------|---------|--------------------------------|
129
+ | 0 | Unset | Default/unspecified client |
130
+ | 1 | Web | Web application |
131
+ | 2 | App | Mobile application |
132
+ | 3 | TgBot | Telegram bot |
133
+ | 4 | TSL | Trailing Stop Loss system |
134
+ | 5 | Grid | Grid trading system |
135
+ | 6 | Chase | Chase trading system |
136
+ | 7 | Desktop | Desktop application |
137
+ | 8 | API | Direct API access |
138
+
139
+ ## Component Types
140
+
141
+ The system supports the following component types (3-bit field supports 0-7):
142
+
143
+ | Code | Name | Description |
144
+ |------|----------------|---------------------------------------|
145
+ | 0 | Unset | Default/unspecified component |
146
+ | 1 | SidePanel | Side panel component |
147
+ | 2 | Widget | Widget component |
148
+ | 3 | FloatingWidget| Floating widget component |
149
+ | 4-7 | Reserved | Available for future component types |
150
+
151
+ ## Encoding Details
152
+
153
+ ### Tenant Slug Encoding
154
+ - **Alphabet**: `A-Z0-9` (36 characters)
155
+ - **Length**: 5 characters maximum
156
+ - **Auto-padding**: Shorter slugs are padded with the last alphabet character
157
+ - **Case**: Automatically converted to uppercase
158
+
159
+ ### OID String Encoding
160
+ - **Alphabet**: `a-z0-9|_- ` (40 characters)
161
+ - **Length**: 12 characters maximum
162
+ - **Case**: Automatically converted to lowercase
163
+ - **Usage**: Can encode order IDs, app IDs, or other tracking identifiers
164
+
165
+ ## Special Values
166
+
167
+ ### Legacy CLOID
168
+ ```typescript
169
+ const LEGACY_CLOID = "0x62baee7262baee7262baee7262baee72";
170
+ ```
171
+ Used for backward compatibility with older systems.
172
+
173
+ ### Default Values
174
+ - **Default Tenant**: `"BASED"`
175
+ - **Default OID**: `0xBA5ED10000BA5ED1`
176
+ - **Default Client**: `Unset` (0)
177
+
178
+ ## Utility Functions
179
+
180
+ ### normaliseSlug(slug: string)
181
+ Normalizes a tenant slug to the standard 5-character format.
182
+
183
+ ```typescript
184
+ normaliseSlug("AXON") // Returns: "AXON9" (padded with 9)
185
+ normaliseSlug("LONGNAME") // Returns: "LONGN" (truncated)
186
+ ```
187
+
188
+ ### normaliseTrackingId(trackingId: string)
189
+ Normalizes a tracking ID to the standard 12-character format.
190
+
191
+ ```typescript
192
+ normaliseTrackingId("order123") // Returns normalized 12-char string
193
+ ```
194
+
195
+ ## Use Cases
196
+
197
+ 1. **Order Tracking**: Encode order IDs with tenant and client information
198
+ 2. **Multi-tenant Systems**: Identify which tenant/organization an order belongs to
199
+ 3. **Client Analytics**: Track orders by client type (Web, Mobile, API, etc.)
200
+ 4. **Mini-app Attribution**: Track orders originating from mini-apps with component-level granularity
201
+ 5. **Component Analytics**: Analyze user behavior across different UI components (SidePanel, Widget, FloatingWidget)
202
+ 6. **Trigger Analysis**: Distinguish between orders created directly in mini-apps vs. triggered by mini-app interactions
203
+ 7. **Cross-system Integration**: Compact identifier that can be passed between systems with full attribution data
204
+ 8. **A/B Testing**: Use component and mini-app flags for UI/UX experimentation tracking
205
+
206
+ ## Backward Compatibility
207
+
208
+ The system maintains full backward compatibility with existing CLOIDs:
209
+
210
+ - **Existing CLOIDs**: All previously generated CLOIDs can be parsed correctly
211
+ - **Client ID Preservation**: Original client IDs (0-31) are preserved in the 5-bit field
212
+ - **Mini-app Defaults**: Existing CLOIDs are interpreted with `isMiniApp=false`, `miniAppTriggered=false`, `widgetType=Unset`
213
+ - **Identical Generation**: New CLOIDs without mini-app options generate identical hex values to old CLOIDs
214
+
215
+ ```typescript
216
+ // These generate identical CLOIDs
217
+ const oldStyleCloid = getCloid("BASED", "Web", "0xba5ed10000ba5ed1");
218
+ const newStyleCloid = getCloid("BASED", "Web", "0xba5ed10000ba5ed1", {
219
+ isMiniApp: false,
220
+ miniAppTriggered: false,
221
+ component: CloidComponentCode.Unset
222
+ });
223
+ // oldStyleCloid === newStyleCloid (true)
224
+ ```
225
+
226
+ ## Implementation Notes
227
+
228
+ - CLOIDs are always returned as `0x`-prefixed hex strings
229
+ - The system is designed to be compact while maintaining readability
230
+ - All encoding/decoding operations preserve data integrity
231
+ - Invalid inputs fallback to safe defaults or legacy values
232
+ - The bit layout ensures efficient storage and parsing
233
+ - Mini-app attribution is optional and defaults to false/Unset when not specified
@@ -0,0 +1,368 @@
1
+ // Client Order ID (cloid) is an optional 128 bit hex string
2
+ // 32 hex characters or 16 utf8 characters
3
+ // Bit layout:
4
+ // [ Prefix (24) | Version (4) | Slug (26) | Client ID (5) | MiniApp Attribution (5) | OID (64) ]
5
+
6
+ import { decodeValue, encodeValue } from "./encoder";
7
+
8
+ const LEGACY_CLOID = "0x62baee7262baee7262baee7262baee72";
9
+ const BASED_VERSION = 1;
10
+
11
+ const DEFAULT_TENANT_CODE = "BASED";
12
+ const DEFAULT_OID = 0xba5ed10000ba5ed1n;
13
+
14
+ // CloID bit layout (128 bits total):
15
+ // [ Prefix (24) | Version (4) | Slug (26) | Client ID (5) | isMiniApp (1) | miniAppTriggered (1) | Widget Type ID (3) | OID (64) ]
16
+
17
+ // Constants
18
+ const BASED_HEX_PREFIX = 0xba5ed1; // 24-bit prefix
19
+ const BASED_HEX_PREFIX_STR = "0xba5ed1"; // 24-bit prefix
20
+ const PREFIX_BITS = 24n;
21
+ const VERSION_BITS = 4n;
22
+ const SLUG_BITS = 26n;
23
+ const CLIENT_BITS = 5n;
24
+ const IS_MINI_APP_BITS = 1n;
25
+ const MINI_APP_TRIGGERED_BITS = 1n;
26
+ const WIDGET_TYPE_BITS = 3n;
27
+ const OID_BITS = 64n;
28
+ const TOTAL_BITS = 128n;
29
+
30
+ // Encoding charsets, do not modify
31
+ // Slug alphabet [A-Z0-9] (36 symbols)
32
+ const SLUG_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
33
+
34
+ // Extended OID alphabet [a-z0-9|_- ] (40 symbols)
35
+ const OID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789|_- ";
36
+
37
+ // Utility: mask for n bits
38
+ const mask = (bits: bigint) => (1n << bits) - 1n;
39
+
40
+ // Encode a 5-char slug into a 26-bit integer
41
+ export function encodeSlug(slug: string): bigint {
42
+ if (!slug) slug = DEFAULT_TENANT_CODE;
43
+
44
+ return encodeValue(slug, SLUG_BITS, SLUG_ALPHABET);
45
+ }
46
+
47
+ // Decode a n-bit integer back into a x-char slug
48
+ export function decodeSlug(value: bigint): string {
49
+ return decodeValue(value, SLUG_BITS, SLUG_ALPHABET);
50
+ }
51
+
52
+ // Build a CloID as a 0x-prefixed 32-char hex string
53
+ export function buildCloid(
54
+ version: number,
55
+ slug: string,
56
+ clientId: number,
57
+ oid: bigint | string, // bitint for oid, string for encoded string slug (12 characters max)
58
+ options?: {
59
+ isMiniApp?: boolean;
60
+ miniAppTriggered?: boolean;
61
+ widgetType?: WidgetType | number;
62
+ },
63
+ ): `0x${string}` {
64
+ if (version > 0xf) version = BASED_VERSION;
65
+ if (clientId > Number(mask(CLIENT_BITS))) {
66
+ clientId = CloidClientCode.Unset;
67
+ }
68
+
69
+ const isMiniApp = options?.isMiniApp ? 1 : 0;
70
+ const miniAppTriggered = options?.miniAppTriggered ? 1 : 0;
71
+ const widgetType =
72
+ typeof options?.widgetType === "number"
73
+ ? options.widgetType
74
+ : WidgetType[options?.widgetType ?? "Unset"];
75
+
76
+ if (widgetType > Number(mask(WIDGET_TYPE_BITS))) {
77
+ throw new Error(
78
+ `Component ID ${widgetType} exceeds maximum value ${Number(mask(WIDGET_TYPE_BITS))}`,
79
+ );
80
+ }
81
+ let oidBigInt: bigint;
82
+ if (typeof oid === "string") {
83
+ // is string hex or numeric?
84
+ if (oid.startsWith("0x") || !isNaN(Number(oid))) {
85
+ oidBigInt = BigInt(oid);
86
+ } else {
87
+ // Encode string into number
88
+ oidBigInt = encodeValue(oid.toLowerCase(), OID_BITS, OID_ALPHABET);
89
+ }
90
+ } else {
91
+ oidBigInt = oid;
92
+ }
93
+ if (oidBigInt > mask(OID_BITS)) {
94
+ oidBigInt = DEFAULT_OID;
95
+ }
96
+
97
+ const slugVal = encodeSlug(slug.toUpperCase());
98
+
99
+ let cloid = BigInt(BASED_HEX_PREFIX) << (TOTAL_BITS - PREFIX_BITS); // 0xba5ed10000000000000000000000000000000000
100
+ cloid |= BigInt(version & 0xf) << (TOTAL_BITS - PREFIX_BITS - VERSION_BITS); // 0xba5ed10000000000000000000000000000000000
101
+ cloid |=
102
+ BigInt(slugVal) << (TOTAL_BITS - PREFIX_BITS - VERSION_BITS - SLUG_BITS);
103
+ cloid |= BigInt(clientId) << OID_BITS;
104
+ cloid |= BigInt(isMiniApp) << (OID_BITS + CLIENT_BITS);
105
+ cloid |=
106
+ BigInt(miniAppTriggered) << (OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS);
107
+ cloid |=
108
+ BigInt(widgetType) <<
109
+ (OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS + MINI_APP_TRIGGERED_BITS);
110
+ cloid |= oidBigInt & mask(OID_BITS);
111
+
112
+ return `0x${cloid.toString(16)}`;
113
+ }
114
+
115
+ // Parse a CloID hex string back into fields
116
+ export function parseCloid(cloidHex: `0x${string}`) {
117
+ if (cloidHex === LEGACY_CLOID) {
118
+ return {
119
+ prefix: LEGACY_CLOID,
120
+ version: 0,
121
+ slug: "BASED",
122
+ clientId: CloidClientCode.Unset,
123
+ isMiniApp: false,
124
+ miniAppTriggered: false,
125
+ widgetTypeId: WidgetType.Unset,
126
+ oid: 0xba5ed10000ba5ed1n,
127
+ decodedOid: decodeValue(0xba5ed10000ba5ed1n, OID_BITS, OID_ALPHABET),
128
+ clientName: "Unset",
129
+ widgetTypeName: "Unset",
130
+ };
131
+ }
132
+ try {
133
+ const cloid = BigInt(cloidHex);
134
+
135
+ const prefix = Number(cloid >> (TOTAL_BITS - PREFIX_BITS));
136
+ const version = Number(
137
+ (cloid >> (TOTAL_BITS - PREFIX_BITS - VERSION_BITS)) & mask(VERSION_BITS),
138
+ );
139
+ const slugVal = Number(
140
+ (cloid >>
141
+ (OID_BITS +
142
+ WIDGET_TYPE_BITS +
143
+ MINI_APP_TRIGGERED_BITS +
144
+ IS_MINI_APP_BITS +
145
+ CLIENT_BITS)) &
146
+ mask(SLUG_BITS),
147
+ );
148
+ const clientId = Number((cloid >> OID_BITS) & mask(CLIENT_BITS));
149
+ const isMiniApp =
150
+ Number((cloid >> (OID_BITS + CLIENT_BITS)) & mask(IS_MINI_APP_BITS)) ===
151
+ 1;
152
+ const miniAppTriggered =
153
+ Number(
154
+ (cloid >> (OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS)) &
155
+ mask(MINI_APP_TRIGGERED_BITS),
156
+ ) === 1;
157
+ const widgetType = Number(
158
+ (cloid >>
159
+ (OID_BITS + CLIENT_BITS + IS_MINI_APP_BITS + MINI_APP_TRIGGERED_BITS)) &
160
+ mask(WIDGET_TYPE_BITS),
161
+ );
162
+ const oid = cloid & mask(OID_BITS);
163
+
164
+ return {
165
+ prefix: `0x${prefix.toString(16)}`, // should equal 0xBA5ED1
166
+ version,
167
+ slug: decodeSlug(BigInt(slugVal)),
168
+ clientId,
169
+ isMiniApp,
170
+ miniAppTriggered,
171
+ widgetTypeId: widgetType,
172
+ oid,
173
+ decodedOid: decodeValue(oid, OID_BITS, OID_ALPHABET),
174
+ clientName: getClientCodeNameById(clientId),
175
+ widgetTypeName: getWidgetTypeById(widgetType),
176
+ };
177
+ } catch (error) {
178
+ console.error("Invalid cloid", { cloidHex });
179
+ return null;
180
+ }
181
+ }
182
+
183
+ export type CloidData = ReturnType<typeof parseCloid>;
184
+
185
+ // Quick prefix check
186
+ export function isBasedCloid(cloidHex?: `0x${string}` | null): boolean {
187
+ if (!cloidHex) return false;
188
+ if (cloidHex === LEGACY_CLOID) return true;
189
+ return cloidHex.toLowerCase().startsWith(BASED_HEX_PREFIX_STR);
190
+ }
191
+
192
+ export function isTenantCloid(
193
+ tenantTrackingSlug: string,
194
+ cloidHex?: `0x${string}` | null,
195
+ ): boolean {
196
+ if (!cloidHex || !isBasedCloid(cloidHex)) return false;
197
+ const cloidData = parseCloid(cloidHex);
198
+ if (!cloidData) return false;
199
+ const { slug } = cloidData;
200
+ if (tenantTrackingSlug.length > 5) {
201
+ tenantTrackingSlug = tenantTrackingSlug.slice(0, 5);
202
+ }
203
+
204
+ // Normalise the tenant tracking slug to 5 characters (eg. AXON -> AAXON)
205
+ const normalisedSlug = decodeSlug(encodeSlug(tenantTrackingSlug));
206
+ return slug === normalisedSlug;
207
+ }
208
+
209
+ export function isTrackingIdCloid(
210
+ trackingId: bigint | string,
211
+ cloidHex?: `0x${string}` | null,
212
+ ): boolean {
213
+ if (!cloidHex || !isBasedCloid(cloidHex)) return false;
214
+ const cloidData = parseCloid(cloidHex);
215
+ if (!cloidData) return false;
216
+
217
+ if (typeof trackingId === "string") {
218
+ const encodedTrackingId = normaliseTrackingId(trackingId);
219
+ return encodedTrackingId === cloidData.decodedOid;
220
+ } else {
221
+ const { oid } = cloidData;
222
+ return oid === trackingId;
223
+ }
224
+ }
225
+
226
+ export function normaliseSlug(slug: string): string {
227
+ if (!slug) return "";
228
+ return decodeSlug(encodeSlug(slug.toUpperCase()));
229
+ }
230
+
231
+ /**
232
+ * Normalise a tracking id to 12 characters
233
+ * @param trackingId - The tracking id to normalise
234
+ * @returns The normalised tracking id
235
+ */
236
+ export function normaliseTrackingId(trackingId: string): string {
237
+ if (!trackingId) return "";
238
+ return decodeValue(
239
+ encodeValue(trackingId.toLowerCase(), OID_BITS, OID_ALPHABET),
240
+ OID_BITS,
241
+ OID_ALPHABET,
242
+ );
243
+ }
244
+
245
+ type ClientCode = string;
246
+
247
+ // Client code type 0 - 10 reserved
248
+ export const CloidClientCode = {
249
+ Unset: 0, // 0x00
250
+ Web: 1,
251
+ App: 2,
252
+ TgBot: 3,
253
+ TSL: 4, // Trailing Stop Loss
254
+ Grid: 5,
255
+ Chase: 6,
256
+ Desktop: 7,
257
+ API: 8,
258
+ } as const;
259
+ type ClientCodeType = keyof typeof CloidClientCode;
260
+
261
+ // Inverted map: number -> name
262
+ export type CloidClientCodeId = (typeof CloidClientCode)[ClientCodeType];
263
+ export const CloidClientCodeNameById: Record<number, ClientCodeType> = {
264
+ [CloidClientCode.Unset]: "Unset",
265
+ [CloidClientCode.Web]: "Web",
266
+ [CloidClientCode.App]: "App",
267
+ [CloidClientCode.TgBot]: "TgBot",
268
+ [CloidClientCode.TSL]: "TSL",
269
+ [CloidClientCode.Grid]: "Grid",
270
+ [CloidClientCode.Chase]: "Chase",
271
+ [CloidClientCode.Desktop]: "Desktop",
272
+ [CloidClientCode.API]: "API",
273
+ };
274
+
275
+ export function getClientCodeNameById(id: number): string {
276
+ return CloidClientCodeNameById[id] ?? `client_${id}`;
277
+ }
278
+
279
+ // Component code type 0 - 7 (3 bits max)
280
+ export const WidgetType = {
281
+ Unset: 0, // 0x00
282
+ SidePanel: 1,
283
+ Widget: 2,
284
+ FloatingWidget: 3,
285
+ } as const;
286
+ type WidgetType = keyof typeof WidgetType;
287
+
288
+ // Inverted map: number -> name
289
+ export type WidgetTypeId = (typeof WidgetType)[WidgetType];
290
+ export const WidgetTypeById: Record<number, WidgetType> = {
291
+ [WidgetType.Unset]: "Unset",
292
+ [WidgetType.SidePanel]: "SidePanel",
293
+ [WidgetType.Widget]: "Widget",
294
+ [WidgetType.FloatingWidget]: "FloatingWidget",
295
+ };
296
+
297
+ export function getWidgetTypeById(id: number): string {
298
+ return WidgetTypeById[id] ?? `widget_${id}`;
299
+ }
300
+
301
+ /**
302
+ * @param tenantCode - The tenant code (max 5 characters, truncated if longer) default: "BASED"
303
+ * @param clientCode CloidClientCode - The client code (max 5 characters, truncated if longer) default: "Unset"
304
+ * @param oid - The oid (64 bits) used for identifying unique orders, default: 0xBA5ED10000BA5ED1 or string for encoded string slug (12 characters max)
305
+ * @param attribution - Mini-app and component options
306
+ * @returns The cloid
307
+ */
308
+ export function getCloid(
309
+ tenantCode?: ClientCode | null,
310
+ clientCode?: ClientCodeType | number,
311
+ oid?: bigint | string,
312
+ attribution?: {
313
+ isMiniApp?: boolean;
314
+ miniAppTriggered?: boolean;
315
+ widgetType?: WidgetType | number;
316
+ },
317
+ ): `0x${string}` {
318
+ try {
319
+ const clientIdx =
320
+ typeof clientCode === "number"
321
+ ? clientCode
322
+ : CloidClientCode[clientCode ?? "Unset"];
323
+ return buildCloid(
324
+ BASED_VERSION,
325
+ tenantCode ?? DEFAULT_TENANT_CODE,
326
+ clientIdx,
327
+ oid ?? DEFAULT_OID,
328
+ attribution,
329
+ );
330
+ } catch (error) {
331
+ console.error(
332
+ "Invalid cloid parameters, defaulting to legacy cloid",
333
+ error,
334
+ { tenantCode, clientCode, oid, options: attribution },
335
+ );
336
+ return LEGACY_CLOID;
337
+ }
338
+ }
339
+
340
+ export function isClientCode(
341
+ clientCode: ClientCodeType | number,
342
+ cloidHex: `0x${string}`,
343
+ ): boolean {
344
+ const cloidData = parseCloid(cloidHex);
345
+ if (!cloidData) return false;
346
+ return cloidData.clientId === clientCode;
347
+ }
348
+
349
+ export function isWidgetType(
350
+ widgetType: WidgetType | number,
351
+ cloidHex: `0x${string}`,
352
+ ): boolean {
353
+ const cloidData = parseCloid(cloidHex);
354
+ if (!cloidData) return false;
355
+ return cloidData.widgetTypeId === widgetType;
356
+ }
357
+
358
+ export function isMiniAppCloid(cloidHex: `0x${string}`): boolean {
359
+ const cloidData = parseCloid(cloidHex);
360
+ if (!cloidData) return false;
361
+ return cloidData.isMiniApp;
362
+ }
363
+
364
+ export function isMiniAppTriggeredCloid(cloidHex: `0x${string}`): boolean {
365
+ const cloidData = parseCloid(cloidHex);
366
+ if (!cloidData) return false;
367
+ return cloidData.miniAppTriggered;
368
+ }
@@ -0,0 +1,60 @@
1
+ const mask = (bits: bigint) => (1n << bits) - 1n;
2
+
3
+ function getEncodingLength(nbits: bigint, alphabet: string): number {
4
+ return Math.floor(Number(nbits) / Math.log2(Number(alphabet.length)));
5
+ }
6
+
7
+ // Encode a string value into a n-bit integer
8
+ export function encodeValue(
9
+ value: string,
10
+ nbits: bigint,
11
+ alphabet: string,
12
+ ): bigint {
13
+ const encodingLength = getEncodingLength(nbits, alphabet);
14
+ if (value.length > encodingLength) {
15
+ // truncate the value
16
+ value = value.slice(0, encodingLength);
17
+ }
18
+
19
+ if (value.length < encodingLength) {
20
+ // pad the value with last character
21
+ value = value.padEnd(encodingLength, alphabet[alphabet.length - 1]);
22
+ }
23
+
24
+ const base = BigInt(alphabet.length);
25
+ let encoded = 0n;
26
+ for (const ch of value) {
27
+ const idx = alphabet.indexOf(ch);
28
+ if (idx === -1) throw new Error(`Invalid slug character: ${ch}`);
29
+ encoded = encoded * base + BigInt(idx);
30
+ }
31
+ if (encoded > Number(mask(nbits))) {
32
+ throw new Error(`Encoded value exceeds ${nbits} bits`);
33
+ }
34
+ return encoded;
35
+ }
36
+
37
+ /**
38
+ * Decode a n-bit integer back into a x-char slug
39
+ * @param value - The numeric value to decode
40
+ * @param nbits - The number of bits
41
+ * @param alphabet - The alphabet to use for decoding
42
+ * @returns The decoded value
43
+ */
44
+ export function decodeValue(
45
+ value: bigint,
46
+ nbits: bigint,
47
+ alphabet: string,
48
+ ): string {
49
+ if (value < 0 || value > Number(mask(nbits))) {
50
+ throw new Error(`Slug value out of range (must fit in ${nbits} bits)`);
51
+ }
52
+ const base = BigInt(alphabet.length);
53
+ let decoded = "";
54
+ for (let i = 0; i < getEncodingLength(nbits, alphabet); i++) {
55
+ const idx = value % base;
56
+ decoded = alphabet[Number(idx)] + decoded;
57
+ value = value / base;
58
+ }
59
+ return decoded.trim();
60
+ }
@@ -0,0 +1,2 @@
1
+ export const BASED_FEE_WALLET = "0x1924b8561eeF20e70Ede628A296175D358BE80e5";
2
+ export const BASED_REFERRAL_CODE = "SHIFU";
@@ -0,0 +1,28 @@
1
+ import { SpotToken } from "@nktkas/hyperliquid";
2
+
3
+ export const USDC_SPOT_TOKEN: SpotToken = {
4
+ name: "USDC",
5
+ szDecimals: 8,
6
+ weiDecimals: 8,
7
+ index: 0,
8
+ tokenId: "0x6d1e7cde53ba9467b783cb7c530ce054",
9
+ isCanonical: true,
10
+ evmContract: null,
11
+ fullName: null,
12
+ deployerTradingFeeShare: "0.0",
13
+ };
14
+
15
+ export const TESTNET_USDC_SPOT_TOKEN: SpotToken = {
16
+ name: "USDC",
17
+ szDecimals: 8,
18
+ weiDecimals: 8,
19
+ index: 0,
20
+ tokenId: "0xeb62eee3685fc4c43992febcd9e75443",
21
+ isCanonical: true,
22
+ evmContract: {
23
+ address: "0xd9cbec81df392a88aeff575e962d149d57f4d6bc",
24
+ evm_extra_wei_decimals: 0,
25
+ },
26
+ fullName: null,
27
+ deployerTradingFeeShare: "0.0",
28
+ };