@lifi/perps-sdk-provider-hyperliquid 0.0.0-preview-c3f47bd → 0.0.0-preview-2edcdb1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/HyperliquidProvider.d.ts.map +1 -1
- package/dist/cjs/HyperliquidProvider.js +2 -0
- package/dist/cjs/HyperliquidProvider.js.map +1 -1
- package/dist/cjs/accountConfig.d.ts.map +1 -1
- package/dist/cjs/accountConfig.js +1 -0
- package/dist/cjs/accountConfig.js.map +1 -1
- package/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +5 -3
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/services/getAccount.d.ts.map +1 -1
- package/dist/cjs/services/getAccount.js +4 -4
- package/dist/cjs/services/getAccount.js.map +1 -1
- package/dist/cjs/services/getAccountExists.d.ts +8 -0
- package/dist/cjs/services/getAccountExists.d.ts.map +1 -0
- package/dist/cjs/services/getAccountExists.js +15 -0
- package/dist/cjs/services/getAccountExists.js.map +1 -0
- package/dist/cjs/types/account.d.ts +3 -0
- package/dist/cjs/types/account.d.ts.map +1 -1
- package/dist/cjs/types/account.js.map +1 -1
- package/dist/cjs/types/ws.d.ts +56 -1
- package/dist/cjs/types/ws.d.ts.map +1 -1
- package/dist/cjs/utils/decodeFastAssetCtxs.d.ts +1 -0
- package/dist/cjs/utils/decodeFastAssetCtxs.d.ts.map +1 -1
- package/dist/cjs/utils/decodeFastAssetCtxs.js +5 -1
- package/dist/cjs/utils/decodeFastAssetCtxs.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +2 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
- package/dist/cjs/utils/mapOrder.js +12 -5
- package/dist/cjs/utils/mapOrder.js.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +22 -0
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +430 -28
- package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/esm/HyperliquidProvider.d.ts.map +1 -1
- package/dist/esm/HyperliquidProvider.js +2 -0
- package/dist/esm/HyperliquidProvider.js.map +1 -1
- package/dist/esm/accountConfig.d.ts.map +1 -1
- package/dist/esm/accountConfig.js +1 -0
- package/dist/esm/accountConfig.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +2 -2
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +12 -9
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/services/getAccount.d.ts.map +1 -1
- package/dist/esm/services/getAccount.js +10 -7
- package/dist/esm/services/getAccount.js.map +1 -1
- package/dist/esm/services/getAccountExists.d.ts +22 -0
- package/dist/esm/services/getAccountExists.d.ts.map +1 -0
- package/dist/esm/services/getAccountExists.js +20 -0
- package/dist/esm/services/getAccountExists.js.map +1 -0
- package/dist/esm/types/account.d.ts +9 -0
- package/dist/esm/types/account.d.ts.map +1 -1
- package/dist/esm/types/account.js.map +1 -1
- package/dist/esm/types/ws.d.ts +75 -1
- package/dist/esm/types/ws.d.ts.map +1 -1
- package/dist/esm/utils/decodeFastAssetCtxs.d.ts +1 -0
- package/dist/esm/utils/decodeFastAssetCtxs.d.ts.map +1 -1
- package/dist/esm/utils/decodeFastAssetCtxs.js +9 -6
- package/dist/esm/utils/decodeFastAssetCtxs.js.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/mapOrder.d.ts +11 -1
- package/dist/esm/utils/mapOrder.d.ts.map +1 -1
- package/dist/esm/utils/mapOrder.js +23 -6
- package/dist/esm/utils/mapOrder.js.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts +27 -8
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +439 -47
- package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/types/HyperliquidProvider.d.ts.map +1 -1
- package/dist/types/accountConfig.d.ts.map +1 -1
- package/dist/types/accountSummary.d.ts +2 -2
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/services/getAccount.d.ts.map +1 -1
- package/dist/types/services/getAccountExists.d.ts +22 -0
- package/dist/types/services/getAccountExists.d.ts.map +1 -0
- package/dist/types/types/account.d.ts +9 -0
- package/dist/types/types/account.d.ts.map +1 -1
- package/dist/types/types/ws.d.ts +75 -1
- package/dist/types/types/ws.d.ts.map +1 -1
- package/dist/types/utils/decodeFastAssetCtxs.d.ts +1 -0
- package/dist/types/utils/decodeFastAssetCtxs.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +1 -1
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/mapOrder.d.ts +11 -1
- package/dist/types/utils/mapOrder.d.ts.map +1 -1
- package/dist/types/websocket/HyperliquidWsProvider.d.ts +27 -8
- package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/HyperliquidProvider.ts +8 -0
- package/src/accountConfig.ts +1 -0
- package/src/accountSummary.ts +12 -9
- package/src/index.ts +2 -0
- package/src/services/getAccount.ts +10 -11
- package/src/services/getAccountExists.ts +40 -0
- package/src/types/account.ts +10 -0
- package/src/types/ws.ts +79 -1
- package/src/utils/decodeFastAssetCtxs.ts +10 -6
- package/src/utils/index.ts +4 -1
- package/src/utils/mapOrder.ts +23 -6
- package/src/websocket/HyperliquidWsProvider.ts +558 -49
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HyperliquidWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/HyperliquidWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAGlB,cAAc,EACd,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,
|
|
1
|
+
{"version":3,"file":"HyperliquidWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/HyperliquidWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAGlB,cAAc,EACd,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,mBAAmB,CAAA;AAsD1B,eAAO,MAAM,qBAAqB,QAC5B,iBAEgD,CAAA;AAgBtD,qBAAa,qBAAsB,SAAQ,cAAc,CAAC,MAAM,CAAC;IAC/D,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,eAAe,CAAsD;IAC7E,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,uBAAuB,CAAiC;IAChE,OAAO,CAAC,yBAAyB,CAAuC;IAKxE,OAAO,CAAC,iBAAiB,CAAuC;IAGhE,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,oBAAoB,CAAmC;gBAEnD,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc;IASjE,cAAc,CAClB,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;cAkBN,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAqEnE,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,2BAA2B;IAWnC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,gBAAgB;cAcL,OAAO,IAAI,IAAI;IAalC,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAM9C,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;IA0B1C,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,WAAW;IA6CnB,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM;IA8EnC,OAAO,CAAC,sBAAsB;IAK9B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,oBAAoB;IAqB5B,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,oBAAoB;IA2B5B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,kBAAkB;IA0D1B,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,+BAA+B;IAkBvC,OAAO,CAAC,eAAe;CAaxB"}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.HyperliquidWsProvider = exports.hyperliquidWsProvider = void 0;
|
|
4
7
|
const perps_sdk_1 = require("@lifi/perps-sdk");
|
|
5
8
|
const perps_types_1 = require("@lifi/perps-types");
|
|
9
|
+
const big_js_1 = __importDefault(require("big.js"));
|
|
6
10
|
const constants_js_1 = require("../constants.js");
|
|
7
11
|
const index_js_1 = require("../utils/index.js");
|
|
8
12
|
const HL_L2_BOOK_MAX_LEVELS_PER_SIDE = 20;
|
|
@@ -13,8 +17,14 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
13
17
|
client;
|
|
14
18
|
registry;
|
|
15
19
|
perpCtxBySubDex = new Map();
|
|
20
|
+
spotCtxByMarketId = {};
|
|
21
|
+
orderbookKeysByMarketId = new Map();
|
|
22
|
+
latestOrderbookByMarketId = new Map();
|
|
16
23
|
fastCtxByMarketId = {};
|
|
17
24
|
fastDecodeChain = Promise.resolve();
|
|
25
|
+
pacDecodeChain = Promise.resolve();
|
|
26
|
+
sacDecodeChain = Promise.resolve();
|
|
27
|
+
orderbookDecodeChain = Promise.resolve();
|
|
18
28
|
constructor(wsUrl, providerKey, client) {
|
|
19
29
|
super(new perps_sdk_1.ReconnectingWebSocket(wsUrl, { pingPayload: '{"method":"ping"}' }), providerKey);
|
|
20
30
|
this.client = client;
|
|
@@ -45,19 +55,32 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
45
55
|
this.rws.send(JSON.stringify({ method: 'unsubscribe', subscription: payload }));
|
|
46
56
|
}
|
|
47
57
|
this.perpCtxBySubDex.clear();
|
|
58
|
+
this.spotCtxByMarketId = {};
|
|
48
59
|
this.fastCtxByMarketId = {};
|
|
49
60
|
};
|
|
50
61
|
}
|
|
51
62
|
const key = this.toKey(sub);
|
|
63
|
+
if (sub.channel === 'orderbook') {
|
|
64
|
+
this.claimOrderbookKey(sub.marketId, key);
|
|
65
|
+
}
|
|
52
66
|
const payload = this.toHlPayload(sub);
|
|
53
67
|
await this.registerSub(key, payload);
|
|
68
|
+
if (sub.channel === 'orderbook') {
|
|
69
|
+
this.registerOrderbook(sub.marketId, key);
|
|
70
|
+
}
|
|
54
71
|
await this.rws.ready();
|
|
55
72
|
return () => {
|
|
56
73
|
this.unregisterSub(key);
|
|
57
74
|
if (this.orderUpdatesKey === key) {
|
|
58
75
|
this.orderUpdatesKey = undefined;
|
|
59
76
|
}
|
|
60
|
-
this.rws.send(JSON.stringify({
|
|
77
|
+
this.rws.send(JSON.stringify({
|
|
78
|
+
method: 'unsubscribe',
|
|
79
|
+
subscription: payload,
|
|
80
|
+
}));
|
|
81
|
+
if (sub.channel === 'orderbook') {
|
|
82
|
+
this.releaseOrderbook(sub.marketId, key);
|
|
83
|
+
}
|
|
61
84
|
};
|
|
62
85
|
}
|
|
63
86
|
claimOrderUpdatesKey(key) {
|
|
@@ -72,15 +95,57 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
72
95
|
}
|
|
73
96
|
this.orderUpdatesKey = key;
|
|
74
97
|
}
|
|
98
|
+
claimOrderbookKey(marketId, key) {
|
|
99
|
+
const activeKeys = this.orderbookKeysByMarketId.get(marketId);
|
|
100
|
+
if (activeKeys === undefined) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
for (const activeKey of [...activeKeys]) {
|
|
104
|
+
if (activeKey === key) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (!this.closeChannelIfIdle(activeKey)) {
|
|
108
|
+
throw new Error(`Hyperliquid supports one orderbook aggregation per market per ` +
|
|
109
|
+
`provider instance. Unsubscribe ${activeKey} before subscribing ${key}.`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
75
113
|
getMarketsContextSubEntries() {
|
|
76
114
|
return [
|
|
77
|
-
{ subKey: '
|
|
115
|
+
{ subKey: 'pac', payload: { type: 'pac' } },
|
|
116
|
+
{ subKey: 'sac', payload: { type: 'sac' } },
|
|
78
117
|
{ subKey: 'fastAssetCtxs', payload: { type: 'fastAssetCtxs' } },
|
|
79
118
|
];
|
|
80
119
|
}
|
|
120
|
+
registerOrderbook(marketId, orderbookKey) {
|
|
121
|
+
let activeKeys = this.orderbookKeysByMarketId.get(marketId);
|
|
122
|
+
if (activeKeys === undefined) {
|
|
123
|
+
activeKeys = new Set();
|
|
124
|
+
this.orderbookKeysByMarketId.set(marketId, activeKeys);
|
|
125
|
+
}
|
|
126
|
+
activeKeys.add(orderbookKey);
|
|
127
|
+
}
|
|
128
|
+
releaseOrderbook(marketId, orderbookKey) {
|
|
129
|
+
const activeKeys = this.orderbookKeysByMarketId.get(marketId);
|
|
130
|
+
if (activeKeys === undefined) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
activeKeys.delete(orderbookKey);
|
|
134
|
+
if (activeKeys.size > 0) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.orderbookKeysByMarketId.delete(marketId);
|
|
138
|
+
}
|
|
81
139
|
onClose() {
|
|
82
140
|
this.perpCtxBySubDex.clear();
|
|
141
|
+
this.spotCtxByMarketId = {};
|
|
83
142
|
this.fastCtxByMarketId = {};
|
|
143
|
+
this.orderbookKeysByMarketId.clear();
|
|
144
|
+
this.latestOrderbookByMarketId.clear();
|
|
145
|
+
this.fastDecodeChain = Promise.resolve();
|
|
146
|
+
this.pacDecodeChain = Promise.resolve();
|
|
147
|
+
this.sacDecodeChain = Promise.resolve();
|
|
148
|
+
this.orderbookDecodeChain = Promise.resolve();
|
|
84
149
|
this.orderUpdatesKey = undefined;
|
|
85
150
|
}
|
|
86
151
|
sendSubscribe(payload) {
|
|
@@ -90,10 +155,14 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
90
155
|
switch (sub.channel) {
|
|
91
156
|
case 'marketsContext':
|
|
92
157
|
return 'marketsContext';
|
|
158
|
+
case 'marketContext':
|
|
159
|
+
return `marketContext:${sub.marketId}`;
|
|
93
160
|
case 'orderbook':
|
|
94
|
-
return `
|
|
161
|
+
return `l2:${sub.marketId}:${this.orderbookAggregationKey(sub.marketId, sub.priceStep)}`;
|
|
95
162
|
case 'candle':
|
|
96
163
|
return `candle:${sub.marketId}:${sub.interval}`;
|
|
164
|
+
case 'trades':
|
|
165
|
+
return `trades:${sub.marketId}`;
|
|
97
166
|
case 'orderUpdates':
|
|
98
167
|
return `orderUpdates:${sub.address.toLowerCase()}`;
|
|
99
168
|
case 'fills':
|
|
@@ -104,24 +173,50 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
104
173
|
return `spotState:${sub.address.toLowerCase()}`;
|
|
105
174
|
}
|
|
106
175
|
}
|
|
176
|
+
orderbookAggregation(marketId, priceStep) {
|
|
177
|
+
if (priceStep === undefined) {
|
|
178
|
+
return {};
|
|
179
|
+
}
|
|
180
|
+
return (0, index_js_1.priceStepToAggregation)(priceStep, this.orderbookReferencePrice(marketId));
|
|
181
|
+
}
|
|
182
|
+
orderbookAggregationKey(marketId, priceStep) {
|
|
183
|
+
const aggregation = this.orderbookAggregation(marketId, priceStep);
|
|
184
|
+
const nSigFigs = aggregation.nSigFigs ?? null;
|
|
185
|
+
const mantissa = aggregation.mantissa ?? null;
|
|
186
|
+
if (nSigFigs === null && mantissa === null) {
|
|
187
|
+
return 'full';
|
|
188
|
+
}
|
|
189
|
+
return `s:${nSigFigs}:m:${mantissa}`;
|
|
190
|
+
}
|
|
107
191
|
toHlPayload(sub) {
|
|
108
192
|
switch (sub.channel) {
|
|
109
193
|
case 'marketsContext':
|
|
110
194
|
return { type: 'allDexsAssetCtxs' };
|
|
111
|
-
case '
|
|
195
|
+
case 'marketContext':
|
|
112
196
|
return {
|
|
113
|
-
type: '
|
|
197
|
+
type: 'activeAssetCtx',
|
|
114
198
|
coin: sub.marketId,
|
|
115
|
-
...(sub.priceStep !== undefined
|
|
116
|
-
? (0, index_js_1.priceStepToAggregation)(sub.priceStep, this.mergedMids().get(sub.marketId) ?? Number.NaN)
|
|
117
|
-
: {}),
|
|
118
199
|
};
|
|
200
|
+
case 'orderbook': {
|
|
201
|
+
const aggregation = this.orderbookAggregation(sub.marketId, sub.priceStep);
|
|
202
|
+
return {
|
|
203
|
+
type: 'l2',
|
|
204
|
+
c: sub.marketId,
|
|
205
|
+
s: aggregation.nSigFigs ?? null,
|
|
206
|
+
m: aggregation.mantissa ?? null,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
119
209
|
case 'candle':
|
|
120
210
|
return {
|
|
121
211
|
type: 'candle',
|
|
122
212
|
coin: sub.marketId,
|
|
123
213
|
interval: sub.interval,
|
|
124
214
|
};
|
|
215
|
+
case 'trades':
|
|
216
|
+
return {
|
|
217
|
+
type: 'trades',
|
|
218
|
+
coin: sub.marketId,
|
|
219
|
+
};
|
|
125
220
|
case 'orderUpdates':
|
|
126
221
|
return { type: 'orderUpdates', user: sub.address };
|
|
127
222
|
case 'fills':
|
|
@@ -159,15 +254,33 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
159
254
|
case 'allDexsAssetCtxs':
|
|
160
255
|
this.handleAllDexsAssetCtxs(msg.data);
|
|
161
256
|
break;
|
|
257
|
+
case 'pac':
|
|
258
|
+
this.handlePac(msg.data);
|
|
259
|
+
break;
|
|
260
|
+
case 'sac':
|
|
261
|
+
this.handleSac(msg.data);
|
|
262
|
+
break;
|
|
162
263
|
case 'fastAssetCtxs':
|
|
163
264
|
this.handleFastAssetCtxs(msg.data);
|
|
164
265
|
break;
|
|
266
|
+
case 'activeAssetCtx':
|
|
267
|
+
this.handleActiveAssetCtx(msg.data, raw);
|
|
268
|
+
break;
|
|
269
|
+
case 'activeSpotAssetCtx':
|
|
270
|
+
this.handleActiveSpotAssetCtx(msg.data);
|
|
271
|
+
break;
|
|
272
|
+
case 'l2':
|
|
273
|
+
this.handleL2(msg.data);
|
|
274
|
+
break;
|
|
165
275
|
case 'l2Book':
|
|
166
276
|
this.handleL2Book(msg.data);
|
|
167
277
|
break;
|
|
168
278
|
case 'candle':
|
|
169
279
|
this.handleCandle(msg.data);
|
|
170
280
|
break;
|
|
281
|
+
case 'trades':
|
|
282
|
+
this.handleTrades(msg.data);
|
|
283
|
+
break;
|
|
171
284
|
case 'orderUpdates':
|
|
172
285
|
this.handleOrderUpdates(msg.data);
|
|
173
286
|
break;
|
|
@@ -187,14 +300,65 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
187
300
|
}
|
|
188
301
|
}
|
|
189
302
|
handleAllDexsAssetCtxs(data) {
|
|
190
|
-
|
|
191
|
-
|
|
303
|
+
this.mergePerpAssetCtxEntries(allDexsAssetCtxEntries(data));
|
|
304
|
+
this.emitMarketsContext();
|
|
305
|
+
}
|
|
306
|
+
handlePac(base64) {
|
|
307
|
+
this.pacDecodeChain = this.pacDecodeChain
|
|
308
|
+
.then(async () => {
|
|
309
|
+
this.mergePerpAssetCtxEntries(await (0, index_js_1.decodeCompressedJson)(base64));
|
|
310
|
+
this.emitMarketsContext();
|
|
311
|
+
})
|
|
312
|
+
.catch((error) => perps_sdk_1.wsLog.handlerFailure(this.providerKey, error));
|
|
313
|
+
}
|
|
314
|
+
mergePerpAssetCtxEntries(entries) {
|
|
315
|
+
for (const [dex, ctxs] of entries) {
|
|
316
|
+
const previous = this.perpCtxBySubDex.get(dex || 'default');
|
|
317
|
+
const byMarketId = {
|
|
318
|
+
...(previous ?? {}),
|
|
319
|
+
};
|
|
192
320
|
for (const ctx of ctxs) {
|
|
193
|
-
|
|
321
|
+
const marketId = ctx.coin;
|
|
322
|
+
if (marketId === undefined) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const merged = mergePerpAssetCtx(previous?.[marketId], marketId, ctx);
|
|
326
|
+
if (merged !== undefined) {
|
|
327
|
+
byMarketId[marketId] = merged;
|
|
328
|
+
}
|
|
194
329
|
}
|
|
195
330
|
this.perpCtxBySubDex.set(dex || 'default', byMarketId);
|
|
196
331
|
}
|
|
197
|
-
|
|
332
|
+
}
|
|
333
|
+
handleSac(base64) {
|
|
334
|
+
this.sacDecodeChain = this.sacDecodeChain
|
|
335
|
+
.then(async () => {
|
|
336
|
+
const spotMarketIdBySacKey = this.spotMarketIdBySacKey();
|
|
337
|
+
const ctxs = await (0, index_js_1.decodeCompressedJson)(base64);
|
|
338
|
+
for (const [sacKey, ctx] of Object.entries(ctxs)) {
|
|
339
|
+
const marketId = spotMarketIdBySacKey.get(sacKey);
|
|
340
|
+
if (marketId === undefined) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
this.spotCtxByMarketId[marketId] = {
|
|
344
|
+
...this.spotCtxByMarketId[marketId],
|
|
345
|
+
...ctx,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
this.emitMarketsContext();
|
|
349
|
+
})
|
|
350
|
+
.catch((error) => perps_sdk_1.wsLog.handlerFailure(this.providerKey, error));
|
|
351
|
+
}
|
|
352
|
+
spotMarketIdBySacKey() {
|
|
353
|
+
const map = new Map();
|
|
354
|
+
for (const market of this.registry?.markets ?? []) {
|
|
355
|
+
if (market.categoryId !== constants_js_1.SPOT_MARKET_ID) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
map.set(market.id, market.id);
|
|
359
|
+
map.set(`${market.baseAsset.displaySymbol}/${market.quoteAsset.displaySymbol}`, market.id);
|
|
360
|
+
}
|
|
361
|
+
return map;
|
|
198
362
|
}
|
|
199
363
|
handleFastAssetCtxs(base64) {
|
|
200
364
|
this.fastDecodeChain = this.fastDecodeChain
|
|
@@ -224,6 +388,13 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
224
388
|
};
|
|
225
389
|
}
|
|
226
390
|
}
|
|
391
|
+
for (const [marketId, ctx] of Object.entries(this.spotCtxByMarketId)) {
|
|
392
|
+
const context = mapSpotMarketContext(marketId, ctx, this.fastCtxByMarketId[marketId]);
|
|
393
|
+
if (context === undefined) {
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
data[marketId] = context;
|
|
397
|
+
}
|
|
227
398
|
for (const [marketId, fast] of Object.entries(this.fastCtxByMarketId)) {
|
|
228
399
|
if (data[marketId] !== undefined) {
|
|
229
400
|
continue;
|
|
@@ -236,6 +407,27 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
236
407
|
}
|
|
237
408
|
this.emit('marketsContext', { channel: 'marketsContext', data });
|
|
238
409
|
}
|
|
410
|
+
handleActiveAssetCtx(data, raw) {
|
|
411
|
+
const ctx = activePerpAssetCtx(data.coin, data.ctx);
|
|
412
|
+
if (ctx === undefined) {
|
|
413
|
+
perps_sdk_1.wsLog.parseFailure(this.providerKey, raw);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
this.emit(`marketContext:${data.coin}`, {
|
|
417
|
+
channel: 'marketContext',
|
|
418
|
+
data: (0, index_js_1.mapMarketContext)(data.coin, ctx),
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
handleActiveSpotAssetCtx(data) {
|
|
422
|
+
const context = mapSpotMarketContext(data.coin, data.ctx);
|
|
423
|
+
if (context === undefined) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
this.emit(`marketContext:${data.coin}`, {
|
|
427
|
+
channel: 'marketContext',
|
|
428
|
+
data: context,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
239
431
|
mergedMids() {
|
|
240
432
|
const map = new Map();
|
|
241
433
|
for (const byMarketId of this.perpCtxBySubDex.values()) {
|
|
@@ -244,6 +436,12 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
244
436
|
map.set(id, Number(mid));
|
|
245
437
|
}
|
|
246
438
|
}
|
|
439
|
+
for (const [id, ctx] of Object.entries(this.spotCtxByMarketId)) {
|
|
440
|
+
const mid = ctx.midPx ?? ctx.markPx;
|
|
441
|
+
if (mid != null) {
|
|
442
|
+
map.set(id, Number(mid));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
247
445
|
for (const [id, fast] of Object.entries(this.fastCtxByMarketId)) {
|
|
248
446
|
const mid = fast.midPx ?? fast.markPx;
|
|
249
447
|
if (mid != null) {
|
|
@@ -252,21 +450,74 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
252
450
|
}
|
|
253
451
|
return map;
|
|
254
452
|
}
|
|
453
|
+
orderbookReferencePrice(marketId) {
|
|
454
|
+
const mid = this.mergedMids().get(marketId);
|
|
455
|
+
if (mid !== undefined) {
|
|
456
|
+
return mid;
|
|
457
|
+
}
|
|
458
|
+
const book = this.latestOrderbookByMarketId.get(marketId);
|
|
459
|
+
const bid = book?.bids[0]?.price;
|
|
460
|
+
const ask = book?.asks[0]?.price;
|
|
461
|
+
if (bid !== undefined && ask !== undefined) {
|
|
462
|
+
return (Number(bid) + Number(ask)) / 2;
|
|
463
|
+
}
|
|
464
|
+
return Number.NaN;
|
|
465
|
+
}
|
|
255
466
|
handleL2Book(data) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
467
|
+
const book = {
|
|
468
|
+
provider: this.providerKey,
|
|
469
|
+
marketId: data.coin,
|
|
470
|
+
bids: data.levels[0]
|
|
471
|
+
.slice(0, HL_L2_BOOK_MAX_LEVELS_PER_SIDE)
|
|
472
|
+
.map((l) => ({ price: l.px, size: l.sz })),
|
|
473
|
+
asks: data.levels[1]
|
|
474
|
+
.slice(0, HL_L2_BOOK_MAX_LEVELS_PER_SIDE)
|
|
475
|
+
.map((l) => ({ price: l.px, size: l.sz })),
|
|
476
|
+
timestamp: data.time,
|
|
477
|
+
};
|
|
478
|
+
this.latestOrderbookByMarketId.set(data.coin, book);
|
|
479
|
+
this.emitOrderbook(data.coin, book);
|
|
480
|
+
}
|
|
481
|
+
handleL2(data) {
|
|
482
|
+
if (data.s !== undefined) {
|
|
483
|
+
this.handleL2Book(data.s);
|
|
484
|
+
}
|
|
485
|
+
if (data.u !== undefined) {
|
|
486
|
+
this.handleCompactL2Delta(data.u);
|
|
487
|
+
}
|
|
488
|
+
if (data.c === undefined) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const compressed = data.c;
|
|
492
|
+
this.orderbookDecodeChain = this.orderbookDecodeChain
|
|
493
|
+
.then(async () => {
|
|
494
|
+
this.handleCompactL2Delta(await (0, index_js_1.decodeCompressedJson)(compressed));
|
|
495
|
+
})
|
|
496
|
+
.catch((error) => perps_sdk_1.wsLog.handlerFailure(this.providerKey, error));
|
|
497
|
+
}
|
|
498
|
+
handleCompactL2Delta(delta) {
|
|
499
|
+
const previous = this.latestOrderbookByMarketId.get(delta.c);
|
|
500
|
+
if (previous === undefined) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const book = {
|
|
504
|
+
provider: this.providerKey,
|
|
505
|
+
marketId: delta.c,
|
|
506
|
+
bids: applyCompressedL2Side(previous.bids, delta.l[0], delta.r?.[0] ?? [], 'bid'),
|
|
507
|
+
asks: applyCompressedL2Side(previous.asks, delta.l[1], delta.r?.[1] ?? [], 'ask'),
|
|
508
|
+
timestamp: delta.t,
|
|
509
|
+
};
|
|
510
|
+
this.latestOrderbookByMarketId.set(delta.c, book);
|
|
511
|
+
this.emitOrderbook(delta.c, book);
|
|
512
|
+
}
|
|
513
|
+
emitOrderbook(marketId, book) {
|
|
514
|
+
const keys = this.orderbookKeysByMarketId.get(marketId);
|
|
515
|
+
if (keys === undefined) {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
for (const key of keys) {
|
|
519
|
+
this.emit(key, { channel: 'orderbook', data: book });
|
|
520
|
+
}
|
|
270
521
|
}
|
|
271
522
|
handleCandle(data) {
|
|
272
523
|
this.emit(`candle:${data.s}:${data.i}`, {
|
|
@@ -281,6 +532,24 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
281
532
|
},
|
|
282
533
|
});
|
|
283
534
|
}
|
|
535
|
+
handleTrades(data) {
|
|
536
|
+
for (const trade of data) {
|
|
537
|
+
this.emit(`trades:${trade.coin}`, {
|
|
538
|
+
channel: 'trades',
|
|
539
|
+
data: [
|
|
540
|
+
{
|
|
541
|
+
provider: this.providerKey,
|
|
542
|
+
marketId: trade.coin,
|
|
543
|
+
price: trade.px,
|
|
544
|
+
size: trade.sz,
|
|
545
|
+
timestamp: trade.time,
|
|
546
|
+
side: trade.side === 'B' ? 'buy' : 'sell',
|
|
547
|
+
id: trade.tid !== undefined ? String(trade.tid) : trade.hash,
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
}
|
|
284
553
|
handleOrderUpdates(data) {
|
|
285
554
|
const key = this.orderUpdatesKey;
|
|
286
555
|
if (key === undefined) {
|
|
@@ -373,8 +642,134 @@ class HyperliquidWsProvider extends perps_sdk_1.WsProviderBase {
|
|
|
373
642
|
}
|
|
374
643
|
exports.HyperliquidWsProvider = HyperliquidWsProvider;
|
|
375
644
|
const isObject = (v) => typeof v === 'object' && v !== null;
|
|
645
|
+
const toMarketContextString = (value) => typeof value === 'string' || typeof value === 'number'
|
|
646
|
+
? String(value)
|
|
647
|
+
: undefined;
|
|
648
|
+
const toMarketCapString = (price, circulatingSupply) => {
|
|
649
|
+
const priceString = toMarketContextString(price);
|
|
650
|
+
const supplyString = toMarketContextString(circulatingSupply);
|
|
651
|
+
if (priceString === undefined || supplyString === undefined) {
|
|
652
|
+
return undefined;
|
|
653
|
+
}
|
|
654
|
+
try {
|
|
655
|
+
const parsedPrice = new big_js_1.default(priceString);
|
|
656
|
+
const parsedSupply = new big_js_1.default(supplyString);
|
|
657
|
+
if (parsedPrice.lte(0) || parsedSupply.lte(0)) {
|
|
658
|
+
return undefined;
|
|
659
|
+
}
|
|
660
|
+
return parsedPrice.times(parsedSupply).toFixed();
|
|
661
|
+
}
|
|
662
|
+
catch {
|
|
663
|
+
return undefined;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
function mergePerpAssetCtx(previous, marketId, update) {
|
|
667
|
+
const funding = update.funding ?? previous?.funding;
|
|
668
|
+
const openInterest = update.openInterest ?? previous?.openInterest;
|
|
669
|
+
const dayNtlVlm = update.dayNtlVlm ?? previous?.dayNtlVlm;
|
|
670
|
+
const prevDayPx = update.prevDayPx ?? previous?.prevDayPx;
|
|
671
|
+
const markPx = update.markPx ?? previous?.markPx;
|
|
672
|
+
const midPx = 'midPx' in update ? update.midPx : previous?.midPx;
|
|
673
|
+
const oraclePx = update.oraclePx ?? previous?.oraclePx;
|
|
674
|
+
if (funding === undefined ||
|
|
675
|
+
openInterest === undefined ||
|
|
676
|
+
dayNtlVlm === undefined ||
|
|
677
|
+
prevDayPx === undefined ||
|
|
678
|
+
markPx === undefined ||
|
|
679
|
+
midPx === undefined ||
|
|
680
|
+
oraclePx === undefined) {
|
|
681
|
+
return undefined;
|
|
682
|
+
}
|
|
683
|
+
return {
|
|
684
|
+
coin: marketId,
|
|
685
|
+
funding,
|
|
686
|
+
openInterest,
|
|
687
|
+
dayNtlVlm,
|
|
688
|
+
prevDayPx,
|
|
689
|
+
markPx,
|
|
690
|
+
midPx,
|
|
691
|
+
oraclePx,
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function allDexsAssetCtxEntries(data) {
|
|
695
|
+
return data.assetCtxs ?? data.ctxs ?? [];
|
|
696
|
+
}
|
|
697
|
+
function activePerpAssetCtx(marketId, ctx) {
|
|
698
|
+
const funding = toMarketContextString(ctx.funding);
|
|
699
|
+
const openInterest = toMarketContextString(ctx.openInterest);
|
|
700
|
+
const dayNtlVlm = toMarketContextString(ctx.dayNtlVlm);
|
|
701
|
+
const prevDayPx = toMarketContextString(ctx.prevDayPx);
|
|
702
|
+
const markPx = toMarketContextString(ctx.markPx);
|
|
703
|
+
const midPx = ctx.midPx === undefined || ctx.midPx === null
|
|
704
|
+
? null
|
|
705
|
+
: (toMarketContextString(ctx.midPx) ?? null);
|
|
706
|
+
const oraclePx = toMarketContextString(ctx.oraclePx);
|
|
707
|
+
if (funding === undefined ||
|
|
708
|
+
openInterest === undefined ||
|
|
709
|
+
dayNtlVlm === undefined ||
|
|
710
|
+
prevDayPx === undefined ||
|
|
711
|
+
markPx === undefined ||
|
|
712
|
+
oraclePx === undefined) {
|
|
713
|
+
return undefined;
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
coin: marketId,
|
|
717
|
+
funding,
|
|
718
|
+
openInterest,
|
|
719
|
+
dayNtlVlm,
|
|
720
|
+
prevDayPx,
|
|
721
|
+
markPx,
|
|
722
|
+
midPx,
|
|
723
|
+
oraclePx,
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function mapSpotMarketContext(marketId, ctx, fast) {
|
|
727
|
+
const midPrice = toMarketContextString(ctx.midPx ?? ctx.markPx);
|
|
728
|
+
const markPrice = toMarketContextString(ctx.markPx);
|
|
729
|
+
if (midPrice === undefined || markPrice === undefined) {
|
|
730
|
+
return undefined;
|
|
731
|
+
}
|
|
732
|
+
const emittedMarkPrice = fast?.markPx != null ? fast.markPx : markPrice;
|
|
733
|
+
return {
|
|
734
|
+
marketId,
|
|
735
|
+
midPrice: fast?.midPx != null ? fast.midPx : midPrice,
|
|
736
|
+
markPrice: emittedMarkPrice,
|
|
737
|
+
prevDayPrice: toMarketContextString(ctx.prevDayPx),
|
|
738
|
+
volume24h: toMarketContextString(ctx.dayNtlVlm),
|
|
739
|
+
marketCap: toMarketCapString(emittedMarkPrice, ctx.circulatingSupply),
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
function compactRemovalPrice(levels, value) {
|
|
743
|
+
if (typeof value === 'number') {
|
|
744
|
+
return levels[value]?.price;
|
|
745
|
+
}
|
|
746
|
+
return typeof value === 'string' ? value : value.p;
|
|
747
|
+
}
|
|
748
|
+
function applyCompressedL2Side(previous, updates, removals, side) {
|
|
749
|
+
const byPrice = new Map(previous.map((level) => [level.price, level.size]));
|
|
750
|
+
for (const removal of removals) {
|
|
751
|
+
const price = compactRemovalPrice(previous, removal);
|
|
752
|
+
if (price !== undefined) {
|
|
753
|
+
byPrice.delete(price);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
for (const update of updates) {
|
|
757
|
+
if (Number(update.s) === 0) {
|
|
758
|
+
byPrice.delete(update.p);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
byPrice.set(update.p, update.s);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return [...byPrice.entries()]
|
|
765
|
+
.map(([price, size]) => ({ price, size }))
|
|
766
|
+
.sort((a, b) => side === 'bid'
|
|
767
|
+
? Number(b.price) - Number(a.price)
|
|
768
|
+
: Number(a.price) - Number(b.price))
|
|
769
|
+
.slice(0, HL_L2_BOOK_MAX_LEVELS_PER_SIDE);
|
|
770
|
+
}
|
|
376
771
|
function isValidHlFrame(channel, data) {
|
|
377
|
-
if (channel === 'fastAssetCtxs') {
|
|
772
|
+
if (channel === 'fastAssetCtxs' || channel === 'pac' || channel === 'sac') {
|
|
378
773
|
return typeof data === 'string';
|
|
379
774
|
}
|
|
380
775
|
if (!isObject(data)) {
|
|
@@ -382,15 +777,22 @@ function isValidHlFrame(channel, data) {
|
|
|
382
777
|
}
|
|
383
778
|
switch (channel) {
|
|
384
779
|
case 'allDexsAssetCtxs':
|
|
385
|
-
return Array.isArray(data.assetCtxs);
|
|
780
|
+
return Array.isArray(data.assetCtxs) || Array.isArray(data.ctxs);
|
|
781
|
+
case 'activeAssetCtx':
|
|
782
|
+
case 'activeSpotAssetCtx':
|
|
783
|
+
return typeof data.coin === 'string' && isObject(data.ctx);
|
|
386
784
|
case 'l2Book':
|
|
387
785
|
return (typeof data.coin === 'string' &&
|
|
388
786
|
Array.isArray(data.levels) &&
|
|
389
787
|
Array.isArray(data.levels[0]) &&
|
|
390
788
|
Array.isArray(data.levels[1]) &&
|
|
391
789
|
typeof data.time === 'number');
|
|
790
|
+
case 'l2':
|
|
791
|
+
return typeof data.c === 'string' || isObject(data.s) || isObject(data.u);
|
|
392
792
|
case 'candle':
|
|
393
793
|
return typeof data.s === 'string' && typeof data.i === 'string';
|
|
794
|
+
case 'trades':
|
|
795
|
+
return Array.isArray(data);
|
|
394
796
|
case 'orderUpdates':
|
|
395
797
|
return Array.isArray(data);
|
|
396
798
|
case 'userFills':
|