@yuants/vendor-hyperliquid 0.9.9 → 0.10.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/api/client.js +36 -2
- package/dist/api/client.js.map +1 -1
- package/dist/api/private-api.js +52 -41
- package/dist/api/private-api.js.map +1 -1
- package/dist/api/public-api.js +22 -11
- package/dist/api/public-api.js.map +1 -1
- package/dist/api/rate-limit.js +205 -0
- package/dist/api/rate-limit.js.map +1 -0
- package/dist/api/rate-limit.test.js +129 -0
- package/dist/api/rate-limit.test.js.map +1 -0
- package/dist/api/sign.js.map +1 -1
- package/dist/api/types.js.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/services/accounts/spot.js.map +1 -1
- package/dist/services/exchange.js.map +1 -1
- package/dist/services/markets/quote.js.map +1 -1
- package/dist/services/ohlc-service.js.map +1 -1
- package/dist/services/orders/cancelOrder.js.map +1 -1
- package/dist/services/orders/listOrders.js +2 -2
- package/dist/services/orders/listOrders.js.map +1 -1
- package/dist/services/orders/modifyOrder.js.map +1 -1
- package/dist/services/quotes.js.map +1 -1
- package/dist/services/utils.js.map +1 -1
- package/lib/api/client.d.ts +1 -1
- package/lib/api/client.d.ts.map +1 -1
- package/lib/api/client.js +35 -1
- package/lib/api/client.js.map +1 -1
- package/lib/api/private-api.d.ts +67 -3
- package/lib/api/private-api.d.ts.map +1 -1
- package/lib/api/private-api.js +59 -43
- package/lib/api/private-api.js.map +1 -1
- package/lib/api/public-api.d.ts +61 -11
- package/lib/api/public-api.d.ts.map +1 -1
- package/lib/api/public-api.js +33 -12
- package/lib/api/public-api.js.map +1 -1
- package/lib/api/rate-limit.d.ts +21 -0
- package/lib/api/rate-limit.d.ts.map +1 -0
- package/lib/api/rate-limit.js +214 -0
- package/lib/api/rate-limit.js.map +1 -0
- package/lib/api/rate-limit.test.d.ts +2 -0
- package/lib/api/rate-limit.test.d.ts.map +1 -0
- package/lib/api/rate-limit.test.js +131 -0
- package/lib/api/rate-limit.test.js.map +1 -0
- package/lib/api/sign.js +5 -6
- package/lib/api/sign.js.map +1 -1
- package/lib/api/types.d.ts.map +1 -1
- package/lib/api/types.js.map +1 -1
- package/lib/index.d.ts +0 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -2
- package/lib/index.js.map +1 -1
- package/lib/services/accounts/perp.d.ts.map +1 -1
- package/lib/services/accounts/spot.d.ts.map +1 -1
- package/lib/services/accounts/spot.js.map +1 -1
- package/lib/services/exchange.js.map +1 -1
- package/lib/services/markets/product.d.ts.map +1 -1
- package/lib/services/markets/quote.js.map +1 -1
- package/lib/services/ohlc-service.js.map +1 -1
- package/lib/services/orders/cancelOrder.d.ts.map +1 -1
- package/lib/services/orders/cancelOrder.js.map +1 -1
- package/lib/services/orders/listOrders.d.ts.map +1 -1
- package/lib/services/orders/listOrders.js +2 -2
- package/lib/services/orders/listOrders.js.map +1 -1
- package/lib/services/orders/modifyOrder.d.ts.map +1 -1
- package/lib/services/orders/modifyOrder.js.map +1 -1
- package/lib/services/orders/submitOrder.d.ts.map +1 -1
- package/lib/services/quotes.js.map +1 -1
- package/lib/services/utils.d.ts +2 -2
- package/lib/services/utils.d.ts.map +1 -1
- package/lib/services/utils.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +48 -48
- package/temp/build/typescript/ts_HOjXkPSo.json +1 -0
- package/temp/package-deps.json +27 -27
- package/temp/test/jest/haste-map-1a3370ad4952cc1cbecf8fc42c6e9732-7b2990dcc44090c4eba2c52e971c544c-6a2a6e27ca3579da37751287ea19ab4c +0 -0
- package/temp/test/jest/perf-cache-1a3370ad4952cc1cbecf8fc42c6e9732-da39a3ee5e6b4b0d3255bfef95601890 +1 -0
- package/temp/vendor-hyperliquid.api.json +18 -2
- package/dist/services/markets/interest-rate.js +0 -60
- package/dist/services/markets/interest-rate.js.map +0 -1
- package/dist/services/markets/ohlc.js +0 -110
- package/dist/services/markets/ohlc.js.map +0 -1
- package/lib/services/markets/interest-rate.d.ts +0 -2
- package/lib/services/markets/interest-rate.d.ts.map +0 -1
- package/lib/services/markets/interest-rate.js +0 -62
- package/lib/services/markets/interest-rate.js.map +0 -1
- package/lib/services/markets/ohlc.d.ts +0 -2
- package/lib/services/markets/ohlc.d.ts.map +0 -1
- package/lib/services/markets/ohlc.js +0 -112
- package/lib/services/markets/ohlc.js.map +0 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { newError, scopeError, tokenBucket } from '@yuants/utils';
|
|
2
|
+
const REST_IP_BUCKET_ID = 'HYPERLIQUID_REST_IP_WEIGHT_1200_PER_MIN';
|
|
3
|
+
const REST_IP_BUCKET_CAPACITY = 1200;
|
|
4
|
+
const REST_IP_WEIGHT_MAX = REST_IP_BUCKET_CAPACITY * 10;
|
|
5
|
+
tokenBucket(REST_IP_BUCKET_ID, {
|
|
6
|
+
capacity: REST_IP_BUCKET_CAPACITY,
|
|
7
|
+
refillInterval: 60000,
|
|
8
|
+
refillAmount: 1200,
|
|
9
|
+
});
|
|
10
|
+
const INFO_TYPE_TO_BASE_WEIGHT = {
|
|
11
|
+
l2Book: 2,
|
|
12
|
+
allMids: 2,
|
|
13
|
+
clearinghouseState: 2,
|
|
14
|
+
orderStatus: 2,
|
|
15
|
+
spotClearinghouseState: 2,
|
|
16
|
+
exchangeStatus: 2,
|
|
17
|
+
userRole: 60,
|
|
18
|
+
};
|
|
19
|
+
const INTERVAL_TO_MS = {
|
|
20
|
+
'1m': 60000,
|
|
21
|
+
'3m': 180000,
|
|
22
|
+
'5m': 300000,
|
|
23
|
+
'15m': 900000,
|
|
24
|
+
'30m': 1800000,
|
|
25
|
+
'1h': 3600000,
|
|
26
|
+
'2h': 7200000,
|
|
27
|
+
'4h': 14400000,
|
|
28
|
+
'8h': 28800000,
|
|
29
|
+
'12h': 43200000,
|
|
30
|
+
'1d': 86400000,
|
|
31
|
+
'3d': 259200000,
|
|
32
|
+
'1w': 604800000,
|
|
33
|
+
'1M': 2592000000,
|
|
34
|
+
};
|
|
35
|
+
const getObject = (value) => {
|
|
36
|
+
if (typeof value !== 'object' || value === null)
|
|
37
|
+
return;
|
|
38
|
+
return value;
|
|
39
|
+
};
|
|
40
|
+
const getString = (value) => {
|
|
41
|
+
if (typeof value !== 'string')
|
|
42
|
+
return;
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
const getNumber = (value) => {
|
|
46
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
47
|
+
return;
|
|
48
|
+
return value;
|
|
49
|
+
};
|
|
50
|
+
const getArray = (value) => {
|
|
51
|
+
if (!Array.isArray(value))
|
|
52
|
+
return;
|
|
53
|
+
return value;
|
|
54
|
+
};
|
|
55
|
+
export const getRestRequestContext = (method, path, body) => {
|
|
56
|
+
var _a, _b;
|
|
57
|
+
if (method === 'POST' && path === 'info') {
|
|
58
|
+
const obj = getObject(body);
|
|
59
|
+
const infoType = getString(obj === null || obj === void 0 ? void 0 : obj.type);
|
|
60
|
+
return { method, path, body, kind: 'info', infoType };
|
|
61
|
+
}
|
|
62
|
+
if (method === 'POST' && path === 'exchange') {
|
|
63
|
+
const obj = getObject(body);
|
|
64
|
+
const action = getObject(obj === null || obj === void 0 ? void 0 : obj.action);
|
|
65
|
+
const exchangeActionType = getString(action === null || action === void 0 ? void 0 : action.type);
|
|
66
|
+
const orders = getArray(action === null || action === void 0 ? void 0 : action.orders);
|
|
67
|
+
const cancels = getArray(action === null || action === void 0 ? void 0 : action.cancels);
|
|
68
|
+
const exchangeBatchLength = Math.max(1, (_b = (_a = orders === null || orders === void 0 ? void 0 : orders.length) !== null && _a !== void 0 ? _a : cancels === null || cancels === void 0 ? void 0 : cancels.length) !== null && _b !== void 0 ? _b : 1);
|
|
69
|
+
return { method, path, body, kind: 'exchange', exchangeActionType, exchangeBatchLength };
|
|
70
|
+
}
|
|
71
|
+
if (path.startsWith('explorer')) {
|
|
72
|
+
return { method, path, body, kind: 'explorer' };
|
|
73
|
+
}
|
|
74
|
+
return { method, path, body, kind: 'other' };
|
|
75
|
+
};
|
|
76
|
+
export const getRestBaseWeight = (ctx) => {
|
|
77
|
+
var _a, _b, _c;
|
|
78
|
+
if (ctx.kind === 'exchange') {
|
|
79
|
+
const batchLength = Math.max(1, (_a = ctx.exchangeBatchLength) !== null && _a !== void 0 ? _a : 1);
|
|
80
|
+
return 1 + Math.floor(batchLength / 40);
|
|
81
|
+
}
|
|
82
|
+
if (ctx.kind === 'info') {
|
|
83
|
+
return (_c = INFO_TYPE_TO_BASE_WEIGHT[(_b = ctx.infoType) !== null && _b !== void 0 ? _b : '']) !== null && _c !== void 0 ? _c : 20;
|
|
84
|
+
}
|
|
85
|
+
if (ctx.kind === 'explorer') {
|
|
86
|
+
return 40;
|
|
87
|
+
}
|
|
88
|
+
return 20;
|
|
89
|
+
};
|
|
90
|
+
const estimateCandleSnapshotItems = (ctx) => {
|
|
91
|
+
var _a;
|
|
92
|
+
if (ctx.kind !== 'info' || ctx.infoType !== 'candleSnapshot')
|
|
93
|
+
return 0;
|
|
94
|
+
const bodyObj = getObject(ctx.body);
|
|
95
|
+
const reqObj = getObject(bodyObj === null || bodyObj === void 0 ? void 0 : bodyObj.req);
|
|
96
|
+
const interval = getString(reqObj === null || reqObj === void 0 ? void 0 : reqObj.interval);
|
|
97
|
+
const startTime = getNumber(reqObj === null || reqObj === void 0 ? void 0 : reqObj.startTime);
|
|
98
|
+
const endTime = getNumber(reqObj === null || reqObj === void 0 ? void 0 : reqObj.endTime);
|
|
99
|
+
if (!interval || startTime === undefined || endTime === undefined || endTime <= startTime)
|
|
100
|
+
return 0;
|
|
101
|
+
const intervalMs = (_a = INTERVAL_TO_MS[interval]) !== null && _a !== void 0 ? _a : 0;
|
|
102
|
+
if (!intervalMs)
|
|
103
|
+
return 0;
|
|
104
|
+
// Hyperliquid docs: Only the most recent 5000 candles are available
|
|
105
|
+
const estimated = Math.ceil((endTime - startTime) / intervalMs);
|
|
106
|
+
return Math.min(5000, Math.max(0, estimated));
|
|
107
|
+
};
|
|
108
|
+
const countArrayResponseItems = (response) => {
|
|
109
|
+
var _a;
|
|
110
|
+
const arr = getArray(response);
|
|
111
|
+
return (_a = arr === null || arr === void 0 ? void 0 : arr.length) !== null && _a !== void 0 ? _a : 0;
|
|
112
|
+
};
|
|
113
|
+
const countUserFillsItems = (response) => {
|
|
114
|
+
var _a;
|
|
115
|
+
const obj = getObject(response);
|
|
116
|
+
const fills = getArray(obj === null || obj === void 0 ? void 0 : obj.fills);
|
|
117
|
+
return (_a = fills === null || fills === void 0 ? void 0 : fills.length) !== null && _a !== void 0 ? _a : 0;
|
|
118
|
+
};
|
|
119
|
+
const extraWeighers = [
|
|
120
|
+
{
|
|
121
|
+
match: (ctx) => ctx.kind === 'info' && ctx.infoType === 'candleSnapshot',
|
|
122
|
+
divisor: 60,
|
|
123
|
+
estimateItems: estimateCandleSnapshotItems,
|
|
124
|
+
countItemsFromResponse: countArrayResponseItems,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
match: (ctx) => ctx.kind === 'info' &&
|
|
128
|
+
(ctx.infoType === 'recentTrades' ||
|
|
129
|
+
ctx.infoType === 'historicalOrders' ||
|
|
130
|
+
ctx.infoType === 'userFills' ||
|
|
131
|
+
ctx.infoType === 'userFillsByTime' ||
|
|
132
|
+
ctx.infoType === 'fundingHistory' ||
|
|
133
|
+
ctx.infoType === 'userFunding' ||
|
|
134
|
+
ctx.infoType === 'nonUserFundingUpdates' ||
|
|
135
|
+
ctx.infoType === 'twapHistory' ||
|
|
136
|
+
ctx.infoType === 'userTwapSliceFills' ||
|
|
137
|
+
ctx.infoType === 'userTwapSliceFillsByTime' ||
|
|
138
|
+
ctx.infoType === 'delegatorHistory' ||
|
|
139
|
+
ctx.infoType === 'delegatorRewards' ||
|
|
140
|
+
ctx.infoType === 'validatorStats'),
|
|
141
|
+
divisor: 20,
|
|
142
|
+
countItemsFromResponse: (response) => countUserFillsItems(response) || countArrayResponseItems(response),
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
export const getRestEstimatedExtraWeight = (ctx) => {
|
|
146
|
+
var _a, _b;
|
|
147
|
+
for (const weigher of extraWeighers) {
|
|
148
|
+
if (!weigher.match(ctx))
|
|
149
|
+
continue;
|
|
150
|
+
const items = (_b = (_a = weigher.estimateItems) === null || _a === void 0 ? void 0 : _a.call(weigher, ctx)) !== null && _b !== void 0 ? _b : 0;
|
|
151
|
+
if (items <= 0)
|
|
152
|
+
return 0;
|
|
153
|
+
return Math.ceil(items / weigher.divisor);
|
|
154
|
+
}
|
|
155
|
+
return 0;
|
|
156
|
+
};
|
|
157
|
+
const normalizeRestWeight = (meta, weight) => {
|
|
158
|
+
if (!Number.isFinite(weight)) {
|
|
159
|
+
throw newError('HYPERLIQUID_REST_WEIGHT_INVALID', Object.assign(Object.assign({}, meta), { weight }));
|
|
160
|
+
}
|
|
161
|
+
const normalized = Math.floor(weight);
|
|
162
|
+
if (normalized <= 0) {
|
|
163
|
+
throw newError('HYPERLIQUID_REST_WEIGHT_INVALID', Object.assign(Object.assign({}, meta), { weight: normalized }));
|
|
164
|
+
}
|
|
165
|
+
if (normalized > REST_IP_WEIGHT_MAX) {
|
|
166
|
+
throw newError('HYPERLIQUID_REST_WEIGHT_EXCESSIVE', Object.assign(Object.assign({}, meta), { weight: normalized, maxWeight: REST_IP_WEIGHT_MAX }));
|
|
167
|
+
}
|
|
168
|
+
return normalized;
|
|
169
|
+
};
|
|
170
|
+
export const acquireRestIpWeightSync = (meta, weight) => {
|
|
171
|
+
const normalized = normalizeRestWeight(meta, weight);
|
|
172
|
+
scopeError('HYPERLIQUID_API_RATE_LIMIT', Object.assign(Object.assign({}, meta), { bucketId: REST_IP_BUCKET_ID, weight: normalized }), () => tokenBucket(REST_IP_BUCKET_ID).acquireSync(normalized));
|
|
173
|
+
};
|
|
174
|
+
const acquireRestIpWeight = async (meta, weight) => {
|
|
175
|
+
let remaining = normalizeRestWeight(meta, weight);
|
|
176
|
+
while (remaining > 0) {
|
|
177
|
+
const chunk = Math.min(REST_IP_BUCKET_CAPACITY, remaining);
|
|
178
|
+
await scopeError('HYPERLIQUID_API_RATE_LIMIT', Object.assign(Object.assign({}, meta), { bucketId: REST_IP_BUCKET_ID, weight: chunk, remaining }), () => tokenBucket(REST_IP_BUCKET_ID).acquire(chunk));
|
|
179
|
+
remaining -= chunk;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
export const beforeRestRequest = (meta, ctx) => {
|
|
183
|
+
const baseWeight = getRestBaseWeight(ctx);
|
|
184
|
+
const estimatedExtraWeight = getRestEstimatedExtraWeight(ctx);
|
|
185
|
+
acquireRestIpWeightSync(meta, baseWeight + estimatedExtraWeight);
|
|
186
|
+
return { baseWeight, estimatedExtraWeight };
|
|
187
|
+
};
|
|
188
|
+
export const afterRestResponse = async (meta, ctx, response, estimatedExtraWeight) => {
|
|
189
|
+
var _a, _b;
|
|
190
|
+
for (const weigher of extraWeighers) {
|
|
191
|
+
if (!weigher.match(ctx))
|
|
192
|
+
continue;
|
|
193
|
+
const items = (_b = (_a = weigher.countItemsFromResponse) === null || _a === void 0 ? void 0 : _a.call(weigher, response)) !== null && _b !== void 0 ? _b : 0;
|
|
194
|
+
if (items <= 0)
|
|
195
|
+
return;
|
|
196
|
+
const actualExtraWeight = Math.ceil(items / weigher.divisor);
|
|
197
|
+
const delta = actualExtraWeight - estimatedExtraWeight;
|
|
198
|
+
if (delta > 0) {
|
|
199
|
+
// 不使用 acquireSync:响应后只阻塞等待,不报错
|
|
200
|
+
await acquireRestIpWeight(meta, delta);
|
|
201
|
+
}
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/api/rate-limit.ts"],"names":[],"mappings":"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","sourcesContent":["import { newError, scopeError, tokenBucket } from '@yuants/utils';\n\ntype HttpMethod = 'GET' | 'POST';\n\ntype RestRequestContext = Readonly<{\n method: HttpMethod;\n path: string;\n body?: unknown;\n kind: 'info' | 'exchange' | 'explorer' | 'other';\n infoType?: string;\n exchangeActionType?: string;\n exchangeBatchLength?: number;\n}>;\n\ntype ExtraWeigher = Readonly<{\n match: (ctx: RestRequestContext) => boolean;\n divisor: 20 | 60;\n estimateItems?: (ctx: RestRequestContext) => number;\n countItemsFromResponse?: (response: unknown) => number;\n}>;\n\nconst REST_IP_BUCKET_ID = 'HYPERLIQUID_REST_IP_WEIGHT_1200_PER_MIN';\nconst REST_IP_BUCKET_CAPACITY = 1200;\nconst REST_IP_WEIGHT_MAX = REST_IP_BUCKET_CAPACITY * 10;\n\ntokenBucket(REST_IP_BUCKET_ID, {\n capacity: REST_IP_BUCKET_CAPACITY,\n refillInterval: 60_000,\n refillAmount: 1200,\n});\n\nconst INFO_TYPE_TO_BASE_WEIGHT: Readonly<Record<string, number>> = {\n l2Book: 2,\n allMids: 2,\n clearinghouseState: 2,\n orderStatus: 2,\n spotClearinghouseState: 2,\n exchangeStatus: 2,\n userRole: 60,\n};\n\nconst INTERVAL_TO_MS: Readonly<Record<string, number>> = {\n '1m': 60_000,\n '3m': 180_000,\n '5m': 300_000,\n '15m': 900_000,\n '30m': 1_800_000,\n '1h': 3_600_000,\n '2h': 7_200_000,\n '4h': 14_400_000,\n '8h': 28_800_000,\n '12h': 43_200_000,\n '1d': 86_400_000,\n '3d': 259_200_000,\n '1w': 604_800_000,\n '1M': 2_592_000_000,\n};\n\nconst getObject = (value: unknown): Record<string, unknown> | undefined => {\n if (typeof value !== 'object' || value === null) return;\n return value as Record<string, unknown>;\n};\n\nconst getString = (value: unknown): string | undefined => {\n if (typeof value !== 'string') return;\n return value;\n};\n\nconst getNumber = (value: unknown): number | undefined => {\n if (typeof value !== 'number' || !Number.isFinite(value)) return;\n return value;\n};\n\nconst getArray = (value: unknown): unknown[] | undefined => {\n if (!Array.isArray(value)) return;\n return value;\n};\n\nexport const getRestRequestContext = (\n method: HttpMethod,\n path: string,\n body?: unknown,\n): RestRequestContext => {\n if (method === 'POST' && path === 'info') {\n const obj = getObject(body);\n const infoType = getString(obj?.type);\n return { method, path, body, kind: 'info', infoType };\n }\n if (method === 'POST' && path === 'exchange') {\n const obj = getObject(body);\n const action = getObject(obj?.action);\n const exchangeActionType = getString(action?.type);\n const orders = getArray(action?.orders);\n const cancels = getArray(action?.cancels);\n const exchangeBatchLength = Math.max(1, orders?.length ?? cancels?.length ?? 1);\n return { method, path, body, kind: 'exchange', exchangeActionType, exchangeBatchLength };\n }\n if (path.startsWith('explorer')) {\n return { method, path, body, kind: 'explorer' };\n }\n return { method, path, body, kind: 'other' };\n};\n\nexport const getRestBaseWeight = (ctx: RestRequestContext): number => {\n if (ctx.kind === 'exchange') {\n const batchLength = Math.max(1, ctx.exchangeBatchLength ?? 1);\n return 1 + Math.floor(batchLength / 40);\n }\n if (ctx.kind === 'info') {\n return INFO_TYPE_TO_BASE_WEIGHT[ctx.infoType ?? ''] ?? 20;\n }\n if (ctx.kind === 'explorer') {\n return 40;\n }\n return 20;\n};\n\nconst estimateCandleSnapshotItems = (ctx: RestRequestContext): number => {\n if (ctx.kind !== 'info' || ctx.infoType !== 'candleSnapshot') return 0;\n const bodyObj = getObject(ctx.body);\n const reqObj = getObject(bodyObj?.req);\n const interval = getString(reqObj?.interval);\n const startTime = getNumber(reqObj?.startTime);\n const endTime = getNumber(reqObj?.endTime);\n if (!interval || startTime === undefined || endTime === undefined || endTime <= startTime) return 0;\n\n const intervalMs = INTERVAL_TO_MS[interval] ?? 0;\n if (!intervalMs) return 0;\n\n // Hyperliquid docs: Only the most recent 5000 candles are available\n const estimated = Math.ceil((endTime - startTime) / intervalMs);\n return Math.min(5000, Math.max(0, estimated));\n};\n\nconst countArrayResponseItems = (response: unknown): number => {\n const arr = getArray(response);\n return arr?.length ?? 0;\n};\n\nconst countUserFillsItems = (response: unknown): number => {\n const obj = getObject(response);\n const fills = getArray(obj?.fills);\n return fills?.length ?? 0;\n};\n\nconst extraWeighers: ReadonlyArray<ExtraWeigher> = [\n {\n match: (ctx) => ctx.kind === 'info' && ctx.infoType === 'candleSnapshot',\n divisor: 60,\n estimateItems: estimateCandleSnapshotItems,\n countItemsFromResponse: countArrayResponseItems,\n },\n {\n match: (ctx) =>\n ctx.kind === 'info' &&\n (ctx.infoType === 'recentTrades' ||\n ctx.infoType === 'historicalOrders' ||\n ctx.infoType === 'userFills' ||\n ctx.infoType === 'userFillsByTime' ||\n ctx.infoType === 'fundingHistory' ||\n ctx.infoType === 'userFunding' ||\n ctx.infoType === 'nonUserFundingUpdates' ||\n ctx.infoType === 'twapHistory' ||\n ctx.infoType === 'userTwapSliceFills' ||\n ctx.infoType === 'userTwapSliceFillsByTime' ||\n ctx.infoType === 'delegatorHistory' ||\n ctx.infoType === 'delegatorRewards' ||\n ctx.infoType === 'validatorStats'),\n divisor: 20,\n countItemsFromResponse: (response) => countUserFillsItems(response) || countArrayResponseItems(response),\n },\n];\n\nexport const getRestEstimatedExtraWeight = (ctx: RestRequestContext): number => {\n for (const weigher of extraWeighers) {\n if (!weigher.match(ctx)) continue;\n const items = weigher.estimateItems?.(ctx) ?? 0;\n if (items <= 0) return 0;\n return Math.ceil(items / weigher.divisor);\n }\n return 0;\n};\n\nconst normalizeRestWeight = (meta: Record<string, unknown>, weight: number): number => {\n if (!Number.isFinite(weight)) {\n throw newError('HYPERLIQUID_REST_WEIGHT_INVALID', { ...meta, weight });\n }\n const normalized = Math.floor(weight);\n if (normalized <= 0) {\n throw newError('HYPERLIQUID_REST_WEIGHT_INVALID', { ...meta, weight: normalized });\n }\n if (normalized > REST_IP_WEIGHT_MAX) {\n throw newError('HYPERLIQUID_REST_WEIGHT_EXCESSIVE', {\n ...meta,\n weight: normalized,\n maxWeight: REST_IP_WEIGHT_MAX,\n });\n }\n return normalized;\n};\n\nexport const acquireRestIpWeightSync = (meta: Record<string, unknown>, weight: number) => {\n const normalized = normalizeRestWeight(meta, weight);\n scopeError('HYPERLIQUID_API_RATE_LIMIT', { ...meta, bucketId: REST_IP_BUCKET_ID, weight: normalized }, () =>\n tokenBucket(REST_IP_BUCKET_ID).acquireSync(normalized),\n );\n};\n\nconst acquireRestIpWeight = async (meta: Record<string, unknown>, weight: number) => {\n let remaining = normalizeRestWeight(meta, weight);\n while (remaining > 0) {\n const chunk = Math.min(REST_IP_BUCKET_CAPACITY, remaining);\n await scopeError(\n 'HYPERLIQUID_API_RATE_LIMIT',\n { ...meta, bucketId: REST_IP_BUCKET_ID, weight: chunk, remaining },\n () => tokenBucket(REST_IP_BUCKET_ID).acquire(chunk),\n );\n remaining -= chunk;\n }\n};\n\nexport const beforeRestRequest = (\n meta: Record<string, unknown>,\n ctx: RestRequestContext,\n): Readonly<{ baseWeight: number; estimatedExtraWeight: number }> => {\n const baseWeight = getRestBaseWeight(ctx);\n const estimatedExtraWeight = getRestEstimatedExtraWeight(ctx);\n acquireRestIpWeightSync(meta, baseWeight + estimatedExtraWeight);\n return { baseWeight, estimatedExtraWeight };\n};\n\nexport const afterRestResponse = async (\n meta: Record<string, unknown>,\n ctx: RestRequestContext,\n response: unknown,\n estimatedExtraWeight: number,\n) => {\n for (const weigher of extraWeighers) {\n if (!weigher.match(ctx)) continue;\n const items = weigher.countItemsFromResponse?.(response) ?? 0;\n if (items <= 0) return;\n const actualExtraWeight = Math.ceil(items / weigher.divisor);\n const delta = actualExtraWeight - estimatedExtraWeight;\n if (delta > 0) {\n // 不使用 acquireSync:响应后只阻塞等待,不报错\n await acquireRestIpWeight(meta, delta);\n }\n return;\n }\n};\n"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { tokenBucket } from '@yuants/utils';
|
|
2
|
+
import { afterRestResponse, beforeRestRequest, getRestBaseWeight, getRestEstimatedExtraWeight, getRestRequestContext, } from './rate-limit';
|
|
3
|
+
describe('rate-limit', () => {
|
|
4
|
+
const bucketId = 'HYPERLIQUID_REST_IP_WEIGHT_1200_PER_MIN';
|
|
5
|
+
const readBucket = () => tokenBucket(bucketId).read();
|
|
6
|
+
afterAll(() => {
|
|
7
|
+
const bucket = tokenBucket(bucketId);
|
|
8
|
+
bucket[Symbol.dispose]();
|
|
9
|
+
});
|
|
10
|
+
it('parses rest request context', () => {
|
|
11
|
+
const infoCtx = getRestRequestContext('POST', 'info', { type: 'allMids' });
|
|
12
|
+
expect(infoCtx.kind).toBe('info');
|
|
13
|
+
expect(infoCtx.infoType).toBe('allMids');
|
|
14
|
+
const exchangeCtx = getRestRequestContext('POST', 'exchange', {
|
|
15
|
+
action: { type: 'order', orders: [{}, {}] },
|
|
16
|
+
});
|
|
17
|
+
expect(exchangeCtx.kind).toBe('exchange');
|
|
18
|
+
expect(exchangeCtx.exchangeActionType).toBe('order');
|
|
19
|
+
expect(exchangeCtx.exchangeBatchLength).toBe(2);
|
|
20
|
+
const explorerCtx = getRestRequestContext('GET', 'explorer/tx/0x', undefined);
|
|
21
|
+
expect(explorerCtx.kind).toBe('explorer');
|
|
22
|
+
});
|
|
23
|
+
it('calculates info base weight', () => {
|
|
24
|
+
const ctx = getRestRequestContext('POST', 'info', { type: 'allMids' });
|
|
25
|
+
expect(getRestBaseWeight(ctx)).toBe(2);
|
|
26
|
+
});
|
|
27
|
+
it('defaults base weight for unknown info type', () => {
|
|
28
|
+
const ctx = getRestRequestContext('POST', 'info', { type: 'unknownType' });
|
|
29
|
+
expect(getRestBaseWeight(ctx)).toBe(20);
|
|
30
|
+
});
|
|
31
|
+
it('assigns base weight for explorer and other requests', () => {
|
|
32
|
+
const explorerCtx = getRestRequestContext('GET', 'explorer/tx/0x', undefined);
|
|
33
|
+
expect(getRestBaseWeight(explorerCtx)).toBe(40);
|
|
34
|
+
const otherCtx = getRestRequestContext('GET', 'status', undefined);
|
|
35
|
+
expect(getRestBaseWeight(otherCtx)).toBe(20);
|
|
36
|
+
});
|
|
37
|
+
it('calculates exchange base weight across batch sizes', () => {
|
|
38
|
+
const cases = [
|
|
39
|
+
{ batchLength: 0, expected: 1 },
|
|
40
|
+
{ batchLength: 1, expected: 1 },
|
|
41
|
+
{ batchLength: 40, expected: 2 },
|
|
42
|
+
{ batchLength: 41, expected: 2 },
|
|
43
|
+
{ batchLength: 80, expected: 3 },
|
|
44
|
+
];
|
|
45
|
+
for (const { batchLength, expected } of cases) {
|
|
46
|
+
const ctx = getRestRequestContext('POST', 'exchange', {
|
|
47
|
+
action: { type: 'order', orders: new Array(batchLength).fill({}) },
|
|
48
|
+
});
|
|
49
|
+
expect(getRestBaseWeight(ctx)).toBe(expected);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
it('estimates candleSnapshot extra weight with 5000 cap', () => {
|
|
53
|
+
const intervalMs = 60000;
|
|
54
|
+
const candles = 10000;
|
|
55
|
+
const ctx = getRestRequestContext('POST', 'info', {
|
|
56
|
+
type: 'candleSnapshot',
|
|
57
|
+
req: { interval: '1m', startTime: 0, endTime: candles * intervalMs },
|
|
58
|
+
});
|
|
59
|
+
expect(getRestEstimatedExtraWeight(ctx)).toBe(Math.ceil(5000 / 60));
|
|
60
|
+
});
|
|
61
|
+
it('returns zero extra weight for invalid candleSnapshot inputs', () => {
|
|
62
|
+
const invalidIntervalCtx = getRestRequestContext('POST', 'info', {
|
|
63
|
+
type: 'candleSnapshot',
|
|
64
|
+
req: { interval: '2m', startTime: 0, endTime: 60000 },
|
|
65
|
+
});
|
|
66
|
+
expect(getRestEstimatedExtraWeight(invalidIntervalCtx)).toBe(0);
|
|
67
|
+
const sameTimeCtx = getRestRequestContext('POST', 'info', {
|
|
68
|
+
type: 'candleSnapshot',
|
|
69
|
+
req: { interval: '1m', startTime: 0, endTime: 0 },
|
|
70
|
+
});
|
|
71
|
+
expect(getRestEstimatedExtraWeight(sameTimeCtx)).toBe(0);
|
|
72
|
+
const missingReqCtx = getRestRequestContext('POST', 'info', { type: 'candleSnapshot' });
|
|
73
|
+
expect(getRestEstimatedExtraWeight(missingReqCtx)).toBe(0);
|
|
74
|
+
});
|
|
75
|
+
it('consumes base and estimated weight before request', () => {
|
|
76
|
+
const ctx = getRestRequestContext('POST', 'info', {
|
|
77
|
+
type: 'candleSnapshot',
|
|
78
|
+
req: { interval: '1m', startTime: 0, endTime: 120 * 60000 },
|
|
79
|
+
});
|
|
80
|
+
const before = readBucket();
|
|
81
|
+
const { baseWeight, estimatedExtraWeight } = beforeRestRequest({ requestKey: 'test' }, ctx);
|
|
82
|
+
const after = readBucket();
|
|
83
|
+
expect(baseWeight).toBe(20);
|
|
84
|
+
expect(estimatedExtraWeight).toBe(2);
|
|
85
|
+
expect(after).toBe(before - baseWeight - estimatedExtraWeight);
|
|
86
|
+
});
|
|
87
|
+
it('throws on invalid or excessive weights before request', () => {
|
|
88
|
+
const invalidCtx = {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
path: 'exchange',
|
|
91
|
+
kind: 'exchange',
|
|
92
|
+
exchangeBatchLength: Number.NaN,
|
|
93
|
+
};
|
|
94
|
+
expect(() => beforeRestRequest({ requestKey: 'test' }, invalidCtx)).toThrow(/HYPERLIQUID_REST_WEIGHT_INVALID/);
|
|
95
|
+
const maxWeight = 1200 * 10;
|
|
96
|
+
const excessiveCtx = {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
path: 'exchange',
|
|
99
|
+
kind: 'exchange',
|
|
100
|
+
exchangeBatchLength: (maxWeight + 1) * 40,
|
|
101
|
+
};
|
|
102
|
+
expect(() => beforeRestRequest({ requestKey: 'test' }, excessiveCtx)).toThrow(/HYPERLIQUID_REST_WEIGHT_EXCESSIVE/);
|
|
103
|
+
});
|
|
104
|
+
it('applies extra weight based on response size', async () => {
|
|
105
|
+
const ctx = getRestRequestContext('POST', 'info', { type: 'userFills' });
|
|
106
|
+
const response = { fills: new Array(41).fill({}) };
|
|
107
|
+
const before = readBucket();
|
|
108
|
+
await afterRestResponse({ requestKey: 'test' }, ctx, response, 0);
|
|
109
|
+
const after = readBucket();
|
|
110
|
+
expect(before - after).toBe(Math.ceil(41 / 20));
|
|
111
|
+
});
|
|
112
|
+
it('applies delta extra weight for candleSnapshot responses', async () => {
|
|
113
|
+
const ctx = getRestRequestContext('POST', 'info', { type: 'candleSnapshot' });
|
|
114
|
+
const response = new Array(120).fill({});
|
|
115
|
+
const before = readBucket();
|
|
116
|
+
await afterRestResponse({ requestKey: 'test' }, ctx, response, 1);
|
|
117
|
+
const after = readBucket();
|
|
118
|
+
expect(before - after).toBe(1);
|
|
119
|
+
});
|
|
120
|
+
it('skips extra acquire when response weight is within estimate', async () => {
|
|
121
|
+
const ctx = getRestRequestContext('POST', 'info', { type: 'userFills' });
|
|
122
|
+
const response = { fills: [{}] };
|
|
123
|
+
const before = readBucket();
|
|
124
|
+
await afterRestResponse({ requestKey: 'test' }, ctx, response, 1);
|
|
125
|
+
const after = readBucket();
|
|
126
|
+
expect(after).toBe(before);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=rate-limit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.test.js","sourceRoot":"","sources":["../../src/api/rate-limit.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { tokenBucket } from '@yuants/utils';\nimport {\n afterRestResponse,\n beforeRestRequest,\n getRestBaseWeight,\n getRestEstimatedExtraWeight,\n getRestRequestContext,\n} from './rate-limit';\n\ndescribe('rate-limit', () => {\n const bucketId = 'HYPERLIQUID_REST_IP_WEIGHT_1200_PER_MIN';\n const readBucket = () => tokenBucket(bucketId).read();\n\n afterAll(() => {\n const bucket = tokenBucket(bucketId);\n bucket[Symbol.dispose]();\n });\n\n it('parses rest request context', () => {\n const infoCtx = getRestRequestContext('POST', 'info', { type: 'allMids' });\n expect(infoCtx.kind).toBe('info');\n expect(infoCtx.infoType).toBe('allMids');\n\n const exchangeCtx = getRestRequestContext('POST', 'exchange', {\n action: { type: 'order', orders: [{}, {}] },\n });\n expect(exchangeCtx.kind).toBe('exchange');\n expect(exchangeCtx.exchangeActionType).toBe('order');\n expect(exchangeCtx.exchangeBatchLength).toBe(2);\n\n const explorerCtx = getRestRequestContext('GET', 'explorer/tx/0x', undefined);\n expect(explorerCtx.kind).toBe('explorer');\n });\n\n it('calculates info base weight', () => {\n const ctx = getRestRequestContext('POST', 'info', { type: 'allMids' });\n expect(getRestBaseWeight(ctx)).toBe(2);\n });\n\n it('defaults base weight for unknown info type', () => {\n const ctx = getRestRequestContext('POST', 'info', { type: 'unknownType' });\n expect(getRestBaseWeight(ctx)).toBe(20);\n });\n\n it('assigns base weight for explorer and other requests', () => {\n const explorerCtx = getRestRequestContext('GET', 'explorer/tx/0x', undefined);\n expect(getRestBaseWeight(explorerCtx)).toBe(40);\n\n const otherCtx = getRestRequestContext('GET', 'status', undefined);\n expect(getRestBaseWeight(otherCtx)).toBe(20);\n });\n\n it('calculates exchange base weight across batch sizes', () => {\n const cases = [\n { batchLength: 0, expected: 1 },\n { batchLength: 1, expected: 1 },\n { batchLength: 40, expected: 2 },\n { batchLength: 41, expected: 2 },\n { batchLength: 80, expected: 3 },\n ];\n\n for (const { batchLength, expected } of cases) {\n const ctx = getRestRequestContext('POST', 'exchange', {\n action: { type: 'order', orders: new Array(batchLength).fill({}) },\n });\n expect(getRestBaseWeight(ctx)).toBe(expected);\n }\n });\n\n it('estimates candleSnapshot extra weight with 5000 cap', () => {\n const intervalMs = 60_000;\n const candles = 10_000;\n const ctx = getRestRequestContext('POST', 'info', {\n type: 'candleSnapshot',\n req: { interval: '1m', startTime: 0, endTime: candles * intervalMs },\n });\n expect(getRestEstimatedExtraWeight(ctx)).toBe(Math.ceil(5000 / 60));\n });\n\n it('returns zero extra weight for invalid candleSnapshot inputs', () => {\n const invalidIntervalCtx = getRestRequestContext('POST', 'info', {\n type: 'candleSnapshot',\n req: { interval: '2m', startTime: 0, endTime: 60_000 },\n });\n expect(getRestEstimatedExtraWeight(invalidIntervalCtx)).toBe(0);\n\n const sameTimeCtx = getRestRequestContext('POST', 'info', {\n type: 'candleSnapshot',\n req: { interval: '1m', startTime: 0, endTime: 0 },\n });\n expect(getRestEstimatedExtraWeight(sameTimeCtx)).toBe(0);\n\n const missingReqCtx = getRestRequestContext('POST', 'info', { type: 'candleSnapshot' });\n expect(getRestEstimatedExtraWeight(missingReqCtx)).toBe(0);\n });\n\n it('consumes base and estimated weight before request', () => {\n const ctx = getRestRequestContext('POST', 'info', {\n type: 'candleSnapshot',\n req: { interval: '1m', startTime: 0, endTime: 120 * 60_000 },\n });\n const before = readBucket();\n const { baseWeight, estimatedExtraWeight } = beforeRestRequest({ requestKey: 'test' }, ctx);\n const after = readBucket();\n expect(baseWeight).toBe(20);\n expect(estimatedExtraWeight).toBe(2);\n expect(after).toBe(before - baseWeight - estimatedExtraWeight);\n });\n\n it('throws on invalid or excessive weights before request', () => {\n const invalidCtx = {\n method: 'POST',\n path: 'exchange',\n kind: 'exchange',\n exchangeBatchLength: Number.NaN,\n } as ReturnType<typeof getRestRequestContext>;\n expect(() => beforeRestRequest({ requestKey: 'test' }, invalidCtx)).toThrow(\n /HYPERLIQUID_REST_WEIGHT_INVALID/,\n );\n\n const maxWeight = 1200 * 10;\n const excessiveCtx = {\n method: 'POST',\n path: 'exchange',\n kind: 'exchange',\n exchangeBatchLength: (maxWeight + 1) * 40,\n } as ReturnType<typeof getRestRequestContext>;\n expect(() => beforeRestRequest({ requestKey: 'test' }, excessiveCtx)).toThrow(\n /HYPERLIQUID_REST_WEIGHT_EXCESSIVE/,\n );\n });\n\n it('applies extra weight based on response size', async () => {\n const ctx = getRestRequestContext('POST', 'info', { type: 'userFills' });\n const response = { fills: new Array(41).fill({}) };\n\n const before = readBucket();\n await afterRestResponse({ requestKey: 'test' }, ctx, response, 0);\n const after = readBucket();\n expect(before - after).toBe(Math.ceil(41 / 20));\n });\n\n it('applies delta extra weight for candleSnapshot responses', async () => {\n const ctx = getRestRequestContext('POST', 'info', { type: 'candleSnapshot' });\n const response = new Array(120).fill({});\n\n const before = readBucket();\n await afterRestResponse({ requestKey: 'test' }, ctx, response, 1);\n const after = readBucket();\n expect(before - after).toBe(1);\n });\n\n it('skips extra acquire when response weight is within estimate', async () => {\n const ctx = getRestRequestContext('POST', 'info', { type: 'userFills' });\n const response = { fills: [{}] };\n\n const before = readBucket();\n await afterRestResponse({ requestKey: 'test' }, ctx, response, 1);\n const after = readBucket();\n expect(after).toBe(before);\n });\n});\n"]}
|
package/dist/api/sign.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../../src/api/sign.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAU,MAAM,QAAQ,CAAC;AA4B3C,SAAS,cAAc,CAAC,OAAe;IACrC,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC3E,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,UAAU,CACjB,MAAW,EACX,YAA2B,EAC3B,KAAa,EACb,YAA2B;IAE3B,IAAI,IAAI,GAAQ,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAE/C,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAClD,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,qBAAqB;IACtE,IAAI,GAAG,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAE3C,IAAI,YAAY,IAAI,IAAI,EAAE;
|
|
1
|
+
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../../src/api/sign.ts"],"names":[],"mappings":"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","sourcesContent":["import { encode } from '@msgpack/msgpack';\nimport { keccak256, Wallet } from 'ethers';\n\ninterface PhantomAgent {\n source: string;\n connectionId: string;\n}\n\ninterface L1Payload {\n domain: {\n chainId: number;\n name: string;\n verifyingContract: string;\n version: string;\n };\n types: {\n Agent: Array<{ name: string; type: string }>;\n EIP712Domain: Array<{ name: string; type: string }>;\n };\n primaryType: string;\n message: PhantomAgent;\n}\n\ninterface Signature {\n r: string;\n s: string;\n v: number;\n}\n\nfunction addressToBytes(address: string): Uint8Array {\n const cleanAddress = address.startsWith('0x') ? address.slice(2) : address;\n return new Uint8Array(Buffer.from(cleanAddress, 'hex'));\n}\n\nfunction actionHash(\n action: any,\n vaultAddress: string | null,\n nonce: number,\n expiresAfter: number | null,\n): string {\n let data: any = new Uint8Array(encode(action));\n\n const nonceBytes = new Uint8Array(8);\n const nonceView = new DataView(nonceBytes.buffer);\n nonceView.setBigUint64(0, BigInt(nonce), false); // false = big endian\n data = concatUint8Arrays(data, nonceBytes);\n\n if (vaultAddress == null) {\n data = concatUint8Arrays(data, new Uint8Array([0x00]));\n } else {\n data = concatUint8Arrays(data, new Uint8Array([0x01]));\n data = concatUint8Arrays(data, addressToBytes(vaultAddress));\n }\n if (expiresAfter != null) {\n data = concatUint8Arrays(data, new Uint8Array([0x00]));\n const expiresBytes = new Uint8Array(8);\n const expiresView = new DataView(expiresBytes.buffer);\n expiresView.setBigUint64(0, BigInt(expiresAfter), false); // false = big endian\n data = concatUint8Arrays(data, expiresBytes);\n }\n\n return keccak256(data);\n}\n\nfunction concatUint8Arrays(...arrays: Uint8Array[]): Uint8Array {\n const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n\n for (const arr of arrays) {\n result.set(arr, offset);\n offset += arr.length;\n }\n\n return result;\n}\n\nfunction constructPhantomAgent(hash: string, isMainnet: boolean): PhantomAgent {\n return {\n source: isMainnet ? 'a' : 'b',\n connectionId: hash,\n };\n}\n\nfunction l1Payload(phantomAgent: PhantomAgent): L1Payload {\n return {\n domain: {\n chainId: 1337,\n name: 'Exchange',\n verifyingContract: '0x0000000000000000000000000000000000000000',\n version: '1',\n },\n types: {\n Agent: [\n { name: 'source', type: 'string' },\n { name: 'connectionId', type: 'bytes32' },\n ],\n EIP712Domain: [\n { name: 'name', type: 'string' },\n { name: 'version', type: 'string' },\n { name: 'chainId', type: 'uint256' },\n { name: 'verifyingContract', type: 'address' },\n ],\n },\n primaryType: 'Agent',\n message: phantomAgent,\n };\n}\n\nasync function signInner(wallet: Wallet, data: L1Payload): Promise<Signature> {\n const signature = await wallet.signTypedData(data.domain, { Agent: data.types.Agent }, data.message);\n\n const r = signature.slice(0, 66);\n const s = '0x' + signature.slice(66, 130);\n const v = parseInt(signature.slice(130, 132), 16);\n\n return { r, s, v };\n}\n\n/**\n * 签署 L1 动作\n *\n * @param wallet - 以太坊钱包实例\n * @param action - 要签署的动作数据\n * @param activePool - 活跃池地址(可以为 null)\n * @param nonce - 随机数\n * @param expiresAfter - 过期时间(可以为 null)\n * @param isMainnet - 是否为主网\n * @returns 签名对象\n */\nexport async function signL1Action(\n wallet: Wallet,\n action: any,\n activePool: string | null,\n nonce: number,\n expiresAfter: number | null,\n isMainnet: boolean,\n): Promise<Signature> {\n const hash = actionHash(action, activePool, nonce, expiresAfter);\n const phantomAgent = constructPhantomAgent(hash, isMainnet);\n const data = l1Payload(phantomAgent);\n return await signInner(wallet, data);\n}\n\nexport { actionHash, addressToBytes, constructPhantomAgent, l1Payload };\n"]}
|
package/dist/api/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAWhC;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,UAAuB,EAAU,EAAE,CACjE,eAAe,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,WAAmB,EAAe,EAAE;IACnE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC;IACvC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;AAClD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAgB,EAAE;IACpD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAC5C,IAAI,CAAC,WAAW,EAAE;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAWhC;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,UAAuB,EAAU,EAAE,CACjE,eAAe,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,WAAmB,EAAe,EAAE;IACnE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC;IACvC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;AAClD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAgB,EAAE;IACpD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAC5C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,gBAAgB,CAAC,WAAW,CAAC,CAAC;AACvC,CAAC,CAAC","sourcesContent":["import { Wallet } from 'ethers';\n\n/**\n * Hyperliquid 凭证接口\n * 仅包含核心数据,行为方法通过辅助函数提供\n */\nexport interface ICredential {\n private_key: string;\n address: string;\n}\n\n/**\n * 获取凭证唯一标识\n */\nexport const getCredentialId = (credential: ICredential): string =>\n `HYPERLIQUID/${credential.address.toLowerCase()}`;\n\n/**\n * 创建凭证对象\n * @param private_key 私钥\n * @returns 凭证对象\n */\nexport const createCredential = (private_key: string): ICredential => {\n const wallet = new Wallet(private_key);\n return { private_key, address: wallet.address };\n};\n\n/**\n * 获取默认凭证(从环境变量)\n * @returns 默认凭证对象\n */\nexport const getDefaultCredential = (): ICredential => {\n const private_key = process.env.PRIVATE_KEY;\n if (!private_key) {\n throw new Error('Missing Hyperliquid credential: PRIVATE_KEY must be set');\n }\n return createCredential(private_key);\n};\n"]}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAC7B,OAAO,4BAA4B,CAAC;AACpC,OAAO,0BAA0B,CAAC;AAClC,OAAO,mBAAmB,CAAC;AAC3B,OAAO,yBAAyB,CAAC;AACjC,OAAO,kCAAkC,CAAC","sourcesContent":["import './services/exchange';\nimport './services/markets/product';\nimport './services/markets/quote';\nimport './services/quotes';\nimport './services/ohlc-service';\nimport './services/interest-rate-service';\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../../../src/services/accounts/spot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAa,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,mBAAmB,GAAG,WAAW,CACrC,KAAK,IAAI,EAAE;IACT,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../../../src/services/accounts/spot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAa,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,mBAAmB,GAAG,WAAW,CACrC,KAAK,IAAI,EAAE;IACT,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,EACD,EAAE,MAAM,EAAE,QAAU,EAAE,CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,UAAuB,EAAE,EAAE;IAChE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,iCAAiC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;IAE5F,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACzD,oBAAoB,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC;QAClD,UAAU,EAAE;QACZ,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;KAC9B,CAAC,CAAC;IACH,MAAM,sBAAsB,GAAG,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,IAAI,GAAG,EAAkB,CAAC;IAE3E,8DAA8D;IAC9D,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ;SAChC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SAC9C,GAAG,CACF,CAAC,OAAO,EAAa,EAAE;;QACrB,OAAA,gBAAgB,CAAC;YACf,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE;YAC9B,aAAa,EAAE,aAAa;YAC5B,UAAU,EACR,MAAA,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,mCACxC,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,OAAO,CAAC;YAC3D,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;YAC7B,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YACzD,cAAc,EAAE,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAG,OAAO,CAAC,IAAI,CAAC,mCAAI,CAAC,CAAC;SAChF,CAAC,CAAA;KAAA,CACL,CAAC;IAEJ,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC","sourcesContent":["import { createCache } from '@yuants/cache';\nimport { IPosition, makeSpotPosition } from '@yuants/data-account';\nimport { encodePath, formatTime } from '@yuants/utils';\nimport { getAllMids, getUserTokenBalances } from '../../api/public-api';\nimport { ICredential } from '../../api/types';\nimport { listProducts } from '../markets/product';\n\nconst spotProductMapCache = createCache(\n async () => {\n const products = await listProducts();\n const map = new Map<string, string>();\n for (const product of products) {\n const [, instType] = product.product_id.split('/');\n if (instType === 'SPOT') {\n map.set(product.base_currency, product.product_id);\n }\n }\n return map;\n },\n { expire: 86_400_000 },\n);\n\n/**\n * Get account info for spot account\n */\nexport const getSpotPositions = async (credential: ICredential) => {\n console.info(formatTime(Date.now()), `Getting spot account info for ${credential.address}`);\n\n const [balances, mids, spotProductMap] = await Promise.all([\n getUserTokenBalances({ user: credential.address }),\n getAllMids(),\n spotProductMapCache.query(''),\n ]);\n const resolvedSpotProductMap = spotProductMap ?? new Map<string, string>();\n\n // Map token balances to positions (using spot as \"positions\")\n const positions = balances.balances\n .filter((balance) => Number(balance.total) > 0)\n .map(\n (balance): IPosition =>\n makeSpotPosition({\n position_id: `${balance.coin}`,\n datasource_id: 'HYPERLIQUID',\n product_id:\n resolvedSpotProductMap.get(balance.coin) ??\n encodePath('HYPERLIQUID', 'SPOT', `${balance.coin}-USDC`),\n volume: Number(balance.total),\n free_volume: Number(balance.total) - Number(balance.hold),\n closable_price: balance.coin === 'USDC' ? 1 : Number(mids?.[balance.coin] ?? 0),\n }),\n );\n\n return positions;\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../src/services/exchange.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAe,eAAe,IAAI,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,wBAAwB,GAAG,CAAC,UAAmB,EAAE,EAAE;IACvD,IAAI,CAAC,UAAU,EAAE;
|
|
1
|
+
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../src/services/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import { IPosition } from '@yuants/data-account';\nimport { IOrder } from '@yuants/data-order';\nimport { provideExchangeServices } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { decodePath, formatTime } from '@yuants/utils';\nimport { ICredential, getCredentialId as getCredentialIdFromCredential } from '../api/types';\nimport { listProducts } from './markets/product';\nimport { getPerpPositions } from './accounts/perp';\nimport { getSpotPositions } from './accounts/spot';\nimport { cancelOrderAction } from './orders/cancelOrder';\nimport { listOrdersByProductId, listPerpOrders } from './orders/listOrders';\nimport { modifyOrder } from './orders/modifyOrder';\nimport { submitOrder } from './orders/submitOrder';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst ensureHyperliquidProduct = (product_id?: string) => {\n if (!product_id) {\n throw new Error('product_id is required');\n }\n const [exchange, instType] = decodePath(product_id);\n if (exchange !== 'HYPERLIQUID') {\n throw new Error(`product_id must start with HYPERLIQUID, got ${product_id}`);\n }\n if (instType !== 'PERPETUAL') {\n throw new Error(`Hyperliquid only supports PERPETUAL orders for now: ${product_id}`);\n }\n};\n\nprovideExchangeServices<ICredential>(terminal, {\n name: 'HYPERLIQUID',\n credentialSchema: {\n type: 'object',\n required: ['private_key', 'address'],\n properties: {\n private_key: { type: 'string' },\n address: { type: 'string' },\n },\n },\n getCredentialId: async (credential) => getCredentialIdFromCredential(credential),\n listProducts,\n getPositions: async (credential: ICredential): Promise<IPosition[]> => {\n console.info(\n `[${formatTime(Date.now())}] Fetching positions for ${getCredentialIdFromCredential(credential)}`,\n );\n const [perpPositions, spotPositions] = await Promise.all([\n getPerpPositions(credential),\n getSpotPositions(credential),\n ]);\n return [...perpPositions, ...spotPositions];\n },\n getPositionsByProductId: async (credential: ICredential, product_id: string): Promise<IPosition[]> => {\n const [exchange, instType] = decodePath(product_id);\n if (exchange !== 'HYPERLIQUID') {\n throw new Error(`Invalid product_id for Hyperliquid: ${product_id}`);\n }\n if (instType === 'PERPETUAL') {\n const perpPositions = await getPerpPositions(credential);\n return perpPositions.filter((position) => position.product_id === product_id);\n }\n if (instType === 'PERPETUAL-ASSET') {\n const perpPositions = await getPerpPositions(credential);\n return perpPositions.filter((position) => position.product_id === product_id);\n }\n if (instType === 'SPOT') {\n const spotPositions = await getSpotPositions(credential);\n return spotPositions.filter((position) => position.product_id === product_id);\n }\n return [];\n },\n getOrders: async (credential: ICredential): Promise<IOrder[]> => {\n return listPerpOrders(credential);\n },\n getOrdersByProductId: async (credential: ICredential, product_id: string): Promise<IOrder[]> => {\n return listOrdersByProductId(credential, product_id);\n },\n submitOrder: async (credential: ICredential, order: IOrder): Promise<{ order_id: string }> => {\n ensureHyperliquidProduct(order.product_id);\n return submitOrder(credential, order);\n },\n modifyOrder: async (credential: ICredential, order: IOrder): Promise<void> => {\n ensureHyperliquidProduct(order.product_id);\n return modifyOrder(credential, order);\n },\n cancelOrder: async (credential: ICredential, order: IOrder): Promise<void> => {\n ensureHyperliquidProduct(order.product_id);\n return cancelOrderAction(credential, order);\n },\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quote.js","sourceRoot":"","sources":["../../../src/services/markets/quote.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"quote.js","sourceRoot":"","sources":["../../../src/services/markets/quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { IQuote, setMetricsQuoteState } from '@yuants/data-quote';\nimport { GlobalPrometheusRegistry, Terminal } from '@yuants/protocol';\nimport { writeToSQL } from '@yuants/sql';\nimport { decodePath, encodePath } from '@yuants/utils';\nimport { defer, filter, map, mergeMap, repeat, retry, shareReplay, withLatestFrom } from 'rxjs';\nimport { getAllMids, getMetaAndAssetCtxs } from '../../api/public-api';\n\nconst terminal = Terminal.fromNodeEnv();\nconst ASSET_CTX_REFRESH_INTERVAL = Number(process.env.ASSET_CTX_REFRESH_INTERVAL ?? 5_000);\n\ntype HyperliquidAssetContext = Awaited<ReturnType<typeof getMetaAndAssetCtxs>>[1][number];\n\nconst assetCtxMap$ = defer(() => getMetaAndAssetCtxs()).pipe(\n map(([meta, assetCtxs]) => {\n const entries = meta?.universe?.map<[string, HyperliquidAssetContext | undefined]>((asset, index) => [\n asset.name,\n assetCtxs?.[index],\n ]);\n return new Map(entries?.filter(([, ctx]) => !!ctx) ?? []);\n }),\n repeat({ delay: ASSET_CTX_REFRESH_INTERVAL }),\n retry({ delay: 5000 }),\n shareReplay({ bufferSize: 1, refCount: true }),\n);\n\nconst quote$ = defer(() => getAllMids()).pipe(\n map((mids) => Object.entries(mids ?? {})),\n mergeMap((entries) => entries),\n withLatestFrom(assetCtxMap$),\n map(([entry, assetCtxMap]): Partial<IQuote> => {\n const [coin, price] = entry;\n const ctx = assetCtxMap.get(coin);\n return {\n datasource_id: 'HYPERLIQUID',\n product_id: encodePath('HYPERLIQUID', 'PERPETUAL', `${coin}-USD`),\n last_price: `${price}`,\n bid_price: `${price}`,\n ask_price: `${price}`,\n open_interest: `${ctx?.openInterest ?? 0}`,\n interest_rate_long: ctx?.funding ? `${-+ctx.funding}` : undefined,\n interest_rate_short: ctx?.funding,\n updated_at: new Date().toISOString(),\n };\n }),\n repeat({ delay: 1000 }),\n retry({ delay: 5000 }),\n shareReplay({ bufferSize: 1, refCount: true }),\n);\n\nconst shouldWriteQuoteToSQL = /^(1|true)$/i.test(process.env.WRITE_QUOTE_TO_SQL ?? '');\n\nif (shouldWriteQuoteToSQL) {\n quote$\n .pipe(\n setMetricsQuoteState(terminal.terminal_id),\n writeToSQL({\n terminal,\n tableName: 'quote',\n writeInterval: 1000,\n conflictKeys: ['datasource_id', 'product_id'],\n }),\n )\n .subscribe();\n}\n\nterminal.channel.publishChannel('quote', { pattern: '^HYPERLIQUID/' }, (channel_id) => {\n const [datasourceId] = decodePath(channel_id);\n if (datasourceId !== 'HYPERLIQUID') {\n throw new Error(`Invalid channel_id: ${channel_id}`);\n }\n return quote$.pipe(filter((quote) => quote.product_id === channel_id));\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ohlc-service.js","sourceRoot":"","sources":["../../src/services/ohlc-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAExC,MAAM,gCAAgC,GAA2B;IAC/D,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;CACV,CAAC;AAEF,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B,MAAM,qBAAqB,GAAG,KAAK,EAAE,GAKpC,EAAoB,EAAE;IACrB,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IAC1E,IAAI,UAAU,KAAK,WAAW,IAAI,UAAU,KAAK,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"ohlc-service.js","sourceRoot":"","sources":["../../src/services/ohlc-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { IOHLC } from '@yuants/data-ohlc';\nimport { provideOHLCService } from '@yuants/exchange';\nimport { Terminal } from '@yuants/protocol';\nimport { convertDurationToOffset, decodePath, formatTime } from '@yuants/utils';\nimport { getCandleSnapshot } from '../api/public-api';\n\nconst terminal = Terminal.fromNodeEnv();\n\nconst DURATION_TO_HYPERLIQUID_INTERVAL: Record<string, string> = {\n PT1M: '1m',\n PT3M: '3m',\n PT5M: '5m',\n PT15M: '15m',\n PT30M: '30m',\n PT1H: '1h',\n PT2H: '2h',\n PT4H: '4h',\n PT8H: '8h',\n PT12H: '12h',\n P1D: '1d',\n P3D: '3d',\n P1W: '1w',\n P1M: '1M',\n};\n\nconst DEFAULT_BAR_COUNT = 1000;\n\nconst fetchOHLCPageBackward = async (req: {\n product_id: string;\n duration: string;\n time: number;\n series_id: string;\n}): Promise<IOHLC[]> => {\n const [, marketType, symbol] = decodePath(req.product_id);\n if (!symbol) throw new Error(`Unsupported product_id: ${req.product_id}`);\n if (marketType !== 'PERPETUAL' && marketType !== 'SPOT') {\n throw new Error(`Unsupported product_id: ${req.product_id}`);\n }\n\n const coin = symbol.split('-')[0];\n if (!coin) throw new Error(`Invalid symbol: ${symbol}`);\n\n const interval = DURATION_TO_HYPERLIQUID_INTERVAL[req.duration];\n if (!interval) throw new Error(`Unsupported duration: ${req.duration}`);\n\n const periodMs = convertDurationToOffset(req.duration);\n const endTime = req.time;\n const startTime = Math.max(0, endTime - DEFAULT_BAR_COUNT * periodMs);\n\n const res = await getCandleSnapshot({\n req: { coin, interval, startTime, endTime },\n });\n\n return (res ?? [])\n .map((x): IOHLC => {\n const createdAtMs = x.t;\n return {\n series_id: req.series_id,\n datasource_id: 'HYPERLIQUID',\n product_id: req.product_id,\n duration: req.duration,\n created_at: formatTime(createdAtMs),\n closed_at: formatTime(createdAtMs + periodMs),\n open: x.o,\n high: x.h,\n low: x.l,\n close: x.c,\n volume: x.v,\n open_interest: '0',\n };\n })\n .filter((x) => Date.parse(x.created_at) < endTime);\n};\n\nprovideOHLCService(\n terminal,\n {\n product_id_prefix: 'HYPERLIQUID/PERPETUAL/',\n duration_list: Object.keys(DURATION_TO_HYPERLIQUID_INTERVAL),\n direction: 'backward',\n },\n fetchOHLCPageBackward,\n);\n\nprovideOHLCService(\n terminal,\n {\n product_id_prefix: 'HYPERLIQUID/SPOT/',\n duration_list: Object.keys(DURATION_TO_HYPERLIQUID_INTERVAL),\n direction: 'backward',\n },\n fetchOHLCPageBackward,\n);\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cancelOrder.js","sourceRoot":"","sources":["../../../src/services/orders/cancelOrder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,UAAuB,EAAE,KAAa,EAAE,EAAE;;IAChF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"cancelOrder.js","sourceRoot":"","sources":["../../../src/services/orders/cancelOrder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,UAAuB,EAAE,KAAa,EAAE,EAAE;;IAChF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE;QACpB,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACzC,IAAI,OAAO,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,QAAQ,CAAA,KAAK,QAAQ,EAAE,CAAC;oBACzC,OAAO,MAAM,CAAC,QAAQ,CAAC;gBACzB,CAAC;YACH,CAAC;YAAC,WAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,EAAE,CAAC;IACL,MAAM,aAAa,GAAG,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,CAAC,MAAM,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;IACpF,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3F,MAAM,MAAM,GAAG,MAAA,MAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,QAAQ,0CAAE,IAAI,0CAAE,QAAQ,CAAC;IAC7C,MAAM,KAAK,GACT,CAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,MAAM,MAAK,IAAI;QAClB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ;YACxD,CAAC,CAAC,MAAA,MAAM,CAAC,CAAC,CAAC,0CAAE,KAAK;YAClB,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC,CAAC","sourcesContent":["import { IOrder } from '@yuants/data-order';\nimport { ICredential } from '../../api/types';\nimport { resolveAssetInfo } from '../utils';\nimport { cancelOrder } from '../../api/private-api';\n\nexport const cancelOrderAction = async (credential: ICredential, order: IOrder) => {\n const orderId = Number(order.order_id);\n if (!Number.isFinite(orderId)) {\n throw new Error(`Invalid order_id: ${order.order_id}`);\n }\n const assetId = (() => {\n if (order.comment) {\n try {\n const parsed = JSON.parse(order.comment);\n if (typeof parsed?.asset_id === 'number') {\n return parsed.asset_id;\n }\n } catch {\n // ignore\n }\n }\n return undefined;\n })();\n const resolvedAsset = assetId ?? (await resolveAssetInfo(order.product_id)).assetId;\n const res = await cancelOrder(credential, { cancels: [{ a: resolvedAsset, o: orderId }] });\n const status = res?.response?.data?.statuses;\n const error =\n res?.status !== 'ok'\n ? 'API ERROR'\n : Array.isArray(status) && typeof status[0] !== 'string'\n ? status[0]?.error\n : undefined;\n\n if (error) throw new Error(error);\n};\n"]}
|