@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.
Files changed (90) hide show
  1. package/dist/api/client.js +36 -2
  2. package/dist/api/client.js.map +1 -1
  3. package/dist/api/private-api.js +52 -41
  4. package/dist/api/private-api.js.map +1 -1
  5. package/dist/api/public-api.js +22 -11
  6. package/dist/api/public-api.js.map +1 -1
  7. package/dist/api/rate-limit.js +205 -0
  8. package/dist/api/rate-limit.js.map +1 -0
  9. package/dist/api/rate-limit.test.js +129 -0
  10. package/dist/api/rate-limit.test.js.map +1 -0
  11. package/dist/api/sign.js.map +1 -1
  12. package/dist/api/types.js.map +1 -1
  13. package/dist/index.js +0 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/services/accounts/spot.js.map +1 -1
  16. package/dist/services/exchange.js.map +1 -1
  17. package/dist/services/markets/quote.js.map +1 -1
  18. package/dist/services/ohlc-service.js.map +1 -1
  19. package/dist/services/orders/cancelOrder.js.map +1 -1
  20. package/dist/services/orders/listOrders.js +2 -2
  21. package/dist/services/orders/listOrders.js.map +1 -1
  22. package/dist/services/orders/modifyOrder.js.map +1 -1
  23. package/dist/services/quotes.js.map +1 -1
  24. package/dist/services/utils.js.map +1 -1
  25. package/lib/api/client.d.ts +1 -1
  26. package/lib/api/client.d.ts.map +1 -1
  27. package/lib/api/client.js +35 -1
  28. package/lib/api/client.js.map +1 -1
  29. package/lib/api/private-api.d.ts +67 -3
  30. package/lib/api/private-api.d.ts.map +1 -1
  31. package/lib/api/private-api.js +59 -43
  32. package/lib/api/private-api.js.map +1 -1
  33. package/lib/api/public-api.d.ts +61 -11
  34. package/lib/api/public-api.d.ts.map +1 -1
  35. package/lib/api/public-api.js +33 -12
  36. package/lib/api/public-api.js.map +1 -1
  37. package/lib/api/rate-limit.d.ts +21 -0
  38. package/lib/api/rate-limit.d.ts.map +1 -0
  39. package/lib/api/rate-limit.js +214 -0
  40. package/lib/api/rate-limit.js.map +1 -0
  41. package/lib/api/rate-limit.test.d.ts +2 -0
  42. package/lib/api/rate-limit.test.d.ts.map +1 -0
  43. package/lib/api/rate-limit.test.js +131 -0
  44. package/lib/api/rate-limit.test.js.map +1 -0
  45. package/lib/api/sign.js +5 -6
  46. package/lib/api/sign.js.map +1 -1
  47. package/lib/api/types.d.ts.map +1 -1
  48. package/lib/api/types.js.map +1 -1
  49. package/lib/index.d.ts +0 -2
  50. package/lib/index.d.ts.map +1 -1
  51. package/lib/index.js +0 -2
  52. package/lib/index.js.map +1 -1
  53. package/lib/services/accounts/perp.d.ts.map +1 -1
  54. package/lib/services/accounts/spot.d.ts.map +1 -1
  55. package/lib/services/accounts/spot.js.map +1 -1
  56. package/lib/services/exchange.js.map +1 -1
  57. package/lib/services/markets/product.d.ts.map +1 -1
  58. package/lib/services/markets/quote.js.map +1 -1
  59. package/lib/services/ohlc-service.js.map +1 -1
  60. package/lib/services/orders/cancelOrder.d.ts.map +1 -1
  61. package/lib/services/orders/cancelOrder.js.map +1 -1
  62. package/lib/services/orders/listOrders.d.ts.map +1 -1
  63. package/lib/services/orders/listOrders.js +2 -2
  64. package/lib/services/orders/listOrders.js.map +1 -1
  65. package/lib/services/orders/modifyOrder.d.ts.map +1 -1
  66. package/lib/services/orders/modifyOrder.js.map +1 -1
  67. package/lib/services/orders/submitOrder.d.ts.map +1 -1
  68. package/lib/services/quotes.js.map +1 -1
  69. package/lib/services/utils.d.ts +2 -2
  70. package/lib/services/utils.d.ts.map +1 -1
  71. package/lib/services/utils.js.map +1 -1
  72. package/lib/tsdoc-metadata.json +1 -1
  73. package/package.json +48 -48
  74. package/temp/build/typescript/ts_HOjXkPSo.json +1 -0
  75. package/temp/package-deps.json +27 -27
  76. package/temp/test/jest/haste-map-1a3370ad4952cc1cbecf8fc42c6e9732-7b2990dcc44090c4eba2c52e971c544c-6a2a6e27ca3579da37751287ea19ab4c +0 -0
  77. package/temp/test/jest/perf-cache-1a3370ad4952cc1cbecf8fc42c6e9732-da39a3ee5e6b4b0d3255bfef95601890 +1 -0
  78. package/temp/vendor-hyperliquid.api.json +18 -2
  79. package/dist/services/markets/interest-rate.js +0 -60
  80. package/dist/services/markets/interest-rate.js.map +0 -1
  81. package/dist/services/markets/ohlc.js +0 -110
  82. package/dist/services/markets/ohlc.js.map +0 -1
  83. package/lib/services/markets/interest-rate.d.ts +0 -2
  84. package/lib/services/markets/interest-rate.d.ts.map +0 -1
  85. package/lib/services/markets/interest-rate.js +0 -62
  86. package/lib/services/markets/interest-rate.js.map +0 -1
  87. package/lib/services/markets/ohlc.d.ts +0 -2
  88. package/lib/services/markets/ohlc.d.ts.map +0 -1
  89. package/lib/services/markets/ohlc.js +0 -112
  90. 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"]}
