@lifi/perps-sdk-provider-hyperliquid 1.4.0 → 1.5.2
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/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +5 -3
- package/dist/cjs/accountSummary.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/types/ws.d.ts +8 -0
- package/dist/cjs/types/ws.d.ts.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 +2 -0
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +85 -13
- package/dist/cjs/websocket/HyperliquidWsProvider.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/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/types/ws.d.ts +10 -0
- package/dist/esm/types/ws.d.ts.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 +2 -0
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +85 -13
- package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/types/accountSummary.d.ts +2 -2
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/services/getAccount.d.ts.map +1 -1
- package/dist/types/types/ws.d.ts +10 -0
- package/dist/types/types/ws.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 +2 -0
- package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/accountSummary.ts +12 -9
- package/src/services/getAccount.ts +10 -11
- package/src/types/ws.ts +12 -0
- package/src/utils/mapOrder.ts +23 -6
- package/src/websocket/HyperliquidWsProvider.ts +108 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapOrder.d.ts","sourceRoot":"","sources":["../../../src/utils/mapOrder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,SAAS,EACT,KAAK,EACL,YAAY,EACb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAEL,WAAW,EACX,SAAS,EAEV,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAE3E;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,WAAW,MAAM,KAAG,SAehD,CAAA;AAED,cAAc;AACd,eAAO,MAAM,aAAa,GAAI,MAAM,SAAS,KAAG,OAIjB,CAAA;AAE/B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc,GACzB,GAAG,mBAAmB,GAAG,aAAa,CAAC,OAAO,CAAC,KAC9C,OAkBF,CAAA;AAED,cAAc;AACd,eAAO,MAAM,YAAY,GACvB,GAAG,mBAAmB,EACtB,QAAQ,aAAa,KACpB,SAaD,CAAA;AAEF,cAAc;AACd,eAAO,MAAM,eAAe,GAC1B,GAAG,mBAAmB,EACtB,QAAQ,aAAa,KACpB,YAcF,CAAA;AAED
|
|
1
|
+
{"version":3,"file":"mapOrder.d.ts","sourceRoot":"","sources":["../../../src/utils/mapOrder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,SAAS,EACT,KAAK,EACL,YAAY,EACb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAEL,WAAW,EACX,SAAS,EAEV,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAE3E;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,WAAW,MAAM,KAAG,SAehD,CAAA;AAED,cAAc;AACd,eAAO,MAAM,aAAa,GAAI,MAAM,SAAS,KAAG,OAIjB,CAAA;AAE/B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc,GACzB,GAAG,mBAAmB,GAAG,aAAa,CAAC,OAAO,CAAC,KAC9C,OAkBF,CAAA;AAED,cAAc;AACd,eAAO,MAAM,YAAY,GACvB,GAAG,mBAAmB,EACtB,QAAQ,aAAa,KACpB,SAaD,CAAA;AAEF,cAAc;AACd,eAAO,MAAM,eAAe,GAC1B,GAAG,mBAAmB,EACtB,QAAQ,aAAa,KACpB,YAcF,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,KAAG,WAwB/C,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,KAAG,MAAM,GAAG,SAyBzD,CAAA;AAeD,cAAc;AACd,eAAO,MAAM,QAAQ,GACnB,QAAQ,aAAa,EACrB,QAAQ,aAAa,KACpB,KAsBF,CAAA"}
|
|
@@ -80,6 +80,8 @@ export declare class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
80
80
|
* + mark overlaid from `fastAssetCtxs`.
|
|
81
81
|
*/
|
|
82
82
|
private emitMarketsContext;
|
|
83
|
+
private handleActiveAssetCtx;
|
|
84
|
+
private handleActiveSpotAssetCtx;
|
|
83
85
|
/** Latest mid per `Market.id` across asset-context and fast feeds. */
|
|
84
86
|
private mergedMids;
|
|
85
87
|
private orderbookReferencePrice;
|
|
@@ -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,EAOL,KAAK,YAAY,EAElB,MAAM,mBAAmB,CAAA;
|
|
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;AA6C1B;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,QAC5B,iBAEgD,CAAA;AAEtD;;;;;;;;;;;;;GAaG;AACH,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;IA+DnE;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,iBAAiB;IAmBzB;;;;OAIG;IACH,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;IAe5B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAgB3B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,wBAAwB;IAWhC,sEAAsE;IACtE,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;IAWvB,OAAO,CAAC,+BAA+B;IAkBvC,OAAO,CAAC,eAAe;CAaxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/perps-sdk-provider-hyperliquid",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "Hyperliquid provider plugin for @lifi/perps-sdk",
|
|
5
5
|
"homepage": "https://github.com/lifinance/perps-sdk",
|
|
6
6
|
"bugs": {
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"big.js": "^7.0.1",
|
|
50
50
|
"viem": "^2.48.8",
|
|
51
|
-
"@lifi/perps-types": "^1.
|
|
51
|
+
"@lifi/perps-types": "^1.5.1"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@lifi/perps-sdk": "^1.
|
|
54
|
+
"@lifi/perps-sdk": "^1.5.2"
|
|
55
55
|
},
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|
package/src/accountSummary.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { summarizeAccount } from '@lifi/perps-sdk'
|
|
1
|
+
import { type CollateralSemantics, summarizeAccount } from '@lifi/perps-sdk'
|
|
2
2
|
import type {
|
|
3
3
|
AccountResponse,
|
|
4
4
|
AccountSummary,
|
|
@@ -7,20 +7,23 @@ import type {
|
|
|
7
7
|
import { HlAbstractionMode } from './types/index.js'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* In `unifiedAccount`/`portfolioMargin` the whole account lives in spot, so
|
|
11
|
-
* collateral rows are
|
|
12
|
-
* `disabled`/`dexAbstraction` (and the
|
|
13
|
-
*
|
|
10
|
+
* In `unifiedAccount`/`portfolioMargin` the whole account lives in spot, so
|
|
11
|
+
* the collateral rows are gross holdings: locked margin included, unrealized
|
|
12
|
+
* PnL carried by the positions. In `disabled`/`dexAbstraction` (and the
|
|
13
|
+
* unset/standard mode) the venue rows hold `accountValue`, Hyperliquid's
|
|
14
|
+
* total equity — locked margin AND unrealized PnL already included.
|
|
14
15
|
*/
|
|
15
|
-
const
|
|
16
|
+
const collateralSemantics = (account: AccountResponse): CollateralSemantics =>
|
|
16
17
|
account.config.provider === 'hyperliquid' &&
|
|
17
18
|
(account.config.abstractionMode === HlAbstractionMode.UNIFIED_ACCOUNT ||
|
|
18
19
|
account.config.abstractionMode === HlAbstractionMode.PORTFOLIO_MARGIN)
|
|
20
|
+
? 'gross'
|
|
21
|
+
: 'equity'
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Roll a Hyperliquid {@link AccountResponse} up into an {@link AccountSummary},
|
|
22
|
-
* branching on the abstraction mode so the
|
|
23
|
-
* rows is interpreted correctly.
|
|
25
|
+
* branching on the abstraction mode so the margin/PnL content of the
|
|
26
|
+
* collateral rows is interpreted correctly.
|
|
24
27
|
*
|
|
25
28
|
* @public
|
|
26
29
|
*/
|
|
@@ -28,5 +31,5 @@ export function getAccountSummary(
|
|
|
28
31
|
account: AccountResponse,
|
|
29
32
|
positions: Position[]
|
|
30
33
|
): AccountSummary {
|
|
31
|
-
return summarizeAccount(account, positions,
|
|
34
|
+
return summarizeAccount(account, positions, collateralSemantics(account))
|
|
32
35
|
}
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
spotPriceById,
|
|
29
29
|
} from '../utils/index.js'
|
|
30
30
|
import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
|
|
31
|
-
import { mapPosition } from '../utils/mapPosition.js'
|
|
31
|
+
import { isOpenAssetPosition, mapPosition } from '../utils/mapPosition.js'
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Parameters for {@link getAccount}.
|
|
@@ -37,16 +37,14 @@ import { mapPosition } from '../utils/mapPosition.js'
|
|
|
37
37
|
*/
|
|
38
38
|
export type GetAccountParams = ProviderGetAccountParams
|
|
39
39
|
|
|
40
|
+
// `marginSummary` covers the whole account (cross AND isolated positions);
|
|
41
|
+
// `crossMarginSummary` is the cross-only subset and would drop isolated
|
|
42
|
+
// equity/margin.
|
|
40
43
|
const getAccountValue = (state: HlClearinghouseState): number =>
|
|
41
|
-
Number.parseFloat(
|
|
42
|
-
state.crossMarginSummary.accountValue || state.marginSummary.accountValue
|
|
43
|
-
)
|
|
44
|
+
Number.parseFloat(state.marginSummary.accountValue)
|
|
44
45
|
|
|
45
46
|
const getTotalMarginUsed = (state: HlClearinghouseState): number =>
|
|
46
|
-
Number.parseFloat(
|
|
47
|
-
state.crossMarginSummary.totalMarginUsed ||
|
|
48
|
-
state.marginSummary.totalMarginUsed
|
|
49
|
-
)
|
|
47
|
+
Number.parseFloat(state.marginSummary.totalMarginUsed)
|
|
50
48
|
|
|
51
49
|
const getMarginUsed = (
|
|
52
50
|
abstraction: HlAbstractionMode | null,
|
|
@@ -113,8 +111,8 @@ const buildBalances = (
|
|
|
113
111
|
|
|
114
112
|
// Unified/portfolio modes hold everything in spot — per-dex equity would
|
|
115
113
|
// double-count. Only disabled/dexAbstraction carry separate venue collateral.
|
|
116
|
-
// `accountValue` is
|
|
117
|
-
//
|
|
114
|
+
// `accountValue` is the dex's TOTAL equity: locked margin and unrealized
|
|
115
|
+
// PnL are already included, so summaries must not add them on top.
|
|
118
116
|
if (!isUnifiedMode(abstraction)) {
|
|
119
117
|
for (const [dex, state] of stateByDex) {
|
|
120
118
|
const categoryId = dex || PROVIDER_KEY
|
|
@@ -218,7 +216,7 @@ export const getAccount = async (
|
|
|
218
216
|
|
|
219
217
|
const positions: Position[] = stateResults.flatMap((state) =>
|
|
220
218
|
state.assetPositions
|
|
221
|
-
.filter(
|
|
219
|
+
.filter(isOpenAssetPosition)
|
|
222
220
|
.map((ap) => mapPosition(ap, registry.require(ap.position.coin)))
|
|
223
221
|
)
|
|
224
222
|
|
|
@@ -252,6 +250,7 @@ export const getAccount = async (
|
|
|
252
250
|
address: params.address,
|
|
253
251
|
balances,
|
|
254
252
|
collateralBalances,
|
|
253
|
+
positions,
|
|
255
254
|
marginUsed: getMarginUsed(abstractionResult, positions, stateByDex),
|
|
256
255
|
unrealizedPnl: totalUnrealizedPnl.toString(),
|
|
257
256
|
feeTier: {
|
package/src/types/ws.ts
CHANGED
|
@@ -71,6 +71,18 @@ export type HlWsSpotAssetCtx = {
|
|
|
71
71
|
circulatingSupply?: HlWsNumberString
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/** @public */
|
|
75
|
+
export type HlWsActiveAssetCtxData = {
|
|
76
|
+
coin: string
|
|
77
|
+
ctx: Partial<Record<keyof HlWsPerpAssetCtx, HlWsNumberString | null>>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @public */
|
|
81
|
+
export type HlWsActiveSpotAssetCtxData = {
|
|
82
|
+
coin: string
|
|
83
|
+
ctx: HlWsSpotAssetCtx
|
|
84
|
+
}
|
|
85
|
+
|
|
74
86
|
/**
|
|
75
87
|
* Compressed spot asset-context feed. The first frame is a broad snapshot; later
|
|
76
88
|
* frames only carry changed fields.
|
package/src/utils/mapOrder.ts
CHANGED
|
@@ -122,7 +122,17 @@ export const mapTriggerOrder = (
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* Map a raw Hyperliquid order status string to the SDK's OrderStatus enum.
|
|
127
|
+
*
|
|
128
|
+
* HL's terminal statuses are mostly compound strings ending in `Canceled`
|
|
129
|
+
* or `Rejected` (e.g. `siblingFilledCanceled`, `tickRejected`); classify
|
|
130
|
+
* those by suffix so a status HL adds later still lands in the correct
|
|
131
|
+
* terminal bucket instead of silently falling through to PENDING, which
|
|
132
|
+
* {@link isActiveOrderStatus} treats as active. `scheduledCancel` is the
|
|
133
|
+
* one documented cancel status without the `Canceled` suffix.
|
|
134
|
+
* @public
|
|
135
|
+
*/
|
|
126
136
|
export const mapOrderStatus = (status: string): OrderStatus => {
|
|
127
137
|
switch (status) {
|
|
128
138
|
case 'open':
|
|
@@ -132,14 +142,19 @@ export const mapOrderStatus = (status: string): OrderStatus => {
|
|
|
132
142
|
return OrderStatus.FILLED
|
|
133
143
|
case 'canceled':
|
|
134
144
|
case 'cancelled':
|
|
145
|
+
case 'scheduledCancel':
|
|
135
146
|
return OrderStatus.CANCELLED
|
|
136
147
|
case 'rejected':
|
|
137
148
|
return OrderStatus.REJECTED
|
|
138
149
|
case 'triggered':
|
|
139
150
|
return OrderStatus.TRIGGERED
|
|
140
|
-
case 'marginCanceled':
|
|
141
|
-
return OrderStatus.CANCELLED
|
|
142
151
|
default:
|
|
152
|
+
if (status.endsWith('Canceled') || status.endsWith('Cancelled')) {
|
|
153
|
+
return OrderStatus.CANCELLED
|
|
154
|
+
}
|
|
155
|
+
if (status.endsWith('Rejected')) {
|
|
156
|
+
return OrderStatus.REJECTED
|
|
157
|
+
}
|
|
143
158
|
return OrderStatus.PENDING
|
|
144
159
|
}
|
|
145
160
|
}
|
|
@@ -153,7 +168,7 @@ export const mapOrderStatus = (status: string): OrderStatus => {
|
|
|
153
168
|
*/
|
|
154
169
|
export const mapStatusReason = (status: string): string | undefined => {
|
|
155
170
|
switch (status) {
|
|
156
|
-
case '
|
|
171
|
+
case 'iocCancelRejected':
|
|
157
172
|
return 'Order cancelled: not enough liquidity to fill immediately.'
|
|
158
173
|
case 'reduceOnlyCanceled':
|
|
159
174
|
return 'Order cancelled: would not reduce your position.'
|
|
@@ -165,12 +180,14 @@ export const mapStatusReason = (status: string): string | undefined => {
|
|
|
165
180
|
return 'Order cancelled: sibling OCO order filled first.'
|
|
166
181
|
case 'selfTradeCanceled':
|
|
167
182
|
return 'Order cancelled: would self-trade against your own resting order.'
|
|
183
|
+
case 'scheduledCancel':
|
|
184
|
+
return "Order cancelled: dead man's switch triggered."
|
|
168
185
|
case 'tickRejected':
|
|
169
186
|
return 'Order rejected: price did not match the tick size.'
|
|
170
187
|
case 'minTradeNtlRejected':
|
|
171
188
|
return 'Order rejected: notional value below the minimum trade size.'
|
|
172
|
-
case '
|
|
173
|
-
return 'Order
|
|
189
|
+
case 'delistedCanceled':
|
|
190
|
+
return 'Order cancelled: market has been delisted.'
|
|
174
191
|
default:
|
|
175
192
|
return undefined
|
|
176
193
|
}
|
|
@@ -27,6 +27,8 @@ import type {
|
|
|
27
27
|
HlAssetPosition,
|
|
28
28
|
HlOrderDetail,
|
|
29
29
|
HlUserFill,
|
|
30
|
+
HlWsActiveAssetCtxData,
|
|
31
|
+
HlWsActiveSpotAssetCtxData,
|
|
30
32
|
HlWsAllDexsAssetCtxsData,
|
|
31
33
|
HlWsAllDexsClearinghouseStateData,
|
|
32
34
|
HlWsCandleData,
|
|
@@ -309,6 +311,8 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
309
311
|
switch (sub.channel) {
|
|
310
312
|
case 'marketsContext':
|
|
311
313
|
return 'marketsContext'
|
|
314
|
+
case 'marketContext':
|
|
315
|
+
return `marketContext:${sub.marketId}`
|
|
312
316
|
case 'orderbook':
|
|
313
317
|
return `l2:${sub.marketId}:${this.orderbookAggregationKey(
|
|
314
318
|
sub.marketId,
|
|
@@ -361,6 +365,11 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
361
365
|
// Handled via getMarketsContextSubEntries in openChannel; never reaches
|
|
362
366
|
// toHlPayload, but TS requires an exhaustive switch.
|
|
363
367
|
return { type: 'allDexsAssetCtxs' }
|
|
368
|
+
case 'marketContext':
|
|
369
|
+
return {
|
|
370
|
+
type: 'activeAssetCtx',
|
|
371
|
+
coin: sub.marketId,
|
|
372
|
+
}
|
|
364
373
|
case 'orderbook': {
|
|
365
374
|
const aggregation = this.orderbookAggregation(
|
|
366
375
|
sub.marketId,
|
|
@@ -435,6 +444,12 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
435
444
|
case 'fastAssetCtxs':
|
|
436
445
|
this.handleFastAssetCtxs(msg.data as string)
|
|
437
446
|
break
|
|
447
|
+
case 'activeAssetCtx':
|
|
448
|
+
this.handleActiveAssetCtx(msg.data as HlWsActiveAssetCtxData, raw)
|
|
449
|
+
break
|
|
450
|
+
case 'activeSpotAssetCtx':
|
|
451
|
+
this.handleActiveSpotAssetCtx(msg.data as HlWsActiveSpotAssetCtxData)
|
|
452
|
+
break
|
|
438
453
|
case 'l2':
|
|
439
454
|
this.handleL2(msg.data as HlWsL2Data)
|
|
440
455
|
break
|
|
@@ -580,21 +595,15 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
580
595
|
}
|
|
581
596
|
}
|
|
582
597
|
for (const [marketId, ctx] of Object.entries(this.spotCtxByMarketId)) {
|
|
583
|
-
const
|
|
584
|
-
const markPrice = toMarketContextString(ctx.markPx)
|
|
585
|
-
if (midPrice === undefined || markPrice === undefined) {
|
|
586
|
-
continue
|
|
587
|
-
}
|
|
588
|
-
const fast = this.fastCtxByMarketId[marketId]
|
|
589
|
-
const emittedMarkPrice = fast?.markPx != null ? fast.markPx : markPrice
|
|
590
|
-
data[marketId] = {
|
|
598
|
+
const context = mapSpotMarketContext(
|
|
591
599
|
marketId,
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
600
|
+
ctx,
|
|
601
|
+
this.fastCtxByMarketId[marketId]
|
|
602
|
+
)
|
|
603
|
+
if (context === undefined) {
|
|
604
|
+
continue
|
|
597
605
|
}
|
|
606
|
+
data[marketId] = context
|
|
598
607
|
}
|
|
599
608
|
for (const [marketId, fast] of Object.entries(this.fastCtxByMarketId)) {
|
|
600
609
|
if (data[marketId] !== undefined) {
|
|
@@ -611,6 +620,29 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
|
|
|
611
620
|
this.emit('marketsContext', { channel: 'marketsContext', data })
|
|
612
621
|
}
|
|
613
622
|
|
|
623
|
+
private handleActiveAssetCtx(data: HlWsActiveAssetCtxData, raw: string) {
|
|
624
|
+
const ctx = activePerpAssetCtx(data.coin, data.ctx)
|
|
625
|
+
if (ctx === undefined) {
|
|
626
|
+
wsLog.parseFailure(this.providerKey, raw)
|
|
627
|
+
return
|
|
628
|
+
}
|
|
629
|
+
this.emit(`marketContext:${data.coin}`, {
|
|
630
|
+
channel: 'marketContext',
|
|
631
|
+
data: mapMarketContext(data.coin, ctx),
|
|
632
|
+
})
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
private handleActiveSpotAssetCtx(data: HlWsActiveSpotAssetCtxData) {
|
|
636
|
+
const context = mapSpotMarketContext(data.coin, data.ctx)
|
|
637
|
+
if (context === undefined) {
|
|
638
|
+
return
|
|
639
|
+
}
|
|
640
|
+
this.emit(`marketContext:${data.coin}`, {
|
|
641
|
+
channel: 'marketContext',
|
|
642
|
+
data: context,
|
|
643
|
+
})
|
|
644
|
+
}
|
|
645
|
+
|
|
614
646
|
/** Latest mid per `Market.id` across asset-context and fast feeds. */
|
|
615
647
|
private mergedMids(): Map<string, number> {
|
|
616
648
|
const map = new Map<string, number>()
|
|
@@ -932,6 +964,66 @@ function allDexsAssetCtxEntries(
|
|
|
932
964
|
return data.assetCtxs ?? data.ctxs ?? []
|
|
933
965
|
}
|
|
934
966
|
|
|
967
|
+
function activePerpAssetCtx(
|
|
968
|
+
marketId: string,
|
|
969
|
+
ctx: HlWsActiveAssetCtxData['ctx']
|
|
970
|
+
): HlWsPerpAssetCtx | undefined {
|
|
971
|
+
const funding = toMarketContextString(ctx.funding)
|
|
972
|
+
const openInterest = toMarketContextString(ctx.openInterest)
|
|
973
|
+
const dayNtlVlm = toMarketContextString(ctx.dayNtlVlm)
|
|
974
|
+
const prevDayPx = toMarketContextString(ctx.prevDayPx)
|
|
975
|
+
const markPx = toMarketContextString(ctx.markPx)
|
|
976
|
+
const midPx =
|
|
977
|
+
ctx.midPx === undefined || ctx.midPx === null
|
|
978
|
+
? null
|
|
979
|
+
: (toMarketContextString(ctx.midPx) ?? null)
|
|
980
|
+
const oraclePx = toMarketContextString(ctx.oraclePx)
|
|
981
|
+
|
|
982
|
+
if (
|
|
983
|
+
funding === undefined ||
|
|
984
|
+
openInterest === undefined ||
|
|
985
|
+
dayNtlVlm === undefined ||
|
|
986
|
+
prevDayPx === undefined ||
|
|
987
|
+
markPx === undefined ||
|
|
988
|
+
oraclePx === undefined
|
|
989
|
+
) {
|
|
990
|
+
return undefined
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
return {
|
|
994
|
+
coin: marketId,
|
|
995
|
+
funding,
|
|
996
|
+
openInterest,
|
|
997
|
+
dayNtlVlm,
|
|
998
|
+
prevDayPx,
|
|
999
|
+
markPx,
|
|
1000
|
+
midPx,
|
|
1001
|
+
oraclePx,
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
function mapSpotMarketContext(
|
|
1006
|
+
marketId: string,
|
|
1007
|
+
ctx: HlWsSpotAssetCtx,
|
|
1008
|
+
fast?: HlWsFastAssetCtx
|
|
1009
|
+
): MarketContext | undefined {
|
|
1010
|
+
const midPrice = toMarketContextString(ctx.midPx ?? ctx.markPx)
|
|
1011
|
+
const markPrice = toMarketContextString(ctx.markPx)
|
|
1012
|
+
if (midPrice === undefined || markPrice === undefined) {
|
|
1013
|
+
return undefined
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
const emittedMarkPrice = fast?.markPx != null ? fast.markPx : markPrice
|
|
1017
|
+
return {
|
|
1018
|
+
marketId,
|
|
1019
|
+
midPrice: fast?.midPx != null ? fast.midPx : midPrice,
|
|
1020
|
+
markPrice: emittedMarkPrice,
|
|
1021
|
+
prevDayPrice: toMarketContextString(ctx.prevDayPx),
|
|
1022
|
+
volume24h: toMarketContextString(ctx.dayNtlVlm),
|
|
1023
|
+
marketCap: toMarketCapString(emittedMarkPrice, ctx.circulatingSupply),
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
935
1027
|
function compactRemovalPrice(
|
|
936
1028
|
levels: OrderbookLevel[],
|
|
937
1029
|
value: number | string | { p: string }
|
|
@@ -991,6 +1083,9 @@ function isValidHlFrame(channel: string, data: unknown): boolean {
|
|
|
991
1083
|
switch (channel) {
|
|
992
1084
|
case 'allDexsAssetCtxs':
|
|
993
1085
|
return Array.isArray(data.assetCtxs) || Array.isArray(data.ctxs)
|
|
1086
|
+
case 'activeAssetCtx':
|
|
1087
|
+
case 'activeSpotAssetCtx':
|
|
1088
|
+
return typeof data.coin === 'string' && isObject(data.ctx)
|
|
994
1089
|
case 'l2Book':
|
|
995
1090
|
return (
|
|
996
1091
|
typeof data.coin === 'string' &&
|