@nktkas/hyperliquid 0.25.6 → 0.25.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -8
- package/esm/src/api/info/webData2.d.ts +146 -23
- package/esm/src/api/info/webData2.d.ts.map +1 -1
- package/esm/src/api/info/webData2.js +3 -54
- package/esm/src/api/info/webData2.js.map +1 -1
- package/esm/src/api/info/~client.d.ts +2 -2
- package/esm/src/api/subscription/webData2.d.ts +4 -4
- package/esm/src/api/subscription/webData2.js +1 -1
- package/esm/src/api/subscription/webData2.js.map +1 -1
- package/esm/src/api/subscription/webData3.d.ts +541 -0
- package/esm/src/api/subscription/webData3.d.ts.map +1 -0
- package/esm/src/api/subscription/webData3.js +94 -0
- package/esm/src/api/subscription/webData3.js.map +1 -0
- package/esm/src/api/subscription/~client.d.ts +22 -0
- package/esm/src/api/subscription/~client.d.ts.map +1 -1
- package/esm/src/api/subscription/~client.js +23 -0
- package/esm/src/api/subscription/~client.js.map +1 -1
- package/esm/src/api/subscription/~mod.d.ts +1 -0
- package/esm/src/api/subscription/~mod.d.ts.map +1 -1
- package/esm/src/api/subscription/~mod.js +1 -0
- package/esm/src/api/subscription/~mod.js.map +1 -1
- package/esm/src/utils/_format.d.ts +29 -0
- package/esm/src/utils/_format.d.ts.map +1 -0
- package/esm/src/utils/_format.js +147 -0
- package/esm/src/utils/_format.js.map +1 -0
- package/esm/src/utils/_symbolConverter.d.ts +13 -0
- package/esm/src/utils/_symbolConverter.d.ts.map +1 -1
- package/esm/src/utils/_symbolConverter.js +17 -0
- package/esm/src/utils/_symbolConverter.js.map +1 -1
- package/esm/src/utils/mod.d.ts +1 -0
- package/esm/src/utils/mod.d.ts.map +1 -1
- package/esm/src/utils/mod.js +1 -0
- package/esm/src/utils/mod.js.map +1 -1
- package/package.json +1 -1
- package/script/src/api/info/webData2.d.ts +146 -23
- package/script/src/api/info/webData2.d.ts.map +1 -1
- package/script/src/api/info/webData2.js +2 -53
- package/script/src/api/info/webData2.js.map +1 -1
- package/script/src/api/info/~client.d.ts +2 -2
- package/script/src/api/subscription/webData2.d.ts +4 -4
- package/script/src/api/subscription/webData2.js +1 -1
- package/script/src/api/subscription/webData2.js.map +1 -1
- package/script/src/api/subscription/webData3.d.ts +541 -0
- package/script/src/api/subscription/webData3.d.ts.map +1 -0
- package/script/src/api/subscription/webData3.js +131 -0
- package/script/src/api/subscription/webData3.js.map +1 -0
- package/script/src/api/subscription/~client.d.ts +22 -0
- package/script/src/api/subscription/~client.d.ts.map +1 -1
- package/script/src/api/subscription/~client.js +23 -0
- package/script/src/api/subscription/~client.js.map +1 -1
- package/script/src/api/subscription/~mod.d.ts +1 -0
- package/script/src/api/subscription/~mod.d.ts.map +1 -1
- package/script/src/api/subscription/~mod.js +1 -0
- package/script/src/api/subscription/~mod.js.map +1 -1
- package/script/src/utils/_format.d.ts +29 -0
- package/script/src/utils/_format.d.ts.map +1 -0
- package/script/src/utils/_format.js +151 -0
- package/script/src/utils/_format.js.map +1 -0
- package/script/src/utils/_symbolConverter.d.ts +13 -0
- package/script/src/utils/_symbolConverter.d.ts.map +1 -1
- package/script/src/utils/_symbolConverter.js +17 -0
- package/script/src/utils/_symbolConverter.js.map +1 -1
- package/script/src/utils/mod.d.ts +1 -0
- package/script/src/utils/mod.d.ts.map +1 -1
- package/script/src/utils/mod.js +1 -0
- package/script/src/utils/mod.js.map +1 -1
- package/src/src/api/info/webData2.ts +3 -104
- package/src/src/api/subscription/webData2.ts +1 -1
- package/src/src/api/subscription/webData3.ts +179 -0
- package/src/src/api/subscription/~client.ts +25 -0
- package/src/src/api/subscription/~mod.ts +1 -0
- package/src/src/utils/_format.ts +172 -0
- package/src/src/utils/_symbolConverter.ts +18 -0
- package/src/src/utils/mod.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../../src/src/utils/mod.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../../src/src/utils/mod.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC"}
|
package/script/src/utils/mod.js
CHANGED
|
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./_symbolConverter.js"), exports);
|
|
18
|
+
__exportStar(require("./_format.js"), exports);
|
|
18
19
|
//# sourceMappingURL=mod.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../../../src/src/utils/mod.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC"}
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../../../src/src/utils/mod.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,+CAA6B"}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import * as v from "valibot";
|
|
2
|
-
import { Address, type DeepImmutable, parser
|
|
2
|
+
import { Address, type DeepImmutable, parser } from "../_base.js";
|
|
3
3
|
import type { InfoRequestConfig } from "./_types.js";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { MetaAndAssetCtxsResponse } from "./metaAndAssetCtxs.js";
|
|
7
|
-
import { ClearinghouseStateResponse } from "./clearinghouseState.js";
|
|
8
|
-
import { SpotClearinghouseStateResponse } from "./spotClearinghouseState.js";
|
|
9
|
-
import { SpotMetaAndAssetCtxsResponse } from "./spotMetaAndAssetCtxs.js";
|
|
5
|
+
import { WebData2Event } from "../subscription/webData2.js";
|
|
10
6
|
|
|
11
7
|
// -------------------- Schemas --------------------
|
|
12
8
|
|
|
@@ -39,104 +35,7 @@ export type WebData2Request = v.InferOutput<typeof WebData2Request>;
|
|
|
39
35
|
*/
|
|
40
36
|
export const WebData2Response = /* @__PURE__ */ (() => {
|
|
41
37
|
return v.pipe(
|
|
42
|
-
|
|
43
|
-
/** Account summary for perpetual trading. */
|
|
44
|
-
clearinghouseState: ClearinghouseStateResponse,
|
|
45
|
-
/** Array of leading vaults. */
|
|
46
|
-
leadingVaults: v.pipe(
|
|
47
|
-
v.array(
|
|
48
|
-
/** Vault that a user is leading. */
|
|
49
|
-
v.pipe(
|
|
50
|
-
v.object({
|
|
51
|
-
/** Address of the vault. */
|
|
52
|
-
address: v.pipe(
|
|
53
|
-
Address,
|
|
54
|
-
v.description("Address of the vault."),
|
|
55
|
-
),
|
|
56
|
-
/** Name of the vault. */
|
|
57
|
-
name: v.pipe(
|
|
58
|
-
v.string(),
|
|
59
|
-
v.description("Name of the vault."),
|
|
60
|
-
),
|
|
61
|
-
}),
|
|
62
|
-
v.description("Vault that a user is leading."),
|
|
63
|
-
),
|
|
64
|
-
),
|
|
65
|
-
v.description("Array of leading vaults."),
|
|
66
|
-
),
|
|
67
|
-
/** Total equity in vaults. */
|
|
68
|
-
totalVaultEquity: v.pipe(
|
|
69
|
-
UnsignedDecimal,
|
|
70
|
-
v.description("Total equity in vaults."),
|
|
71
|
-
),
|
|
72
|
-
/** Array of user open orders with frontend information. */
|
|
73
|
-
openOrders: v.pipe(
|
|
74
|
-
v.array(DetailedOrderSchema),
|
|
75
|
-
v.description("User open orders with frontend information."),
|
|
76
|
-
),
|
|
77
|
-
/** Agent address if one exists. */
|
|
78
|
-
agentAddress: v.pipe(
|
|
79
|
-
v.nullable(Address),
|
|
80
|
-
v.description("Agent address if one exists."),
|
|
81
|
-
),
|
|
82
|
-
/** Timestamp until which the agent is valid. */
|
|
83
|
-
agentValidUntil: v.pipe(
|
|
84
|
-
v.nullable(UnsignedInteger),
|
|
85
|
-
v.description("Timestamp until which the agent is valid."),
|
|
86
|
-
),
|
|
87
|
-
/** Cumulative ledger value. */
|
|
88
|
-
cumLedger: v.pipe(
|
|
89
|
-
UnsignedDecimal,
|
|
90
|
-
v.description("Cumulative ledger value."),
|
|
91
|
-
),
|
|
92
|
-
/** Metadata for perpetual assets. */
|
|
93
|
-
meta: MetaAndAssetCtxsResponse.items[0],
|
|
94
|
-
/** Context for each perpetual asset. */
|
|
95
|
-
assetCtxs: MetaAndAssetCtxsResponse.items[1],
|
|
96
|
-
/** Server timestamp (in ms since epoch). */
|
|
97
|
-
serverTime: v.pipe(
|
|
98
|
-
UnsignedInteger,
|
|
99
|
-
v.description("Server timestamp (in ms since epoch)."),
|
|
100
|
-
),
|
|
101
|
-
/** Whether this account is a vault. */
|
|
102
|
-
isVault: v.pipe(
|
|
103
|
-
v.boolean(),
|
|
104
|
-
v.description("Whether this account is a vault."),
|
|
105
|
-
),
|
|
106
|
-
/** User address. */
|
|
107
|
-
user: v.pipe(
|
|
108
|
-
Address,
|
|
109
|
-
v.description("User address."),
|
|
110
|
-
),
|
|
111
|
-
/** Array of TWAP states. */
|
|
112
|
-
twapStates: v.pipe(
|
|
113
|
-
v.array(
|
|
114
|
-
/** TWAP ID and state. */
|
|
115
|
-
v.pipe(
|
|
116
|
-
v.tuple([
|
|
117
|
-
UnsignedInteger,
|
|
118
|
-
TwapStateSchema,
|
|
119
|
-
]),
|
|
120
|
-
v.description("TWAP ID and state."),
|
|
121
|
-
),
|
|
122
|
-
),
|
|
123
|
-
v.description("Array of TWAP states."),
|
|
124
|
-
),
|
|
125
|
-
/** Account summary for spot trading. */
|
|
126
|
-
spotState: SpotClearinghouseStateResponse,
|
|
127
|
-
/** Context for each spot asset. */
|
|
128
|
-
spotAssetCtxs: SpotMetaAndAssetCtxsResponse.items[1],
|
|
129
|
-
/** Whether the user has opted out of spot dusting. */
|
|
130
|
-
optOutOfSpotDusting: v.pipe(
|
|
131
|
-
v.optional(v.literal(true)),
|
|
132
|
-
v.description("Whether the user has opted out of spot dusting."),
|
|
133
|
-
),
|
|
134
|
-
/** Assets currently at their open interest cap. */
|
|
135
|
-
perpsAtOpenInterestCap: v.pipe(
|
|
136
|
-
v.optional(v.array(v.string())),
|
|
137
|
-
v.description("Assets currently at their open interest cap."),
|
|
138
|
-
),
|
|
139
|
-
}),
|
|
38
|
+
WebData2Event,
|
|
140
39
|
v.description("Comprehensive user and market data."),
|
|
141
40
|
);
|
|
142
41
|
})();
|
|
@@ -118,7 +118,7 @@ export const WebData2Event = /* @__PURE__ */ (() => {
|
|
|
118
118
|
v.description("Array of TWAP states."),
|
|
119
119
|
),
|
|
120
120
|
/** Account summary for spot trading. */
|
|
121
|
-
spotState: SpotClearinghouseStateResponse,
|
|
121
|
+
spotState: v.optional(SpotClearinghouseStateResponse),
|
|
122
122
|
/** Context for each spot asset. */
|
|
123
123
|
spotAssetCtxs: SpotMetaAndAssetCtxsResponse.items[1],
|
|
124
124
|
/** Whether the user has opted out of spot dusting. */
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import { Address, type DeepImmutable, parser, UnsignedDecimal, UnsignedInteger } from "../_base.js";
|
|
3
|
+
import type { SubscriptionRequestConfig } from "./_types.js";
|
|
4
|
+
import type { Subscription } from "../../transport/base.js";
|
|
5
|
+
|
|
6
|
+
import { DetailedOrderSchema } from "../_common_schemas.js";
|
|
7
|
+
import { MetaAndAssetCtxsResponse } from "../info/metaAndAssetCtxs.js";
|
|
8
|
+
import { ClearinghouseStateResponse } from "../info/clearinghouseState.js";
|
|
9
|
+
|
|
10
|
+
// -------------------- Schemas --------------------
|
|
11
|
+
|
|
12
|
+
/** Subscription to comprehensive user and market data events. */
|
|
13
|
+
export const WebData3Request = /* @__PURE__ */ (() => {
|
|
14
|
+
return v.pipe(
|
|
15
|
+
v.object({
|
|
16
|
+
/** Type of subscription. */
|
|
17
|
+
type: v.pipe(
|
|
18
|
+
v.literal("webData3"),
|
|
19
|
+
v.description("Type of subscription."),
|
|
20
|
+
),
|
|
21
|
+
/** User address. */
|
|
22
|
+
user: v.pipe(
|
|
23
|
+
Address,
|
|
24
|
+
v.description("User address."),
|
|
25
|
+
),
|
|
26
|
+
}),
|
|
27
|
+
v.description("Subscription to comprehensive user and market data events."),
|
|
28
|
+
);
|
|
29
|
+
})();
|
|
30
|
+
export type WebData3Request = v.InferOutput<typeof WebData3Request>;
|
|
31
|
+
|
|
32
|
+
/** Event of comprehensive user and market data. */
|
|
33
|
+
export const WebData3Event = /* @__PURE__ */ (() => {
|
|
34
|
+
return v.pipe(
|
|
35
|
+
v.object({
|
|
36
|
+
/** User state information. */
|
|
37
|
+
userState: v.pipe(
|
|
38
|
+
v.object({
|
|
39
|
+
/** Agent address if one exists. */
|
|
40
|
+
agentAddress: v.pipe(
|
|
41
|
+
v.nullable(Address),
|
|
42
|
+
v.description("Agent address if one exists."),
|
|
43
|
+
),
|
|
44
|
+
/** Timestamp until which the agent is valid. */
|
|
45
|
+
agentValidUntil: v.pipe(
|
|
46
|
+
v.nullable(UnsignedInteger),
|
|
47
|
+
v.description("Timestamp until which the agent is valid."),
|
|
48
|
+
),
|
|
49
|
+
/** Cumulative ledger value. */
|
|
50
|
+
cumLedger: v.pipe(
|
|
51
|
+
UnsignedDecimal,
|
|
52
|
+
v.description("Cumulative ledger value."),
|
|
53
|
+
),
|
|
54
|
+
/** Server timestamp (in ms since epoch). */
|
|
55
|
+
serverTime: v.pipe(
|
|
56
|
+
UnsignedInteger,
|
|
57
|
+
v.description("Server timestamp (in ms since epoch)."),
|
|
58
|
+
),
|
|
59
|
+
/** Whether this account is a vault. */
|
|
60
|
+
isVault: v.pipe(
|
|
61
|
+
v.boolean(),
|
|
62
|
+
v.description("Whether this account is a vault."),
|
|
63
|
+
),
|
|
64
|
+
/** User address. */
|
|
65
|
+
user: v.pipe(
|
|
66
|
+
Address,
|
|
67
|
+
v.description("User address."),
|
|
68
|
+
),
|
|
69
|
+
/** Whether the user has opted out of spot dusting. */
|
|
70
|
+
optOutOfSpotDusting: v.pipe(
|
|
71
|
+
v.optional(v.literal(true)),
|
|
72
|
+
v.description("Whether the user has opted out of spot dusting."),
|
|
73
|
+
),
|
|
74
|
+
/** Whether DEX abstraction is enabled. */
|
|
75
|
+
dexAbstractionEnabled: v.pipe(
|
|
76
|
+
v.optional(v.boolean()),
|
|
77
|
+
v.description("Whether DEX abstraction is enabled."),
|
|
78
|
+
),
|
|
79
|
+
}),
|
|
80
|
+
v.description("User state information."),
|
|
81
|
+
),
|
|
82
|
+
/** Array of perpetual DEX states. */
|
|
83
|
+
perpDexStates: v.pipe(
|
|
84
|
+
v.array(
|
|
85
|
+
v.object({
|
|
86
|
+
/** Account summary for perpetual trading. */
|
|
87
|
+
clearinghouseState: ClearinghouseStateResponse,
|
|
88
|
+
/** Total equity in vaults. */
|
|
89
|
+
totalVaultEquity: v.pipe(
|
|
90
|
+
UnsignedDecimal,
|
|
91
|
+
v.description("Total equity in vaults."),
|
|
92
|
+
),
|
|
93
|
+
/** Array of user open orders with frontend information. */
|
|
94
|
+
openOrders: v.pipe(
|
|
95
|
+
v.optional(v.array(DetailedOrderSchema)),
|
|
96
|
+
v.description("User open orders with frontend information."),
|
|
97
|
+
),
|
|
98
|
+
/** Context for each perpetual asset. */
|
|
99
|
+
assetCtxs: MetaAndAssetCtxsResponse.items[1],
|
|
100
|
+
/** Assets currently at their open interest cap. */
|
|
101
|
+
perpsAtOpenInterestCap: v.pipe(
|
|
102
|
+
v.optional(v.array(v.string())),
|
|
103
|
+
v.description("Assets currently at their open interest cap."),
|
|
104
|
+
),
|
|
105
|
+
/** Array of leading vaults. */
|
|
106
|
+
leadingVaults: v.pipe(
|
|
107
|
+
v.optional(
|
|
108
|
+
v.array(
|
|
109
|
+
/** Vault that a user is leading. */
|
|
110
|
+
v.pipe(
|
|
111
|
+
v.object({
|
|
112
|
+
/** Address of the vault. */
|
|
113
|
+
address: v.pipe(
|
|
114
|
+
Address,
|
|
115
|
+
v.description("Address of the vault."),
|
|
116
|
+
),
|
|
117
|
+
/** Name of the vault. */
|
|
118
|
+
name: v.pipe(
|
|
119
|
+
v.string(),
|
|
120
|
+
v.description("Name of the vault."),
|
|
121
|
+
),
|
|
122
|
+
}),
|
|
123
|
+
v.description("Vault that a user is leading."),
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
v.description("Array of leading vaults."),
|
|
128
|
+
),
|
|
129
|
+
}),
|
|
130
|
+
),
|
|
131
|
+
v.description("Array of perpetual DEX states."),
|
|
132
|
+
),
|
|
133
|
+
}),
|
|
134
|
+
v.description("Comprehensive user and market data."),
|
|
135
|
+
);
|
|
136
|
+
})();
|
|
137
|
+
export type WebData3Event = v.InferOutput<typeof WebData3Event>;
|
|
138
|
+
|
|
139
|
+
// -------------------- Function --------------------
|
|
140
|
+
|
|
141
|
+
/** Request parameters for the {@linkcode webData3} function. */
|
|
142
|
+
export type WebData3Parameters = Omit<v.InferInput<typeof WebData3Request>, "type">;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Subscribe to comprehensive user and market data updates.
|
|
146
|
+
* @param config - General configuration for Subscription API subscriptions.
|
|
147
|
+
* @param params - Parameters specific to the API subscription.
|
|
148
|
+
* @param listener - A callback function to be called when the event is received.
|
|
149
|
+
* @returns A request-promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
|
|
150
|
+
*
|
|
151
|
+
* @throws {TransportError} When the transport layer throws an error.
|
|
152
|
+
*
|
|
153
|
+
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* import { WebSocketTransport } from "@nktkas/hyperliquid";
|
|
157
|
+
* import { webData3 } from "@nktkas/hyperliquid/api/subscription";
|
|
158
|
+
*
|
|
159
|
+
* const transport = new WebSocketTransport();
|
|
160
|
+
*
|
|
161
|
+
* const sub = await webData3(
|
|
162
|
+
* { transport },
|
|
163
|
+
* { user: "0x..." },
|
|
164
|
+
* (data) => console.log(data),
|
|
165
|
+
* );
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export function webData3(
|
|
169
|
+
config: SubscriptionRequestConfig,
|
|
170
|
+
params: DeepImmutable<WebData3Parameters>,
|
|
171
|
+
listener: (data: WebData3Event) => void,
|
|
172
|
+
): Promise<Subscription> {
|
|
173
|
+
const payload = parser(WebData3Request)({ type: "webData3", ...params });
|
|
174
|
+
return config.transport.subscribe<WebData3Event>(payload.type, payload, (e) => {
|
|
175
|
+
if (e.detail.userState.user === payload.user) {
|
|
176
|
+
listener(e.detail);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
@@ -25,6 +25,7 @@ import { userNonFundingLedgerUpdates } from "./userNonFundingLedgerUpdates.js";
|
|
|
25
25
|
import { userTwapHistory } from "./userTwapHistory.js";
|
|
26
26
|
import { userTwapSliceFills } from "./userTwapSliceFills.js";
|
|
27
27
|
import { webData2 } from "./webData2.js";
|
|
28
|
+
import { webData3 } from "./webData3.js";
|
|
28
29
|
|
|
29
30
|
export type {
|
|
30
31
|
ActiveAssetCtxEvent as WsActiveAssetCtxEvent,
|
|
@@ -94,6 +95,7 @@ export type {
|
|
|
94
95
|
UserTwapSliceFillsParameters as WsUserTwapSliceFillsParameters,
|
|
95
96
|
} from "./userTwapSliceFills.js";
|
|
96
97
|
export type { WebData2Event as WsWebData2Event, WebData2Parameters as WsWebData2Parameters } from "./webData2.js";
|
|
98
|
+
export type { WebData3Event as WsWebData3Event, WebData3Parameters as WsWebData3Parameters } from "./webData3.js";
|
|
97
99
|
|
|
98
100
|
export type { SubscriptionRequestConfig } from "./_types.js";
|
|
99
101
|
|
|
@@ -660,4 +662,27 @@ export class SubscriptionClient<
|
|
|
660
662
|
webData2(...args: OmitFirst<OverloadedParameters<typeof webData2>>) {
|
|
661
663
|
return webData2(this, ...args);
|
|
662
664
|
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Subscribe to comprehensive user and market data updates.
|
|
668
|
+
* @param params - Parameters specific to the API subscription.
|
|
669
|
+
* @param listener - A callback function to be called when the event is received.
|
|
670
|
+
* @returns A request-promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
|
|
671
|
+
*
|
|
672
|
+
* @throws {TransportError} When the transport layer throws an error.
|
|
673
|
+
*
|
|
674
|
+
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
|
|
675
|
+
* @example
|
|
676
|
+
* ```ts
|
|
677
|
+
* import * as hl from "@nktkas/hyperliquid";
|
|
678
|
+
*
|
|
679
|
+
* const transport = new hl.WebSocketTransport();
|
|
680
|
+
*
|
|
681
|
+
* const client = new hl.SubscriptionClient({ transport });
|
|
682
|
+
* const sub = await client.webData3({ user: "0x..." }, (data) => console.log(data));
|
|
683
|
+
* ```
|
|
684
|
+
*/
|
|
685
|
+
webData3(...args: OmitFirst<OverloadedParameters<typeof webData3>>) {
|
|
686
|
+
return webData3(this, ...args);
|
|
687
|
+
}
|
|
663
688
|
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { HyperliquidError } from "../_base.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Format price according to Hyperliquid {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size | rules}:
|
|
5
|
+
* - Maximum 5 significant figures
|
|
6
|
+
* - Maximum (6 for perp, 8 for spot) - `szDecimals` decimal places
|
|
7
|
+
* - Integer prices are always allowed regardless of significant figures
|
|
8
|
+
* - Remove trailing zeros
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { formatPrice } from "@nktkas/hyperliquid/utils";
|
|
12
|
+
*
|
|
13
|
+
* // `true` for perp (default), `false` for spot
|
|
14
|
+
* // ⌄⌄⌄⌄⌄
|
|
15
|
+
* const price = formatPrice("0.0000123456789", 0, false); // → "0.00001234"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function formatPrice(
|
|
19
|
+
price: string | number,
|
|
20
|
+
szDecimals: number,
|
|
21
|
+
isPerp: boolean = true,
|
|
22
|
+
): string {
|
|
23
|
+
// Prepare: trim, validate, normalize leading/trailing zeros
|
|
24
|
+
let priceStr = prepareNumber(typeof price === "string" ? price : price.toString());
|
|
25
|
+
|
|
26
|
+
// Integer prices bypass sig figs limit per spec
|
|
27
|
+
if (!priceStr.includes(".")) {
|
|
28
|
+
return priceStr;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Apply decimal limit: max (6 for perp, 8 for spot) - `szDecimals` decimals
|
|
32
|
+
const maxDecimals = Math.max((isPerp ? 6 : 8) - szDecimals, 0);
|
|
33
|
+
priceStr = truncateDecimals(priceStr, maxDecimals);
|
|
34
|
+
|
|
35
|
+
// Apply sig figs limit: max 5 significant figures
|
|
36
|
+
priceStr = truncateSigFigs(priceStr, 5);
|
|
37
|
+
|
|
38
|
+
return priceStr;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Format size according to Hyperliquid {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size | rules}:
|
|
43
|
+
* - Truncate to `szDecimals` decimal places
|
|
44
|
+
* - Remove trailing zeros
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { formatSize } from "@nktkas/hyperliquid/utils";
|
|
48
|
+
*
|
|
49
|
+
* const size = formatSize("1.23456789", 5); // → "1.23456"
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function formatSize(size: string | number, szDecimals: number): string {
|
|
53
|
+
// Prepare: trim, validate, normalize leading/trailing zeros
|
|
54
|
+
let sizeStr = prepareNumber(typeof size === "string" ? size : size.toString());
|
|
55
|
+
|
|
56
|
+
// Truncate to `szDecimals` decimal places
|
|
57
|
+
sizeStr = truncateDecimals(sizeStr, szDecimals);
|
|
58
|
+
|
|
59
|
+
return sizeStr;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Prepare number string for processing:
|
|
64
|
+
* 1. Trim whitespace
|
|
65
|
+
* 2. Validate format (decimal number, not hex/scientific)
|
|
66
|
+
* 3. Normalize: remove leading zeros from integer part, trailing zeros from decimal part
|
|
67
|
+
*/
|
|
68
|
+
function prepareNumber(numStr: string): string {
|
|
69
|
+
const trimmed = numStr.trim();
|
|
70
|
+
|
|
71
|
+
// Validate: only decimal numbers allowed (no hex, scientific notation, etc)
|
|
72
|
+
if (!/^-?(\d+\.?\d*|\.\d+)$/.test(trimmed)) {
|
|
73
|
+
throw new HyperliquidError(`Invalid number format: ${numStr}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Normalize: remove leading zeros from integer, trailing zeros from decimal
|
|
77
|
+
const [int, dec] = trimmed.split(".");
|
|
78
|
+
const trimmedInt = int.replace(/^0+/, "") || "0";
|
|
79
|
+
const trimmedDec = dec?.replace(/0+$/, "");
|
|
80
|
+
return trimmedInt + (trimmedDec ? "." + trimmedDec : "");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** String-based Math operations for arbitrary precision */
|
|
84
|
+
const StringMath = {
|
|
85
|
+
/** Absolute value: remove negative sign if present */
|
|
86
|
+
abs(numStr: string): string {
|
|
87
|
+
return numStr[0] === "-" ? numStr.slice(1) : numStr;
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/** Floor log10 (magnitude): position of most significant digit */
|
|
91
|
+
log10Floor(numStr: string): number {
|
|
92
|
+
const abs = this.abs(numStr);
|
|
93
|
+
const [int, dec] = abs.split(".");
|
|
94
|
+
|
|
95
|
+
// Number >= 1: magnitude = length of integer part - 1
|
|
96
|
+
if (int !== "0") {
|
|
97
|
+
const trimmed = int.replace(/^0+/, "");
|
|
98
|
+
return trimmed.length - 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Number < 1: count leading zeros in decimal part
|
|
102
|
+
if (!dec) return -Infinity;
|
|
103
|
+
const leadingZeros = dec.match(/^0*/)?.[0].length ?? 0;
|
|
104
|
+
return -(leadingZeros + 1);
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/** Multiply by 10^exp: shift decimal point left (negative) or right (positive) */
|
|
108
|
+
multiplyByPow10(numStr: string, exp: number): string {
|
|
109
|
+
if (exp === 0) return numStr;
|
|
110
|
+
|
|
111
|
+
const neg = numStr[0] === "-";
|
|
112
|
+
const abs = neg ? numStr.slice(1) : numStr;
|
|
113
|
+
const [int, dec = ""] = abs.split(".");
|
|
114
|
+
|
|
115
|
+
if (exp > 0) {
|
|
116
|
+
// Shift right: move digits from decimal to integer
|
|
117
|
+
if (exp >= dec.length) {
|
|
118
|
+
return (neg ? "-" : "") + int + dec + "0".repeat(exp - dec.length);
|
|
119
|
+
}
|
|
120
|
+
return (neg ? "-" : "") + int + dec.slice(0, exp) + "." + dec.slice(exp);
|
|
121
|
+
} else {
|
|
122
|
+
// Shift left: move digits from integer to decimal
|
|
123
|
+
const absExp = -exp;
|
|
124
|
+
if (absExp >= int.length) {
|
|
125
|
+
return (neg ? "-" : "") + "0." + "0".repeat(absExp - int.length) + int + dec;
|
|
126
|
+
}
|
|
127
|
+
return (neg ? "-" : "") + int.slice(0, -absExp) + "." + int.slice(-absExp) + dec;
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
/** Truncate: remove decimal part */
|
|
132
|
+
trunc(numStr: string): string {
|
|
133
|
+
const dotIndex = numStr.indexOf(".");
|
|
134
|
+
return dotIndex === -1 ? numStr : numStr.slice(0, dotIndex);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/** Truncate to specified decimal places */
|
|
139
|
+
function truncateDecimals(numStr: string, maxDecimals: number): string {
|
|
140
|
+
const dotIndex = numStr.indexOf(".");
|
|
141
|
+
if (dotIndex === -1) return numStr;
|
|
142
|
+
|
|
143
|
+
const truncated = numStr.substring(0, dotIndex + maxDecimals + 1);
|
|
144
|
+
|
|
145
|
+
// Remove trailing zeros from decimal
|
|
146
|
+
const [int, dec] = truncated.split(".");
|
|
147
|
+
const trimmedDec = dec?.replace(/0+$/, "");
|
|
148
|
+
return trimmedDec ? int + "." + trimmedDec : int;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Truncate to specified significant figures using string-based math */
|
|
152
|
+
function truncateSigFigs(numStr: string, maxSigFigs: number): string {
|
|
153
|
+
if (parseFloat(numStr) === 0) return "0";
|
|
154
|
+
|
|
155
|
+
const neg = numStr[0] === "-";
|
|
156
|
+
const abs = neg ? numStr.slice(1) : numStr;
|
|
157
|
+
|
|
158
|
+
// Calculate how much to shift: align most significant digit to ones place + (maxSigFigs-1)
|
|
159
|
+
const magnitude = StringMath.log10Floor(abs);
|
|
160
|
+
const shiftAmount = maxSigFigs - magnitude - 1;
|
|
161
|
+
|
|
162
|
+
// Shift right, truncate integer part, shift back
|
|
163
|
+
const shifted = StringMath.multiplyByPow10(abs, shiftAmount);
|
|
164
|
+
const truncated = StringMath.trunc(shifted);
|
|
165
|
+
const result = StringMath.multiplyByPow10(truncated, -shiftAmount);
|
|
166
|
+
|
|
167
|
+
// Remove trailing zeros introduced by shifting
|
|
168
|
+
const final = neg ? "-" + result : result;
|
|
169
|
+
const [int, dec] = final.split(".");
|
|
170
|
+
const trimmedDec = dec?.replace(/0+$/, "");
|
|
171
|
+
return trimmedDec ? int + "." + trimmedDec : int;
|
|
172
|
+
}
|
|
@@ -25,6 +25,9 @@ export interface SymbolConverterOptions {
|
|
|
25
25
|
* const transport = new HttpTransport(); // or `WebSocketTransport`
|
|
26
26
|
* const converter = await SymbolConverter.create({ transport });
|
|
27
27
|
*
|
|
28
|
+
* // By default, dexs are not loaded; specify them when creating an instance
|
|
29
|
+
* // const converter = await SymbolConverter.create({ transport, dexs: ["test"] });
|
|
30
|
+
*
|
|
28
31
|
* const btcId = converter.getAssetId("BTC"); // perpetual → 0
|
|
29
32
|
* const hypeUsdcId = converter.getAssetId("HYPE/USDC"); // spot market → 10107
|
|
30
33
|
* const dexAbcId = converter.getAssetId("test:ABC"); // builder dex (if enabled) → 110000
|
|
@@ -32,6 +35,8 @@ export interface SymbolConverterOptions {
|
|
|
32
35
|
* const btcSzDecimals = converter.getSzDecimals("BTC"); // perpetual → 5
|
|
33
36
|
* const hypeUsdcSzDecimals = converter.getSzDecimals("HYPE/USDC"); // spot market → 2
|
|
34
37
|
* const dexAbcSzDecimals = converter.getSzDecimals("test:ABC"); // builder dex (if enabled) → 0
|
|
38
|
+
*
|
|
39
|
+
* const spotPairId = converter.getSpotPairId("HFUN/USDC"); // → "@2"
|
|
35
40
|
* ```
|
|
36
41
|
*/
|
|
37
42
|
export class SymbolConverter {
|
|
@@ -39,6 +44,7 @@ export class SymbolConverter {
|
|
|
39
44
|
private readonly dexOption: DexOption;
|
|
40
45
|
private readonly nameToAssetId = new Map<string, number>();
|
|
41
46
|
private readonly nameToSzDecimals = new Map<string, number>();
|
|
47
|
+
private readonly nameToSpotPairId = new Map<string, string>();
|
|
42
48
|
|
|
43
49
|
private constructor(options: SymbolConverterOptions) {
|
|
44
50
|
this.transport = options.transport;
|
|
@@ -86,6 +92,7 @@ export class SymbolConverter {
|
|
|
86
92
|
|
|
87
93
|
this.nameToAssetId.clear();
|
|
88
94
|
this.nameToSzDecimals.clear();
|
|
95
|
+
this.nameToSpotPairId.clear();
|
|
89
96
|
|
|
90
97
|
this.processDefaultPerps(perpMetaData);
|
|
91
98
|
this.processSpotAssets(spotMetaData);
|
|
@@ -158,6 +165,7 @@ export class SymbolConverter {
|
|
|
158
165
|
const baseQuoteKey = `${baseToken.name}/${quoteToken.name}`;
|
|
159
166
|
this.nameToAssetId.set(baseQuoteKey, assetId);
|
|
160
167
|
this.nameToSzDecimals.set(baseQuoteKey, baseToken.szDecimals);
|
|
168
|
+
this.nameToSpotPairId.set(baseQuoteKey, market.name);
|
|
161
169
|
});
|
|
162
170
|
}
|
|
163
171
|
|
|
@@ -182,4 +190,14 @@ export class SymbolConverter {
|
|
|
182
190
|
getSzDecimals(name: string): number | undefined {
|
|
183
191
|
return this.nameToSzDecimals.get(name);
|
|
184
192
|
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get spot pair ID for info endpoints and subscriptions (e.g., l2book, trades).
|
|
196
|
+
*
|
|
197
|
+
* Accepts spot markets in the "BASE/QUOTE" format (e.g., "HFUN/USDC").
|
|
198
|
+
* @example "HFUN/USDC" → "@2", "PURR/USDC" → "PURR/USDC"
|
|
199
|
+
*/
|
|
200
|
+
getSpotPairId(name: string): string | undefined {
|
|
201
|
+
return this.nameToSpotPairId.get(name);
|
|
202
|
+
}
|
|
185
203
|
}
|
package/src/src/utils/mod.ts
CHANGED