@syldel/hl-shared-types 0.0.20 → 0.0.22

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.
@@ -57,4 +57,28 @@ export type CollateralBalance =
57
57
  status: 'unknown-collateral';
58
58
  mode: AccountAbstractionMode;
59
59
  asset: string;
60
+ }
61
+ /**
62
+ * Le compte est dans un mode dont ce gateway ne sait pas lire le collatéral.
63
+ *
64
+ * Deux cas, et c'est un refus **délibéré** plutôt qu'une approximation :
65
+ *
66
+ * - **`portfolioMargin`** réunit plusieurs actifs en un seul portefeuille
67
+ * (HYPE, BTC, USDC, USDT à ce jour). Rendre le solde d'un seul d'entre eux
68
+ * sous-estimerait le capital, et les agréger demanderait de valoriser HYPE
69
+ * et BTC en dollars — donc d'introduire une source de **prix** dans un
70
+ * calcul de collatéral. C'est un chantier, pas une ligne ;
71
+ * - **`dexAbstraction`** est arrêté par l'exchange. La doc le décrit (USDC
72
+ * depuis le solde perp, tout autre collatéral depuis le spot), mais aucun
73
+ * compte ne permet de l'éprouver — et une implémentation non exercée d'un
74
+ * mode qu'on ne peut pas tester vaut moins qu'un refus net.
75
+ *
76
+ * L'appelant doit le traiter comme les autres statuts sans montant : ne rien
77
+ * dimensionner, et le dire. Un nombre plausible aurait traversé tout le
78
+ * système sans rien déclencher.
79
+ */
80
+ | {
81
+ status: 'unsupported-mode';
82
+ mode: AccountAbstractionMode;
83
+ asset: string;
60
84
  };
@@ -1,4 +1,26 @@
1
1
  import { DecimalString } from '../common';
2
+ /**
3
+ * ============================================================================
4
+ * DÉCLARER CE QUE L'EXCHANGE REND, PAS CE QU'IL POURRAIT RENDRE
5
+ *
6
+ * Les champs ci-dessous ont été relevés le 2026-10-01 sur les cinq dex vivants
7
+ * (`''`, `xyz`, `para`, `mkts`, `io`) : 434 entrées d'univers et 363 contextes
8
+ * d'actif, via `meta` et `metaAndAssetCtxs`. Les commentaires portent ces
9
+ * comptes parce qu'un type optimiste coûte plus cher qu'un type absent : tant
10
+ * que `midPx` était déclaré `string`, `Number(ctx.midPx)` rendait **`0`** sur
11
+ * les marchés délistés — un prix, pas une erreur.
12
+ *
13
+ * Deux traitements, selon ce que l'absence du champ signifie déjà :
14
+ *
15
+ * - **Drapeau de présence** (`onlyIsolated`, `isDelisted`) : l'absence porte le
16
+ * sens complémentaire, donc une seule valeur est utile et le type la fixe
17
+ * (`?: true`). Écrire `false` serait redondant, et dans un double ce serait
18
+ * rendre une forme que l'exchange ne rend pas.
19
+ * - **Dimension à valeurs** (`growthMode`, `marginMode`, `deployerFeeScale`) :
20
+ * d'autres valeurs sont plausibles même si une seule a été observée, donc le
21
+ * type reste ouvert et le commentaire dit ce qui a été vu.
22
+ * ============================================================================
23
+ */
2
24
  /**
3
25
  * Metadata describing a perpetual market.
4
26
  */
