@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.
- package/dist/chunk-4UEJOM6W.mjs +9 -0
- package/dist/index.d.mts +488 -0
- package/dist/index.d.ts +488 -2
- package/dist/index.js +37574 -2
- package/dist/index.mjs +1097 -0
- package/dist/lib/cloid.d.ts.map +1 -1
- package/dist/lib/cloid.js +11 -1
- package/dist/lib/cloid.js.map +1 -1
- package/dist/meta-52Q5UUQ4.mjs +1474 -0
- package/dist/meta-FTWJX4LV.mjs +1445 -0
- package/dist/meta-IKWYLG3Q.mjs +1316 -0
- package/dist/meta-UUXKK7IB.mjs +1355 -0
- package/dist/perpDexs-PSE3LEVV.mjs +9 -0
- package/dist/perpDexs-S3TK25EU.mjs +17 -0
- package/dist/perpDexs-TZIQ57IW.mjs +537 -0
- package/dist/perpDexs-YNEAJ3R5.mjs +7 -0
- package/dist/perpDexs-YS3QQSHW.mjs +338 -0
- package/dist/spotMeta-7IJT3W6H.mjs +6442 -0
- package/dist/spotMeta-LEO5QFNS.mjs +26392 -0
- package/dist/spotMeta-MC5UYLQ7.mjs +6335 -0
- package/dist/spotMeta-TXJWYTKI.mjs +26403 -0
- package/dist/spotMeta-VAANYV77.mjs +6346 -0
- package/dist/spotMeta-ZVBZNUUE.mjs +26559 -0
- package/dist/staticMeta-HRXST42O.mjs +24 -0
- package/dist/staticMeta-QWPQK3MD.mjs +22 -0
- package/index.ts +6 -0
- package/lib/cloid/README.md +233 -0
- package/lib/cloid/cloid.ts +368 -0
- package/lib/cloid/encoder.ts +60 -0
- package/lib/constants/fee.ts +2 -0
- package/lib/constants/tokens.ts +28 -0
- package/lib/fee.ts +105 -0
- package/lib/hip3/market-info.ts +25 -0
- package/lib/hip3/utils.ts +9 -0
- package/lib/meta/README.md +471 -0
- package/lib/meta/data/mainnet/dexs/xyz.json +26 -0
- package/lib/meta/data/mainnet/meta.json +1462 -0
- package/lib/meta/data/mainnet/perpDexs.json +11 -0
- package/lib/meta/data/mainnet/spotMeta.json +6432 -0
- package/lib/meta/data/mainnet/staticMeta.json +14 -0
- package/lib/meta/data/testnet/dexs/rrrrr.json +33 -0
- package/lib/meta/data/testnet/meta.json +1343 -0
- package/lib/meta/data/testnet/perpDexs.json +531 -0
- package/lib/meta/data/testnet/spotMeta.json +26547 -0
- package/lib/meta/data/testnet/staticMeta.json +12 -0
- package/lib/meta/metadata.ts +717 -0
- package/lib/pup/calculator.ts +221 -0
- package/lib/pup/index.ts +9 -0
- package/lib/pup/types.ts +94 -0
- package/lib/utils/formatter.ts +97 -0
- package/package.json +21 -17
- package/readme.md +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "./chunk-4UEJOM6W.mjs";
|
|
2
|
+
|
|
3
|
+
// lib/meta/data/mainnet/staticMeta.json
|
|
4
|
+
var coins = {
|
|
5
|
+
"xyz:XYZ100": {
|
|
6
|
+
imageUrl: "https://app.based.one/hip3/xyz/xyz100.webp",
|
|
7
|
+
displayName: "Nasdaq-100"
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var dexs = {
|
|
11
|
+
xyz: {
|
|
12
|
+
imageUrl: "",
|
|
13
|
+
displayName: "Stocks"
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var staticMeta_default = {
|
|
17
|
+
coins,
|
|
18
|
+
dexs
|
|
19
|
+
};
|
|
20
|
+
export {
|
|
21
|
+
coins,
|
|
22
|
+
staticMeta_default as default,
|
|
23
|
+
dexs
|
|
24
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "./chunk-4UEJOM6W.mjs";
|
|
2
|
+
|
|
3
|
+
// lib/meta/data/testnet/staticMeta.json
|
|
4
|
+
var coins = {
|
|
5
|
+
"rrrrr:BTC": {
|
|
6
|
+
displayName: "BTCe"
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var dexs = {
|
|
10
|
+
rrrrr: {
|
|
11
|
+
displayName: "Hyena"
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var staticMeta_default = {
|
|
15
|
+
coins,
|
|
16
|
+
dexs
|
|
17
|
+
};
|
|
18
|
+
export {
|
|
19
|
+
coins,
|
|
20
|
+
staticMeta_default as default,
|
|
21
|
+
dexs
|
|
22
|
+
};
|
package/index.ts
ADDED
|
@@ -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
|
+
}
|