@@ -1 +1 @@
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"]}
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"]}
@@ -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;QAChB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;KAC5E;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"]}
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
@@ -1,6 +1,4 @@
1
1
  import './services/exchange';
2
- import './services/markets/interest-rate';
3
- import './services/markets/ohlc';
4
2
  import './services/markets/product';
5
3
  import './services/markets/quote';
6
4
  import './services/quotes';
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,kCAAkC,CAAC;AAC1C,OAAO,yBAAyB,CAAC;AACjC,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/interest-rate';\nimport './services/markets/ohlc';\nimport './services/markets/product';\nimport './services/markets/quote';\nimport './services/quotes';\nimport './services/ohlc-service';\nimport './services/interest-rate-service';\n"]}
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;QAC9B,MAAM,CAAC,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,QAAQ,KAAK,MAAM,EAAE;YACvB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;SACpD;KACF;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
+ {"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":"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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
+ {"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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","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
+ {"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":"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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
+ {"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,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;IAExD,MAAM,QAAQ,GAAG,gCAAgC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAExE,MAAM,QAAQ,GAAG,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC;IACzB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,iBAAiB,GAAG,QAAQ,CAAC,CAAC;IAEtE,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC;QAClC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE;KAC5C,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,aAAH,GAAG,cAAH,GAAG,GAAI,EAAE,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAS,EAAE;QAChB,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,aAAa,EAAE,aAAa;YAC5B,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,UAAU,EAAE,UAAU,CAAC,WAAW,CAAC;YACnC,SAAS,EAAE,UAAU,CAAC,WAAW,GAAG,QAAQ,CAAC;YAC7C,IAAI,EAAE,CAAC,CAAC,CAAC;YACT,IAAI,EAAE,CAAC,CAAC,CAAC;YACT,GAAG,EAAE,CAAC,CAAC,CAAC;YACR,KAAK,EAAE,CAAC,CAAC,CAAC;YACV,MAAM,EAAE,CAAC,CAAC,CAAC;YACX,aAAa,EAAE,GAAG;SACnB,CAAC;IACJ,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,CAAC;AACvD,CAAC,CAAC;AAEF,kBAAkB,CAChB,QAAQ,EACR;IACE,iBAAiB,EAAE,wBAAwB;IAC3C,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC;IAC5D,SAAS,EAAE,UAAU;CACtB,EACD,qBAAqB,CACtB,CAAC;AAEF,kBAAkB,CAChB,QAAQ,EACR;IACE,iBAAiB,EAAE,mBAAmB;IACtC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC;IAC5D,SAAS,EAAE,UAAU;CACtB,EACD,qBAAqB,CACtB,CAAC","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;QAC7B,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;KACxD;IACD,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE;QACpB,IAAI,KAAK,CAAC,OAAO,EAAE;YACjB,IAAI;gBACF,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;oBACxC,OAAO,MAAM,CAAC,QAAQ,CAAC;iBACxB;aACF;YAAC,WAAM;gBACN,SAAS;aACV;SACF;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"]}
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"]}