@@ -9,12 +31,71 @@ export interface HLPerpMarketInfo {
9
31
  szDecimals: number;
10
32
  /** Maximum leverage allowed. */
11
33
  maxLeverage: number;
12
- /** Whether the market only supports isolated margin. */
13
- onlyIsolated?: boolean;
14
- /** Whether the market has been delisted. */
15
- isDelisted?: boolean;
16
- /** Optional margin mode restriction. */
34
+ /**
35
+ * Clé de la table de marge qui s'applique à ce marché, à chercher dans
36
+ * `HLPerpMeta.marginTables`.
37
+ *
38
+ * **Requis**, et non optionnel : présent sur **434/434** marchés des cinq
39
+ * dex, délistés compris. Le déclarer optionnel n'évitait aucune erreur — il
40
+ * autorisait seulement des doubles à l'omettre, donc à rendre une forme que
41
+ * l'exchange ne rend jamais.
42
+ */
43
+ marginTableId: number;
44
+ /**
45
+ * Présent **uniquement** sur les marchés restreints à la marge isolée, et
46
+ * toujours accompagné de `marginMode` (0 contre-exemple sur 434).
47
+ *
48
+ * ⚠️ Ce champ n'est **pas** déprécié, contrairement à ce que suggère le dex
49
+ * principal : il n'y survit que sur 8 marchés, tous délistés. Les HIP-3 le
50
+ * rendent partout — `io` 8/8 vivants, `xyz` 90/110, `para` 26/29, soit 126
51
+ * marchés vivants au total. Le marquer `@deprecated` ferait clignoter du
52
+ * code juste.
53
+ *
54
+ * `true` et non `boolean` : les 162 occurrences relevées valent `true`.
55
+ */
56
+ onlyIsolated?: true;
57
+ /**
58
+ * Présent **uniquement** sur les marchés délistés, et toujours à `true` —
59
+ * c'est ainsi que l'exchange marque un marché mort (doc `meta`, exemple
60
+ * `LOOM`). Un marché vivant n'a pas la clé du tout.
61
+ *
62
+ * `true` et non `boolean`, pour que le compilateur refuse
63
+ * `isDelisted: false` : écrit dans un double, il rendrait une forme que le
64
+ * vrai ne rend pas, et c'est précisément ce qu'un double ne doit pas faire.
65
+ */
66
+ isDelisted?: true;
67
+ /**
68
+ * Restriction de mode de marge. Toujours accompagnée de `onlyIsolated`, dans
69
+ * les deux sens. Valeurs relevées : `strictIsolated` sur 52 marchés du dex
70
+ * principal et de `xyz`, `noCross` sur 129 HIP-3.
71
+ */
17
72
  marginMode?: 'strictIsolated' | 'noCross';
73
+ /**
74
+ * Relevé sur les quatre dex HIP-3, jamais sur le principal (0/234).
75
+ *
76
+ * Laissé ouvert (`string`) bien que `'enabled'` soit la seule valeur vue sur
77
+ * 154 marchés : le champ nomme un mode, d'autres états sont plausibles, et il
78
+ * **subsiste sur 13 marchés délistés** — donc il n'est pas tenu à jour et ne
79
+ * dit rien de la vivacité d'un marché. Pour ça, `isDelisted`.
80
+ */
81
+ growthMode?: string;
82
+ /**
83
+ * Multiplicateur appliqué aux frais du déployeur. Relevé sur les quatre dex
84
+ * HIP-3 (200 marchés), jamais sur le principal. Valeurs vues : `'1.0'` et
85
+ * `'0.5'` — laissé ouvert, c'est une échelle.
86
+ */
87
+ deployerFeeScale?: DecimalString;
88
+ /**
89
+ * Date du dernier changement de `deployerFeeScale`.
90
+ *
91
+ * ⚠️ Une **chaîne**, malgré le `Time` du nom, et une chaîne piégeuse :
92
+ * `"2025-11-23T17:37:10.033211662"` — 9 décimales de seconde et **aucun
93
+ * fuseau**. `Date.parse` l'accepte sans broncher, tronque les nanosecondes
94
+ * **et l'interprète en heure locale** : mesuré, cette valeur donne
95
+ * `16:37:10Z` sur une machine en UTC+1 et un autre instant ailleurs. Donc
96
+ * jamais `number`, et pas de parsing sans imposer le fuseau explicitement.
97
+ */
98
+ lastFeeScaleChangeTime?: string;
18
99
  }
19
100
  /**
20
101
  * Margin tier defining leverage limits for a position size range.
@@ -83,53 +164,77 @@ export interface HLPerpMarketUniverse extends HLPerpMarketInfo {
83
164
  export interface HLPerpAssetCtx {
84
165
  /** Daily notional trading volume. */
85
166
  dayNtlVlm: string;
167
+ /**
168
+ * Volume quotidien exprimé dans l'actif de base, là où `dayNtlVlm` l'exprime
169
+ * en notionnel. Relevé sur 363/363 contextes ; il traversait déjà le fil sans
170
+ * qu'aucun type ne le déclare.
171
+ */
172
+ dayBaseVlm: string;
86
173
  /** Current funding rate. */
87
174
  funding: string;
88
- /** Impact price levels used for slippage estimation. */
89
- impactPxs: string[];
90
- /** Mark price used for PnL calculations. */
175
+ /**
176
+ * Prix d'impact estimés, `[bid, ask]`.
177
+ *
178
+ * **`null`** quand l'exchange n'a pas de carnet à montrer : mesuré sur 75/363
179
+ * contextes, tous délistés. Le tableau, lui, fait toujours exactement deux
180
+ * entrées quand il existe (288/288).
181
+ */
182
+ impactPxs: string[] | null;
183
+ /**
184
+ * Mark price used for PnL calculations. Jamais `null` sur les 363 contextes
185
+ * relevés, délistés compris — c'est le seul prix sur lequel on peut compter.
186
+ */
91
187
  markPx: string;
