@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
@@ -0,0 +1,221 @@
1
+ /**
2
+ * PUP Token Calculation Logic
3
+ * Pure functions for calculating PUP amounts and boost percentages
4
+ */
5
+
6
+ import {
7
+ UpheavalPosition,
8
+ PUP_TOKEN_ADDRESS,
9
+ PUP_TOKEN_THRESHOLDS,
10
+ XP_BOOST_PERCENTAGES,
11
+ } from './types';
12
+
13
+ /**
14
+ * Calculate total PUP amount from all positions
15
+ * @param positions Array of Upheaval positions
16
+ * @returns Total PUP token amount
17
+ */
18
+ export function calculateTotalPupAmount(positions: UpheavalPosition[]): number {
19
+ let totalPupAmount = 0;
20
+ const pupAddress = PUP_TOKEN_ADDRESS.toLowerCase();
21
+
22
+ for (const position of positions) {
23
+ try {
24
+ if (position.version === 'erc20' && position.pair === 'PUP') {
25
+ // Pure PUP position - amount is in wei (18 decimals)
26
+ const amount = parseFloat(position.amount) / 1e18;
27
+ totalPupAmount += amount;
28
+ console.log(`Found pure PUP position: ${amount} PUP`);
29
+ }
30
+ else if (position.version === 'v3' && position.v3LPTokenInfo) {
31
+ // V3 LP position - check if PUP is token0 or token1
32
+ const { token0, token1 } = position.v3LPTokenInfo;
33
+
34
+ if (token0.address.toLowerCase() === pupAddress || token0.symbol === 'PUP') {
35
+ // PUP is token0 - amount is already in human-readable format
36
+ totalPupAmount += token0.amount;
37
+ console.log(`Found V3 LP position with PUP as token0: ${token0.amount} PUP`);
38
+ }
39
+ else if (token1.address.toLowerCase() === pupAddress || token1.symbol === 'PUP') {
40
+ // PUP is token1 - amount is already in human-readable format
41
+ totalPupAmount += token1.amount;
42
+ console.log(`Found V3 LP position with PUP as token1: ${token1.amount} PUP`);
43
+ }
44
+ }
45
+ // V2 LP positions excluded for security (can't verify if it's real PUP)
46
+ // As noted: "Someone can just create another PUP ERC20 token and pair it"
47
+ } catch (error) {
48
+ console.error(`Error processing position ${position.pair}:`, error);
49
+ }
50
+ }
51
+
52
+ console.log(`Total PUP amount calculated: ${totalPupAmount}`);
53
+ return totalPupAmount;
54
+ }
55
+
56
+ /**
57
+ * Calculate XP boost percentage based on PUP holdings
58
+ * @param pupTokenAmount Current PUP token holdings
59
+ * @param normalizedAirDropAmount Normalized airdrop amount (divided by 1e18)
60
+ * @param isAirdropRecipient Whether user received an airdrop
61
+ * @returns Boost percentage (0, 25, 50, or 60)
62
+ */
63
+ export function calculateBoostPercentage(
64
+ pupTokenAmount: number,
65
+ normalizedAirDropAmount: number,
66
+ isAirdropRecipient: boolean
67
+ ): number {
68
+ if (isAirdropRecipient && normalizedAirDropAmount > 0) {
69
+ // Airdrop recipients: boost based on percentage of airdrop retained
70
+ const retentionRatio = pupTokenAmount / normalizedAirDropAmount;
71
+
72
+ if (retentionRatio >= PUP_TOKEN_THRESHOLDS.AIRDROP_110_PERCENT) {
73
+ return XP_BOOST_PERCENTAGES.TIER_3; // 60%
74
+ }
75
+ if (retentionRatio >= PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT) {
76
+ return XP_BOOST_PERCENTAGES.TIER_2; // 50%
77
+ }
78
+ if (retentionRatio >= PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT) {
79
+ return XP_BOOST_PERCENTAGES.TIER_1; // 25%
80
+ }
81
+ return XP_BOOST_PERCENTAGES.NO_BOOST;
82
+ } else {
83
+ // Non-airdrop recipients: need 2M+ PUP tokens for 25% boost
84
+ if (pupTokenAmount >= PUP_TOKEN_THRESHOLDS.NON_AIRDROP_TOKENS) {
85
+ return XP_BOOST_PERCENTAGES.TIER_1; // 25%
86
+ }
87
+ return XP_BOOST_PERCENTAGES.NO_BOOST;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Normalize airdrop amount from BigInt or Prisma Decimal
93
+ * @param amount Airdrop amount from database
94
+ * @returns Normalized amount as number
95
+ */
96
+ export function normalizeAirdropAmount(
97
+ amount: bigint | { div: (divisor: number) => { toNumber: () => number } } | null | undefined
98
+ ): number {
99
+ if (!amount) return 0;
100
+
101
+ if (typeof amount === 'bigint') {
102
+ // Direct BigInt
103
+ return Number(amount) / 1e18;
104
+ } else if (amount && typeof amount.div === 'function') {
105
+ // Prisma Decimal type
106
+ return amount.div(1e18).toNumber();
107
+ }
108
+
109
+ return 0;
110
+ }
111
+
112
+ /**
113
+ * Get information about the next tier and amount needed to reach it
114
+ * @param pupTokenAmount Current PUP token holdings
115
+ * @param normalizedAirDropAmount Normalized airdrop amount (divided by 1e18)
116
+ * @param isAirdropRecipient Whether user received an airdrop
117
+ * @returns Information about current tier and progression to next tier
118
+ */
119
+ export function getNextTierInfo(
120
+ pupTokenAmount: number,
121
+ normalizedAirDropAmount: number,
122
+ isAirdropRecipient: boolean
123
+ ): {
124
+ currentTier: number;
125
+ currentBoost: number;
126
+ nextTier: number | null;
127
+ nextBoost: number | null;
128
+ amountToNextTier: number | null;
129
+ nextTierThreshold: number | null;
130
+ progressPercentage: number;
131
+ } {
132
+ const currentBoost = calculateBoostPercentage(pupTokenAmount, normalizedAirDropAmount, isAirdropRecipient);
133
+
134
+ // Determine current tier
135
+ let currentTier = 0;
136
+ if (currentBoost === XP_BOOST_PERCENTAGES.TIER_3) currentTier = 3;
137
+ else if (currentBoost === XP_BOOST_PERCENTAGES.TIER_2) currentTier = 2;
138
+ else if (currentBoost === XP_BOOST_PERCENTAGES.TIER_1) currentTier = 1;
139
+
140
+ if (isAirdropRecipient && normalizedAirDropAmount > 0) {
141
+ // Airdrop recipients: calculate based on percentage of airdrop
142
+ const retentionRatio = pupTokenAmount / normalizedAirDropAmount;
143
+
144
+ if (currentTier === 0) {
145
+ // Currently no boost, need 35% of airdrop for Tier 1
146
+ const threshold = normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT;
147
+ return {
148
+ currentTier: 0,
149
+ currentBoost: XP_BOOST_PERCENTAGES.NO_BOOST,
150
+ nextTier: 1,
151
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_1,
152
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
153
+ nextTierThreshold: threshold,
154
+ progressPercentage: Math.min(100, (pupTokenAmount / threshold) * 100)
155
+ };
156
+ } else if (currentTier === 1) {
157
+ // Currently 25% boost, need 70% of airdrop for Tier 2
158
+ const threshold = normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT;
159
+ return {
160
+ currentTier: 1,
161
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_1,
162
+ nextTier: 2,
163
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_2,
164
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
165
+ nextTierThreshold: threshold,
166
+ progressPercentage: Math.min(100, ((pupTokenAmount - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT) /
167
+ (threshold - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_35_PERCENT)) * 100)
168
+ };
169
+ } else if (currentTier === 2) {
170
+ // Currently 50% boost, need 110% of airdrop for Tier 3
171
+ const threshold = normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_110_PERCENT;
172
+ return {
173
+ currentTier: 2,
174
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_2,
175
+ nextTier: 3,
176
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_3,
177
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
178
+ nextTierThreshold: threshold,
179
+ progressPercentage: Math.min(100, ((pupTokenAmount - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT) /
180
+ (threshold - normalizedAirDropAmount * PUP_TOKEN_THRESHOLDS.AIRDROP_70_PERCENT)) * 100)
181
+ };
182
+ } else {
183
+ // Already at max tier (60% boost)
184
+ return {
185
+ currentTier: 3,
186
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_3,
187
+ nextTier: null,
188
+ nextBoost: null,
189
+ amountToNextTier: null,
190
+ nextTierThreshold: null,
191
+ progressPercentage: 100
192
+ };
193
+ }
194
+ } else {
195
+ // Non-airdrop recipients: only one tier available (25% at 2M tokens)
196
+ const threshold = PUP_TOKEN_THRESHOLDS.NON_AIRDROP_TOKENS;
197
+
198
+ if (currentTier === 0) {
199
+ return {
200
+ currentTier: 0,
201
+ currentBoost: XP_BOOST_PERCENTAGES.NO_BOOST,
202
+ nextTier: 1,
203
+ nextBoost: XP_BOOST_PERCENTAGES.TIER_1,
204
+ amountToNextTier: Math.max(0, threshold - pupTokenAmount),
205
+ nextTierThreshold: threshold,
206
+ progressPercentage: Math.min(100, (pupTokenAmount / threshold) * 100)
207
+ };
208
+ } else {
209
+ // Already at max tier for non-airdrop (25% boost)
210
+ return {
211
+ currentTier: 1,
212
+ currentBoost: XP_BOOST_PERCENTAGES.TIER_1,
213
+ nextTier: null,
214
+ nextBoost: null,
215
+ amountToNextTier: null,
216
+ nextTierThreshold: null,
217
+ progressPercentage: 100
218
+ };
219
+ }
220
+ }
221
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * PUP Module Exports
3
+ */
4
+
5
+ // Export all types
6
+ export * from './types';
7
+
8
+ // Export calculator functions
9
+ export * from './calculator';
@@ -0,0 +1,94 @@
1
+ /**
2
+ * PUP Token Eligibility Types and Constants
3
+ */
4
+
5
+ // Upheaval API Types
6
+ export interface V3LPTokenInfo {
7
+ token0: {
8
+ price: number;
9
+ value: number;
10
+ amount: number;
11
+ symbol: string;
12
+ address: string;
13
+ };
14
+ token1: {
15
+ price: number;
16
+ value: number;
17
+ amount: number;
18
+ symbol: string;
19
+ address: string;
20
+ };
21
+ }
22
+
23
+ export interface UpheavalPosition {
24
+ pair: string;
25
+ pool: string;
26
+ value: number;
27
+ amount: string;
28
+ version: 'erc20' | 'v3' | 'v2';
29
+ v3LPTokenInfo?: V3LPTokenInfo;
30
+ }
31
+
32
+ export interface UpheavalSnapshot {
33
+ id: string;
34
+ user_address: string;
35
+ total_lp_value: number;
36
+ position_count: number;
37
+ metadata: {
38
+ positions: UpheavalPosition[];
39
+ snapshot_date: string;
40
+ };
41
+ created_at: string;
42
+ userId: string | null;
43
+ }
44
+
45
+ export interface UpheavalApiResponse {
46
+ success: boolean;
47
+ snapshot: {
48
+ timestamp: string;
49
+ user_count: number;
50
+ };
51
+ data: UpheavalSnapshot[];
52
+ cached_at: string;
53
+ filtered_by: string;
54
+ }
55
+
56
+ // PUP Eligibility Types
57
+ export interface PupEligibilityResult {
58
+ isEligible: boolean;
59
+ boostPct: number;
60
+ isAirdropRecipient: boolean;
61
+ pupTokenAmount?: number;
62
+ totalLpValue?: number;
63
+ // Tier progression info
64
+ currentTier?: number;
65
+ currentBoost?: number;
66
+ nextTier?: number | null;
67
+ nextBoost?: number | null;
68
+ amountToNextTier?: number | null;
69
+ nextTierThreshold?: number | null;
70
+ progressPercentage?: number;
71
+ }
72
+
73
+ // Airdrop Allocation Data (from database)
74
+ export interface AirdropAllocationData {
75
+ amount: bigint | { div: (divisor: number) => { toNumber: () => number } };
76
+ walletAddress: string;
77
+ }
78
+
79
+ // Constants
80
+ export const PUP_TOKEN_ADDRESS = '0x876e7f2f30935118a654fc0e1f807afc49efe500';
81
+
82
+ export const PUP_TOKEN_THRESHOLDS = {
83
+ AIRDROP_70_PERCENT: 0.7,
84
+ AIRDROP_35_PERCENT: 0.35,
85
+ AIRDROP_110_PERCENT: 1.1,
86
+ NON_AIRDROP_TOKENS: 2000000,
87
+ } as const;
88
+
89
+ export const XP_BOOST_PERCENTAGES = {
90
+ NO_BOOST: 0,
91
+ TIER_1: 25,
92
+ TIER_2: 50,
93
+ TIER_3: 60,
94
+ } as const;
@@ -0,0 +1,97 @@
1
+ import { Decimal } from "decimal.js";
2
+
3
+ export const formatPriceAndSize = ({
4
+ px,
5
+ sz,
6
+ szDecimals,
7
+ isSpot,
8
+ }: {
9
+ px: number;
10
+ sz: number;
11
+ szDecimals: number;
12
+ isSpot: boolean;
13
+ }) => {
14
+ const priceDecimals = getPriceDecimals(px, szDecimals, isSpot);
15
+
16
+ const price = new Decimal(px).toDP(priceDecimals).toNumber();
17
+ const size = new Decimal(sz).toDP(szDecimals, Decimal.ROUND_DOWN).toNumber();
18
+
19
+ return {
20
+ price,
21
+ size,
22
+ };
23
+ };
24
+
25
+ /**
26
+ * Formats price for order placement following Hyperliquid rules
27
+ * - Rounded to priceDecimals of the asset
28
+ * @param px - The price to format
29
+ * @param priceDecimals - Price decimals for the asset
30
+ * @returns Formatted price as number (rounded to priceDecimals if exceeds)
31
+ */
32
+ export const formatPriceForOrder = ({
33
+ px,
34
+ szDecimals,
35
+ isSpot,
36
+ }: {
37
+ px: number;
38
+ szDecimals: number;
39
+ isSpot: boolean;
40
+ }) => {
41
+ const priceDecimals = getPriceDecimals(px, szDecimals, isSpot);
42
+ const price = new Decimal(px).toDP(priceDecimals).toNumber();
43
+
44
+ return price;
45
+ };
46
+
47
+ /**
48
+ * Formats size for order placement following Hyperliquid rules
49
+ * - Rounded to szDecimals of the asset
50
+ * @param sz - The size to format
51
+ * @param szDecimals - Size decimals for the asset
52
+ * @returns Formatted size as number (rounded down to szDecimals if exceeds)
53
+ */
54
+ export const formatSizeForOrder = ({
55
+ sz,
56
+ szDecimals,
57
+ }: {
58
+ sz: number;
59
+ szDecimals: number;
60
+ }) => {
61
+ return new Decimal(sz).toDP(szDecimals, Decimal.ROUND_DOWN).toNumber();
62
+ };
63
+
64
+ /**
65
+ * Get minimum price decimals for tick size calculations
66
+ * Uses the same logic as internal price formatting
67
+ *
68
+ * @param price - The current price
69
+ * @param szDecimals - Size decimals for the asset
70
+ * @param isSpot - Whether this is a spot market (true) or perp market (false)
71
+ * @returns Minimum decimal places for price display
72
+ *
73
+ * @example
74
+ * getPriceDecimals(1234.5, 0, false) // 1 (PERP market)
75
+ * getPriceDecimals(0.00123, 0, true) // 6 (SPOT market)
76
+ * getPriceDecimals(100000, 0, false) // 0 (large prices)
77
+ */
78
+ export function getPriceDecimals(
79
+ price: number,
80
+ szDecimals: number,
81
+ isSpot: boolean,
82
+ ): number {
83
+ const baseDecimals = isSpot ? 8 : 6; // SPOT: 8, PERP: 6
84
+ const maxDP = Math.max(baseDecimals - szDecimals, 0);
85
+ const maxSigFigs = 5;
86
+
87
+ let minDecimals: number;
88
+ if (price >= 100000) {
89
+ minDecimals = 0;
90
+ } else {
91
+ const exp = Math.floor(Math.log10(price));
92
+ const dp = Math.max(maxSigFigs - exp - 1, 0);
93
+ minDecimals = Math.min(dp, maxDP);
94
+ }
95
+
96
+ return minDecimals;
97
+ }
package/package.json CHANGED
@@ -1,30 +1,34 @@
1
1
  {
2
2
  "name": "@basedone/core",
3
- "version": "0.0.1",
3
+ "version": "0.0.6",
4
4
  "description": "Core utilities for Based One",
5
5
  "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
6
7
  "types": "./dist/index.d.ts",
7
- "exports": {
8
- ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.js",
11
- "require": "./dist/index.js"
12
- }
13
- },
8
+ "source": "./index.ts",
14
9
  "files": [
15
- "dist"
10
+ "dist",
11
+ "index.ts",
12
+ "lib"
16
13
  ],
14
+ "scripts": {
15
+ "build": "tsup index.ts --format cjs,esm --dts",
16
+ "dev": "tsup index.ts --format cjs,esm --dts --watch",
17
+ "test": "vitest",
18
+ "update-meta": "tsx scripts/update-static-meta.ts"
19
+ },
17
20
  "keywords": [],
18
21
  "author": "",
19
22
  "license": "ISC",
20
- "dependencies": {
21
- "vitest": "^3.2.4"
22
- },
23
+ "packageManager": "pnpm@10.10.0",
23
24
  "devDependencies": {
24
- "typescript": "^5.0.0"
25
+ "tsup": "^8.5.0",
26
+ "tsx": "^4.19.2",
27
+ "typescript": "^5.0.0",
28
+ "vitest": "^3.2.4"
25
29
  },
26
- "scripts": {
27
- "build": "tsc",
28
- "test": "vitest"
30
+ "dependencies": {
31
+ "@nktkas/hyperliquid": "^0.24.3",
32
+ "decimal.js": "^10.6.0"
29
33
  }
30
- }
34
+ }
package/readme.md ADDED
File without changes