@basedone/core 0.1.8 → 0.2.0
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-4GAKANLT.mjs +1987 -0
- package/dist/chunk-4UEJOM6W.mjs +1 -3
- package/dist/chunk-VBC6EQ7Q.mjs +235 -0
- package/dist/client-CgmiTuEX.d.mts +179 -0
- package/dist/client-CgmiTuEX.d.ts +179 -0
- package/dist/ecommerce.d.mts +3732 -0
- package/dist/ecommerce.d.ts +3732 -0
- package/dist/ecommerce.js +2031 -0
- package/dist/ecommerce.mjs +2 -0
- package/dist/index.d.mts +79 -4
- package/dist/index.d.ts +79 -4
- package/dist/index.js +3674 -331
- package/dist/index.mjs +107 -104
- package/dist/{meta-57AY44US.mjs → meta-JB5ITE27.mjs} +6 -14
- package/dist/{meta-RSZFFH63.mjs → meta-UOGUG3OW.mjs} +5 -11
- package/dist/{perpDexs-PBKWKKQU.mjs → perpDexs-3LRJ5ZHM.mjs} +100 -13
- package/dist/{perpDexs-XSB4Y2BP.mjs → perpDexs-4ISLD7NX.mjs} +798 -121
- package/dist/react.d.mts +39 -0
- package/dist/react.d.ts +39 -0
- package/dist/react.js +268 -0
- package/dist/react.mjs +31 -0
- package/dist/{spotMeta-WQ4PXRNY.mjs → spotMeta-GHXX7C5M.mjs} +85 -14
- package/dist/{spotMeta-Y7G2GI7B.mjs → spotMeta-IBBUP2SG.mjs} +249 -12
- package/dist/staticMeta-GM7T3OYL.mjs +3 -6
- package/dist/staticMeta-QV2KMX57.mjs +3 -6
- package/ecommerce.ts +15 -0
- package/index.ts +7 -0
- package/lib/cloid/cloid.ts +2 -0
- package/lib/ecommerce/QUICK_REFERENCE.md +211 -0
- package/lib/ecommerce/README.md +385 -0
- package/lib/ecommerce/USAGE_EXAMPLES.md +704 -0
- package/lib/ecommerce/client/base.ts +272 -0
- package/lib/ecommerce/client/customer.ts +522 -0
- package/lib/ecommerce/client/merchant.ts +1341 -0
- package/lib/ecommerce/index.ts +51 -0
- package/lib/ecommerce/types/entities.ts +722 -0
- package/lib/ecommerce/types/enums.ts +270 -0
- package/lib/ecommerce/types/index.ts +18 -0
- package/lib/ecommerce/types/requests.ts +525 -0
- package/lib/ecommerce/types/responses.ts +805 -0
- package/lib/ecommerce/utils/errors.ts +113 -0
- package/lib/ecommerce/utils/helpers.ts +131 -0
- package/lib/fee.ts +10 -10
- package/lib/hip3/market-info.ts +36 -8
- package/lib/hip3/utils.ts +15 -2
- package/lib/instrument/client.ts +351 -0
- package/lib/meta/data/mainnet/meta.json +2 -4
- package/lib/meta/data/mainnet/perpDexs.json +97 -9
- package/lib/meta/data/mainnet/spotMeta.json +82 -8
- package/lib/meta/data/testnet/meta.json +3 -7
- package/lib/meta/data/testnet/perpDexs.json +795 -117
- package/lib/meta/data/testnet/spotMeta.json +246 -6
- package/lib/meta/metadata.ts +8 -1
- package/lib/meta/types.ts +36 -0
- package/lib/react/InstrumentProvider.tsx +69 -0
- package/lib/utils/flooredDateTime.ts +55 -0
- package/lib/utils/time.ts +51 -0
- package/package.json +37 -11
- package/react.ts +1 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ecommerce API Error Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module contains error handling utilities for the ecommerce API.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ecommerce API error class
|
|
9
|
+
*/
|
|
10
|
+
export class EcommerceApiError extends Error {
|
|
11
|
+
/** HTTP status code */
|
|
12
|
+
public statusCode?: number;
|
|
13
|
+
|
|
14
|
+
/** Response data */
|
|
15
|
+
public data?: any;
|
|
16
|
+
|
|
17
|
+
/** Is network error */
|
|
18
|
+
public isNetworkError: boolean;
|
|
19
|
+
|
|
20
|
+
/** Is timeout error */
|
|
21
|
+
public isTimeoutError: boolean;
|
|
22
|
+
|
|
23
|
+
/** Is authentication error */
|
|
24
|
+
public isAuthError: boolean;
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
message: string,
|
|
28
|
+
statusCode?: number,
|
|
29
|
+
data?: any,
|
|
30
|
+
isNetworkError = false,
|
|
31
|
+
isTimeoutError = false
|
|
32
|
+
) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = "EcommerceApiError";
|
|
35
|
+
this.statusCode = statusCode;
|
|
36
|
+
this.data = data;
|
|
37
|
+
this.isNetworkError = isNetworkError;
|
|
38
|
+
this.isTimeoutError = isTimeoutError;
|
|
39
|
+
this.isAuthError = statusCode === 401 || statusCode === 403;
|
|
40
|
+
|
|
41
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
42
|
+
if (Error.captureStackTrace) {
|
|
43
|
+
Error.captureStackTrace(this, EcommerceApiError);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse error from axios error or API response
|
|
50
|
+
*/
|
|
51
|
+
export function parseError(error: any): EcommerceApiError {
|
|
52
|
+
// Network error
|
|
53
|
+
if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") {
|
|
54
|
+
return new EcommerceApiError(
|
|
55
|
+
"Request timeout",
|
|
56
|
+
undefined,
|
|
57
|
+
undefined,
|
|
58
|
+
false,
|
|
59
|
+
true
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (error.code === "ERR_NETWORK" || !error.response) {
|
|
64
|
+
return new EcommerceApiError(
|
|
65
|
+
error.message || "Network error",
|
|
66
|
+
undefined,
|
|
67
|
+
undefined,
|
|
68
|
+
true,
|
|
69
|
+
false
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// API error
|
|
74
|
+
const response = error.response;
|
|
75
|
+
const statusCode = response?.status;
|
|
76
|
+
const data = response?.data;
|
|
77
|
+
|
|
78
|
+
const message =
|
|
79
|
+
data?.error ||
|
|
80
|
+
data?.message ||
|
|
81
|
+
error.message ||
|
|
82
|
+
`API error (${statusCode})`;
|
|
83
|
+
|
|
84
|
+
return new EcommerceApiError(message, statusCode, data);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Check if error is retryable
|
|
89
|
+
*/
|
|
90
|
+
export function isRetryableError(error: EcommerceApiError): boolean {
|
|
91
|
+
// Retry on network errors
|
|
92
|
+
if (error.isNetworkError) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Retry on timeout
|
|
97
|
+
if (error.isTimeoutError) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Retry on 5xx errors
|
|
102
|
+
if (error.statusCode && error.statusCode >= 500) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Retry on 429 (rate limit)
|
|
107
|
+
if (error.statusCode === 429) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ecommerce API Helper Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module contains helper functions for the ecommerce API.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build query string from params object
|
|
9
|
+
*/
|
|
10
|
+
export function buildQueryString(params: Record<string, any>): string {
|
|
11
|
+
const searchParams = new URLSearchParams();
|
|
12
|
+
|
|
13
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
14
|
+
if (value !== undefined && value !== null) {
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
// Handle arrays (e.g., ids, tags)
|
|
17
|
+
searchParams.append(key, value.join(","));
|
|
18
|
+
} else {
|
|
19
|
+
searchParams.append(key, String(value));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const queryString = searchParams.toString();
|
|
25
|
+
return queryString ? `?${queryString}` : "";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sleep for specified milliseconds
|
|
30
|
+
*/
|
|
31
|
+
export function sleep(ms: number): Promise<void> {
|
|
32
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Calculate exponential backoff delay
|
|
37
|
+
*/
|
|
38
|
+
export function getBackoffDelay(attempt: number, baseDelay = 1000): number {
|
|
39
|
+
return Math.min(baseDelay * Math.pow(2, attempt), 30000);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Retry function with exponential backoff
|
|
44
|
+
*/
|
|
45
|
+
export async function retryWithBackoff<T>(
|
|
46
|
+
fn: () => Promise<T>,
|
|
47
|
+
maxRetries = 3,
|
|
48
|
+
baseDelay = 1000,
|
|
49
|
+
shouldRetry?: (error: any) => boolean
|
|
50
|
+
): Promise<T> {
|
|
51
|
+
let lastError: any;
|
|
52
|
+
|
|
53
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
54
|
+
try {
|
|
55
|
+
return await fn();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
lastError = error;
|
|
58
|
+
|
|
59
|
+
// Check if we should retry
|
|
60
|
+
if (attempt < maxRetries && (!shouldRetry || shouldRetry(error))) {
|
|
61
|
+
const delay = getBackoffDelay(attempt, baseDelay);
|
|
62
|
+
await sleep(delay);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
throw lastError;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Format price for display
|
|
75
|
+
*/
|
|
76
|
+
export function formatPrice(price: string | number, decimals = 2): string {
|
|
77
|
+
const num = typeof price === "string" ? parseFloat(price) : price;
|
|
78
|
+
return num.toFixed(decimals);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Validate email address
|
|
83
|
+
*/
|
|
84
|
+
export function isValidEmail(email: string): boolean {
|
|
85
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
86
|
+
return emailRegex.test(email);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Validate Ethereum address
|
|
91
|
+
*/
|
|
92
|
+
export function isValidAddress(address: string): boolean {
|
|
93
|
+
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Truncate address for display
|
|
98
|
+
*/
|
|
99
|
+
export function truncateAddress(address: string, start = 6, end = 4): string {
|
|
100
|
+
if (!address || address.length < start + end) {
|
|
101
|
+
return address;
|
|
102
|
+
}
|
|
103
|
+
return `${address.slice(0, start)}...${address.slice(-end)}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Calculate discount amount
|
|
108
|
+
*/
|
|
109
|
+
export function calculateDiscountAmount(
|
|
110
|
+
price: number,
|
|
111
|
+
discountType: "PERCENTAGE" | "FIXED_AMOUNT",
|
|
112
|
+
discountValue: number
|
|
113
|
+
): number {
|
|
114
|
+
if (discountType === "PERCENTAGE") {
|
|
115
|
+
return (price * discountValue) / 100;
|
|
116
|
+
}
|
|
117
|
+
return Math.min(discountValue, price);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Calculate final price after discount
|
|
122
|
+
*/
|
|
123
|
+
export function calculateFinalPrice(
|
|
124
|
+
price: number,
|
|
125
|
+
discountType: "PERCENTAGE" | "FIXED_AMOUNT",
|
|
126
|
+
discountValue: number
|
|
127
|
+
): number {
|
|
128
|
+
const discountAmount = calculateDiscountAmount(price, discountType, discountValue);
|
|
129
|
+
return Math.max(0, price - discountAmount);
|
|
130
|
+
}
|
|
131
|
+
|
package/lib/fee.ts
CHANGED
|
@@ -15,8 +15,8 @@ export const TARGET_APPROVED_MAX_BUILDER_FEE_PERCENT = `0.1%`;
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Get the amount of builder fee to approve for
|
|
18
|
-
* @param perpetualTradingFee - Perp fee in percentage
|
|
19
|
-
* @param spotTradingFee - Spot fee in percentage
|
|
18
|
+
* @param perpetualTradingFee - Perp fee in percentage (0.025 means 0.025% perp fee)
|
|
19
|
+
* @param spotTradingFee - Spot fee in percentage (0.01 means 0.01% spot fee)
|
|
20
20
|
* @param feeDiscount - Discount fee in percentage (0.9 means 90% discount)
|
|
21
21
|
* @returns {
|
|
22
22
|
* amount: number; - The amount of builder fee to approve in 1/10 of a basis point
|
|
@@ -75,19 +75,19 @@ export const getApprovalAmount = ({
|
|
|
75
75
|
.mul(discountMultiplier)
|
|
76
76
|
.toNumber();
|
|
77
77
|
|
|
78
|
-
// ensure perp fee is either 0 or between 0.
|
|
79
|
-
if (validatedPerpFeePct > 0 && validatedPerpFeePct < 0.
|
|
80
|
-
console.warn("Perp fee is less than 0.
|
|
81
|
-
validatedPerpFeePct = 0.
|
|
82
|
-
}
|
|
83
|
-
if (validatedPerpFeePct < 0) {
|
|
84
|
-
console.warn("Perp fee is less than 0, setting to 0");
|
|
85
|
-
validatedPerpFeePct = 0;
|
|
78
|
+
// ensure perp fee is either 0 or between 0.001%
|
|
79
|
+
if (validatedPerpFeePct > 0 && validatedPerpFeePct < 0.001) {
|
|
80
|
+
console.warn("Perp fee is less than 0.001%, setting to 0.001%");
|
|
81
|
+
validatedPerpFeePct = 0.001;
|
|
86
82
|
}
|
|
87
83
|
if (validatedPerpFeePct > 0.1) {
|
|
88
84
|
console.warn("Perp fee is greater than 0.1%, setting to 0.1%");
|
|
89
85
|
validatedPerpFeePct = 0.1;
|
|
90
86
|
}
|
|
87
|
+
if (validatedPerpFeePct < 0) {
|
|
88
|
+
console.warn("Perp fee is less than 0, setting to 0");
|
|
89
|
+
validatedPerpFeePct = 0;
|
|
90
|
+
}
|
|
91
91
|
|
|
92
92
|
let validatedSpotFeePct = spotTradingFee;
|
|
93
93
|
|
package/lib/hip3/market-info.ts
CHANGED
|
@@ -1,17 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InfoClient, PerpsAssetCtx, MarginTables } from "@nktkas/hyperliquid";
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
collateralToken
|
|
5
|
-
|
|
3
|
+
export interface PerpsMeta {
|
|
4
|
+
collateralToken: number;
|
|
5
|
+
/** Trading universes available for perpetual trading. */
|
|
6
|
+
universe: PerpsUniverse[];
|
|
7
|
+
/** Margin requirement tables for different leverage tiers. */
|
|
8
|
+
marginTables: MarginTables;
|
|
9
|
+
}
|
|
10
|
+
/** Metadata and context for perpetual assets. */
|
|
11
|
+
export type PerpsMetaAndAssetCtxs = [
|
|
12
|
+
/** Metadata for assets. */
|
|
13
|
+
PerpsMeta,
|
|
14
|
+
/** Context for each perpetual asset. */
|
|
15
|
+
PerpsAssetCtx[],
|
|
16
|
+
];
|
|
17
|
+
/** Trading universe parameters for perpetual assets. */
|
|
18
|
+
export interface PerpsUniverse {
|
|
19
|
+
/** Minimum decimal places for order sizes. */
|
|
20
|
+
szDecimals: number;
|
|
21
|
+
/** Name of the universe. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Maximum allowed leverage. */
|
|
24
|
+
maxLeverage: number;
|
|
25
|
+
/** Unique identifier for the margin requirements table. */
|
|
26
|
+
marginTableId: number;
|
|
27
|
+
/** Indicates if only isolated margin trading is allowed. */
|
|
28
|
+
onlyIsolated?: true;
|
|
29
|
+
/** Indicates if the universe is delisted. */
|
|
30
|
+
isDelisted?: true;
|
|
31
|
+
/** Indicates if the universe is in growth mode, eligible for discounted fees */
|
|
32
|
+
growthMode?: "enabled";
|
|
33
|
+
/** Margin mode for the universe. */
|
|
34
|
+
marginMode?: "strictIsolated" | "noCross";
|
|
35
|
+
}
|
|
6
36
|
|
|
7
|
-
export type AllPerpsMeta =
|
|
37
|
+
export type AllPerpsMeta = PerpsMeta[];
|
|
8
38
|
|
|
9
39
|
export async function getAllPerpsMeta(
|
|
10
40
|
infoClient: InfoClient,
|
|
11
41
|
): Promise<AllPerpsMeta> {
|
|
12
42
|
return infoClient.transport.request<AllPerpsMeta>("info", {
|
|
13
|
-
|
|
14
|
-
type: "allPerpMetas",
|
|
15
|
-
},
|
|
43
|
+
type: "allPerpMetas",
|
|
16
44
|
});
|
|
17
45
|
}
|
package/lib/hip3/utils.ts
CHANGED
|
@@ -99,7 +99,7 @@ export async function getHip3DexAbstraction(client: InfoClient, user: string) {
|
|
|
99
99
|
|
|
100
100
|
const dexToCollateralTokenSymbol = {
|
|
101
101
|
rrrrr: "USDEEE",
|
|
102
|
-
|
|
102
|
+
hyna: "USDE",
|
|
103
103
|
flx: "USDH",
|
|
104
104
|
vntl: "USDH",
|
|
105
105
|
};
|
|
@@ -150,7 +150,20 @@ export function getDisplayMarketSymbol(
|
|
|
150
150
|
showCollateralTokenSymbol: boolean = true,
|
|
151
151
|
collateralTokenSymbol?: string,
|
|
152
152
|
) {
|
|
153
|
-
if (!coin
|
|
153
|
+
if (!coin) return coin;
|
|
154
|
+
|
|
155
|
+
if (isSpotSymbol(coin)) {
|
|
156
|
+
if (coin.includes("/")) {
|
|
157
|
+
const [baseToken, quoteToken] = coin.split("/");
|
|
158
|
+
|
|
159
|
+
if (showCollateralTokenSymbol) {
|
|
160
|
+
return `${baseToken}/${collateralTokenSymbol ?? quoteToken}`;
|
|
161
|
+
} else {
|
|
162
|
+
return baseToken;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return coin;
|
|
166
|
+
}
|
|
154
167
|
|
|
155
168
|
if (isHip3Symbol(coin)) {
|
|
156
169
|
const [_, symbol] = coin.split(":");
|