92
- /** Mid price between best bid and ask. */
93
- midPx: string;
188
+ /**
189
+ * Prix milieu du spread, **`null`** sur les mêmes 75 contextes délistés.
190
+ *
191
+ * C'est le champ qui a motivé ce chantier. Déclaré `string`, il faisait
192
+ * rendre `0` à `Number(ctx.midPx)` — et `0` n'est pas une absence de réponse
193
+ * mais une réponse affirmative : dans une comparaison `mid >= oracle`, un
194
+ * `NaN` aurait rendu les deux côtés `false`, `0` tranche. Un consommateur
195
+ * doit donc écarter le `null` avant de calculer, pas le convertir.
196
+ */
197
+ midPx: string | null;
94
198
  /** Total open interest. */
95
199
  openInterest: string;
96
200
  /** Oracle price reference. */
97
201
  oraclePx: string;
98
- /** Price premium relative to the oracle. */
99
- premium: string;
202
+ /** Price premium relative to the oracle. **`null`** sur les mêmes 75. */
203
+ premium: string | null;
100
204
  /** Previous day's closing price. */
101
205
  prevDayPx: string;
102
206
  }
103
207
  /**
104
208
  * Response combining market metadata and runtime context.
209
+ *
210
+ * Le premier élément est le **`HLPerpMeta` complet** : relevé le 2026-10-01 sur
211
+ * `''` et `xyz`, `metaAndAssetCtxs[0]` porte exactement les mêmes trois clés
212
+ * que `meta` — `universe`, `marginTables`, `collateralToken`. Il était typé
213
+ * `{ universe }` seul, ce qui rendait le collatéral du dex illisible depuis cet
214
+ * appel alors qu'il était déjà sur le fil : il fallait un second appel à `meta`
215
+ * pour obtenir une donnée reçue.
105
216
  */
106
- export type HLPerpMetaAndCtx = [{
107
- universe: HLPerpMarketInfo[];
108
- }, HLPerpAssetCtx[]];
217
+ export type HLPerpMetaAndCtx = [HLPerpMeta, HLPerpAssetCtx[]];
109
218
  /**
110
219
  * Normalized representation of a perpetual market used by the SDK.
220
+ *
221
+ * Étend `HLPerpMarketInfo` au lieu d'en recopier les champs : la copie avait
222
+ * déjà divergé — `marginTableId` y était déclaré alors qu'il manquait à la
223
+ * source, et les trois champs HIP-3 traversaient le gateway (`{ ...market }`)
224
+ * sans qu'aucun des deux types ne les connaisse. Un champ ajouté par l'exchange
225
+ * se propage maintenant aux deux formes, ou à aucune.
111
226
  */
112
- export interface HLPerpMarket {
227
+ export interface HLPerpMarket extends HLPerpMarketInfo {
113
228
  /** Market index in the universe list. */
114
229
  index: number;
115
- /** Market symbol (e.g. BTC). */
116
- name: string;
117
- /** Size precision for orders. */
118
- szDecimals: number;
119
- /** Maximum leverage allowed. */
120
- maxLeverage: number;
121
- /** Margin table identifier. */
122
- marginTableId?: number;
123
- /** Whether the market only supports isolated margin mode. */
124
- onlyIsolated?: boolean;
125
- /** Whether the market has been delisted by the exchange. */
126
- isDelisted?: boolean;
127
- /** Optional restriction applied to the market margin mode. */
128
- marginMode?: 'strictIsolated' | 'noCross';
129
230
  /** Current mark price. */
130
231
  markPrice?: DecimalString;
131
- /** Current mid price. */
132
- midPrice?: DecimalString;
232
+ /**
233
+ * Current mid price, `null` quand l'exchange n'en publie pas (marché
234
+ * délisté). `undefined` dit autre chose : la ligne de contexte manquait en
235
+ * face de l'entrée d'univers — deux incidents, deux diagnostics.
236
+ */
237
+ midPrice?: DecimalString | null;
133
238
  /** Current funding rate. */
134
239
  funding?: DecimalString;
135
240
  /** Current open interest. */
@@ -141,8 +246,8 @@ export interface HLPerpMarket {
141
246
  export interface HLPerpMarketExtended extends HLPerpMarket {
142
247
  /** Oracle price reference. */
143
248
  oraclePrice?: DecimalString;
144
- /** Premium vs oracle. */
145
- premium?: DecimalString;
249
+ /** Premium vs oracle, `null` sur un marché sans prix milieu. */
250
+ premium?: DecimalString | null;
146
251
  /** Daily notional volume. */
147
252
  dayNotionalVolume?: DecimalString;
148
253
  /** Estimated bid impact price. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syldel/hl-shared-types",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "Shared TypeScript interfaces and types for Hyperliquid integration.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",