@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,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
|
+
}
|
package/lib/pup/index.ts
ADDED
package/lib/pup/types.ts
ADDED
|
@@ -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.
|
|
3
|
+
"version": "0.0.7",
|
|
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
|
-
"
|
|
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
|
-
"
|
|
21
|
-
"vitest": "^3.2.4"
|
|
22
|
-
},
|
|
23
|
+
"packageManager": "pnpm@10.10.0",
|
|
23
24
|
"devDependencies": {
|
|
24
|
-
"
|
|
25
|
+
"tsup": "^8.5.0",
|
|
26
|
+
"tsx": "^4.19.2",
|
|
27
|
+
"typescript": "^5.0.0",
|
|
28
|
+
"vitest": "^3.2.4"
|
|
25
29
|
},
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
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
|