@syldel/hl-shared-types 0.0.23 → 0.0.25

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 CHANGED
@@ -119,10 +119,48 @@ git push origin main --follow-tags
119
119
 
120
120
  ---
121
121
 
122
+ ## 🔍 Avant de déclarer un champ : d'où vient l'information
123
+
124
+ Chaque champ de ce paquet est une **affirmation sur ce que l'exchange rend**, et les trois
125
+ dépôts la croient. Une affirmation fausse ne se voit pas : elle se paie plus loin, sur un
126
+ dimensionnement ou un affichage. Avant d'ajouter, de resserrer ou d'élargir un type, lire
127
+ [`nest-hyperliquid-gateway/docs/sources.md`](https://github.com/Syldel/nest-hyperliquid-gateway/blob/main/docs/sources.md).
128
+
129
+ En résumé de ce document :
130
+
131
+ * **La mesure** (captures du gateway, lectures `/hyperliquid/info/*`) prouve qu'une forme
132
+ existe, jamais qu'elle soit la seule. Un `null` vu une fois clôt la nullité d'un champ ;
133
+ mille valeurs présentes ne closent rien. Et un échantillon se décrit honnêtement — 22
134
+ instantanés d'une même position ne sont pas 22 observations.
135
+ * **La doc officielle** fait autorité sur les noms, et tient sur **un exemple par
136
+ endpoint** : elle est donc muette sur ce qui varie. Un champ absent d'un exemple n'est ni
137
+ absent de l'API ni optionnel.
138
+ * **Le SDK Python officiel**
139
+ ([hyperliquid-dex/hyperliquid-python-sdk](https://github.com/hyperliquid-dex/hyperliquid-python-sdk))
140
+ est de première partie **et typé** : il tranche les unions, les champs propres à une
141
+ variante et les valeurs énumérées que la prose laisse en suspens. Mais il ne type pas
142
+ tout, et son silence n'est pas une réponse.
143
+ * **Les SDK communautaires ne concluent pas.** La page d'API en recommande plusieurs — un en
144
+ Rust, deux en TypeScript, plus CCXT — et le dit : ils sont écrits par la communauté. Être
145
+ lié par la doc officielle donne de la visibilité, pas de l'autorité ; ils lisent la même
146
+ API que nous et peuvent s'être trompés pareil. Ils servent à repérer une question, jamais
147
+ à la clore — et le piège est celui en TypeScript, dont on a envie de recopier une union
148
+ toute faite. Il n'existe **aucun SDK TypeScript de première partie**.
149
+
150
+ `HLPerpLeverage` est le cas d'école : ni les captures (que du `cross`) ni l'exemple de la
151
+ doc (que de l'`isolated`) ne pouvaient trancher, et `hyperliquid/utils/types.py` déclare les
152
+ deux branches. Les types portent leur source et leur date en commentaire — c'est ce qui
153
+ permet de les contredire plus tard au lieu de devoir tout remesurer.
154
+
155
+ ---
156
+
122
157
  ## 📝 Conventions de code
123
158
 
124
159
  * **Sauts de ligne** : Une ligne vide est automatiquement insérée entre chaque `interface` pour une meilleure lisibilité.
125
160
  * **Naming** : Toutes les interfaces commencent par `HL`.
126
161
  * **Types stricts** : Usage de `DecimalString` pour la précision financière.
162
+ * **Fins de ligne** : LF partout, imposé par `.gitattributes` et non par la configuration de
163
+ la machine — le paquet publié embarque du code généré par `tsc`, dont les fins de ligne
164
+ suivent celles des sources.
127
165
 
128
166
  ---
@@ -4,3 +4,4 @@ export * from './l2Book.interfaces';
4
4
  export * from './active-asset.interfaces';
5
5
  export * from './account-abstraction.type';
6
6
  export * from './collateral-balance.interfaces';
7
+ export * from './user-fees.interfaces';
@@ -20,3 +20,4 @@ __exportStar(require("./l2Book.interfaces"), exports);
20
20
  __exportStar(require("./active-asset.interfaces"), exports);
21
21
  __exportStar(require("./account-abstraction.type"), exports);
22
22
  __exportStar(require("./collateral-balance.interfaces"), exports);
23
+ __exportStar(require("./user-fees.interfaces"), exports);
@@ -0,0 +1,113 @@
1
+ import { DecimalString, HexString } from '../common';
2
+ /**
3
+ * ============================================================================
4
+ * LE BARÈME RÉEL D'UN UTILISATEUR
5
+ *
6
+ * Réponse de `userFees`, servie telle quelle par
7
+ * `GET /hyperliquid/info/user-fees` du gateway.
8
+ *
9
+ * Recopiée de la documentation officielle (« Query a user's fees », relevée le
10
+ * 2026-10-11), **pas déduite** de la formule publiée sur la page des frais. Les
11
+ * deux ne portent pas les mêmes noms, et c'est le piège : le pseudo-code de la
12
+ * formule écrit `fees: { makerRate, takerRate }`, alors que le point de
13
+ * terminaison ne connaît ni l'un ni l'autre. Ce sont `userCrossRate` (preneur)
14
+ * et `userAddRate` (apporteur).
15
+ *
16
+ * ⚠️ Tout est en **chaînes décimales**, y compris des taux qui peuvent être
17
+ * négatifs (`tiers.mm[].add` vaut `'-0.00001'` : un rebate). `Number('')` rend
18
+ * `0`, soit un barème parfaitement plausible — donc jamais de conversion sans
19
+ * refuser ce qui n'est pas un nombre.
20
+ * ============================================================================
21
+ */
22
+ /** Un palier de volume : au-delà de `ntlCutoff`, ces taux s'appliquent. */
23
+ export interface HlVipFeeTier {
24
+ ntlCutoff: DecimalString;
25
+ cross: DecimalString;
26
+ add: DecimalString;
27
+ spotCross: DecimalString;
28
+ spotAdd: DecimalString;
29
+ }
30
+ /**
31
+ * Un palier d'apporteur de liquidité. `add` y est **négatif** : c'est un
32
+ * rebate, payé à l'utilisateur et non prélevé.
33
+ */
34
+ export interface HlMakerFeeTier {
35
+ makerFractionCutoff: DecimalString;
36
+ add: DecimalString;
37
+ }
38
+ export interface HlStakingDiscountTier {
39
+ bpsOfMaxSupply: DecimalString;
40
+ discount: DecimalString;
41
+ }
42
+ /** Le barème **public**, identique pour tous : les paliers de base et leurs seuils. */
43
+ export interface HlFeeSchedule {
44
+ /** Preneur, perp. `'0.00045'` au palier de base. */
45
+ cross: DecimalString;
46
+ /** Apporteur, perp. `'0.00015'` au palier de base. */
47
+ add: DecimalString;
48
+ spotCross: DecimalString;
49
+ spotAdd: DecimalString;
50
+ tiers: {
51
+ vip: HlVipFeeTier[];
52
+ mm: HlMakerFeeTier[];
53
+ };
54
+ referralDiscount: DecimalString;
55
+ stakingDiscountTiers: HlStakingDiscountTier[];
56
+ }
57
+ /** Le volume d'un jour, tel que le barème le compte. */
58
+ export interface HlDailyUserVolume {
59
+ /** `'2025-05-23'` — une date sans heure ni fuseau. */
60
+ date: string;
61
+ userCross: DecimalString;
62
+ userAdd: DecimalString;
63
+ exchange: DecimalString;
64
+ }
65
+ /**
66
+ * Le lien entre un compte qui stake et un compte qui trade.
67
+ *
68
+ * ⚠️ Lier est **irréversible** et donne au compte de staking le pouvoir de
69
+ * vider le compte de trading — ne jamais proposer cette action depuis l'app.
70
+ */
71
+ export interface HlStakingLink {
72
+ type: string;
73
+ stakingUser: HexString;
74
+ }
75
+ export interface HlActiveStakingDiscount {
76
+ bpsOfMaxSupply: DecimalString;
77
+ discount: DecimalString;
78
+ }
79
+ export interface HlUserFees {
80
+ dailyUserVlm: HlDailyUserVolume[];
81
+ feeSchedule: HlFeeSchedule;
82
+ /**
83
+ * Le taux **preneur** de cet utilisateur, déjà net de son palier de volume et
84
+ * de sa remise de staking — mais **pas** de sa remise de parrainage, que la
85
+ * formule officielle applique à part, ni du barème propre à un marché HIP-3.
86
+ *
87
+ * Vérifié sur l'exemple de la documentation : `'0.000315'` vaut
88
+ * `0,00045 × 0,7`, et `activeStakingDiscount.discount` y vaut `'0.3'`.
89
+ */
90
+ userCrossRate: DecimalString;
91
+ /** Le taux **apporteur**, mêmes réserves. Peut être négatif : voir `HlMakerFeeTier`. */
92
+ userAddRate: DecimalString;
93
+ userSpotCrossRate: DecimalString;
94
+ userSpotAddRate: DecimalString;
95
+ /** Entre `'0.0'` et `'1.0'`. C'est le `(1 - activeReferralDiscount)` de la formule. */
96
+ activeReferralDiscount: DecimalString;
97
+ /**
98
+ * `null` quand aucun essai n'est en cours.
99
+ *
100
+ * ⚠️ Seule la valeur `null` a été observée : la forme du cas non nul est
101
+ * **inconnue**, et l'inventer ici donnerait à un consommateur l'illusion de
102
+ * pouvoir la lire. `unknown` force à la vérifier avant d'y toucher — et
103
+ * `unknown | null` se réduirait à `unknown`, donc le `null` est explicite
104
+ * dans ce commentaire plutôt que dans un type qui ne le dirait pas.
105
+ */
106
+ trial: unknown;
107
+ feeTrialReward: DecimalString;
108
+ /** `null` quand il n'y en a pas de prévu. */
109
+ nextTrialAvailableTimestamp: number | null;
110
+ /** Absent quand le compte ne stake pas depuis un autre compte. */
111
+ stakingLink?: HlStakingLink | null;
112
+ activeStakingDiscount?: HlActiveStakingDiscount | null;
113
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -25,6 +25,12 @@ import { DecimalString, Timestamp } from '../common';
25
25
  * porte `rawUsd: "-95.059824"`. Aucun des deux ne couvre l'autre branche — le
26
26
  * SDK, lui, les couvre toutes les deux.
27
27
  *
28
+ * ⚠️ Ce « officiel » ne se déduit **pas** du nom de l'organisation GitHub, qui
29
+ * n'est d'ailleurs pas vérifiée (`is_verified: false`). Il repose sur la page
30
+ * d'API de la documentation, qui distingue ce SDK des bibliothèques
31
+ * communautaires, et sur PyPI, qui le publie sous `hello@hyperliquid.xyz`. La
32
+ * chaîne et ses limites : `nest-hyperliquid-gateway/docs/sources.md`.
33
+ *
28
34
  * Pourquoi l'union et non `rawUsd?: DecimalString` : l'optionnel rendrait
29
35
  * `lev.rawUsd` lisible sans vérifier `type`, et `Number(undefined)` rend `NaN`
30
36
  * sans un mot. L'union en fait une erreur de compilation. Et si un cross
@@ -0,0 +1,115 @@
1
+ import { DecimalString, Timestamp } from '../common';
2
+ /**
3
+ * ============================================================================
4
+ * L'HISTORIQUE DE FUNDING — LE SEUL CHAMP DE CONTEXTE QUI AIT UNE VRAIE SÉRIE
5
+ *
6
+ * `fundingHistory` est, au 2026-10-06, le **seul** endpoint d'information qui
7
+ * rende une série temporelle d'un champ de contexte de marché. Il n'existe
8
+ * aucun endpoint documenté pour l'historique de l'intérêt ouvert, ni pour celui
9
+ * des prix d'impact : ces valeurs ne sont lisibles qu'à l'instant courant.
10
+ *
11
+ * C'est ce qui décide de ce qu'un moteur de règles peut en faire : une
12
+ * transformation glissante (z-score, pente, percentile) a besoin d'une série,
13
+ * donc elle n'est légitime que sur `fundingRate` et `premium`.
14
+ *
15
+ * ## Ce qui a été mesuré, le 2026-10-06
16
+ *
17
+ * Deux appels, sur six heures, sur `api.hyperliquid.xyz` :
18
+ *
19
+ * - **BTC** (vivant) : 6 entrées pour 6 heures — la cadence est bien horaire,
20
+ * ce que la documentation confirme (« funding is paid every hour at one
21
+ * eighth of the computed rate »). Quatre clés, toutes en chaîne sauf `time`.
22
+ * **Aucun nul**, sur aucun champ.
23
+ * - **MATIC** (délisté) : 6 entrées également, avec `fundingRate: "0.0"` et
24
+ * `premium: "0.0"`.
25
+ * - **xyz:XYZ100** (HIP-3, vivant) : 6 entrées, écarts de 3 600 000 ms ± 20 ms,
26
+ * et le `coin` rendu est identique à celui demandé, préfixe compris.
27
+ *
28
+ * ⚠️ Les horodatages ne tombent **pas exactement** sur l'heure : les restes
29
+ * modulo une heure relevés valaient 37, 39, 27, 7, 46 et 24 ms. Aligner une
30
+ * fenêtre de requête sur l'heure pleine reste correct — `startTime` est
31
+ * inclusif, donc arrondir vers le bas attrape l'entrée — mais comparer un
32
+ * horodatage à une frontière d'heure par égalité ne marcherait pas.
33
+ *
34
+ * ## ⚠️ Trois pièges que ces mesures révèlent
35
+ *
36
+ * **1. `"0.0"` a trois significations différentes, et rien ne les distingue
37
+ * dans cette réponse.** Mesuré le 2026-10-06 via `perpDexs` :
38
+ *
39
+ * - un **marché délisté** rend `"0.0"` (MATIC) ;
40
+ * - un **marché vivant et sain** peut rendre `"0.0"` en permanence, parce que
41
+ * son dex déclare un multiplicateur de funding nul : `assetToFundingMultiplier`
42
+ * vaut `0.0` sur **tous** les actifs de `flx` et de `vntl` ;
43
+ * - et un financement réellement nul à cette heure-là.
44
+ *
45
+ * Une règle du genre `funding <= 0` serait donc vraie en permanence sur des
46
+ * marchés parfaitement vivants. Un consommateur doit croiser cette série avec
47
+ * `isDelisted` (voir `HLPerpMarketInfo`) **et** avec le multiplicateur du dex
48
+ * (voir `HLPerpDex.assetToFundingMultiplier`). L'API fournit ici elle-même la
49
+ * valeur de repli plausible et fausse que ce dépôt refuse d'habitude de
50
+ * fabriquer.
51
+ *
52
+ * **2. Un seuil de funding absolu n'est pas transposable d'un marché à
53
+ * l'autre.** Les multiplicateurs relevés vont de `0.0` (`flx`, `vntl`) à
54
+ * `0.000001` (`cash`), `0.01` à `1.0` (`hyna`, qui les fait varier **par
55
+ * actif** dans un même dex), `0.1` à `0.6` (`para`), `0.125` à `0.5` (`io`),
56
+ * `0.5` partout sur `xyz`. Trois dex n'en déclarent aucun. Un `funding >
57
+ * 0.00001` serait donc courant sur l'un et impossible sur l'autre : ce champ
58
+ * se compare **relativement** (z-score, percentile) ou normalisé par le
59
+ * multiplicateur, jamais à une constante écrite en dur.
60
+ *
61
+ * **3. `fundingRate` est souvent constant.** Sur BTC, les trois heures relevées
62
+ * valaient toutes `0.0000125`, soit exactement le plancher (un huitième de
63
+ * 0,01 %) ; sur `xyz:XYZ100`, toutes `0.00000625`, soit ce même plancher
64
+ * multiplié par le `0.5` du dex. Une transformation glissante sur un taux au
65
+ * plancher voit une série plate : son écart-type est nul, et un z-score n'y a
66
+ * aucun sens. `premium`, lui, varie en continu sur les deux marchés — c'est la
67
+ * série informative des deux.
68
+ *
69
+ * ## `premium` ici n'est pas `premium` dans `metaAndAssetCtxs`
70
+ *
71
+ * La documentation dit que « the premium is sampled **every 5 seconds and
72
+ * averaged over the hour** », et que `premium = impact_price_difference /
73
+ * oracle_price`. Le champ rendu ici est donc une **moyenne horaire** sur
74
+ * environ 720 échantillons, là où le `premium` d'un contexte d'actif est la
75
+ * lecture de l'instant. Les deux portent le même nom et ne sont pas la même
76
+ * quantité.
77
+ * ============================================================================
78
+ */
79
+ /**
80
+ * Une entrée de l'historique de funding, telle que `fundingHistory` la rend.
81
+ *
82
+ * Aucun champ n'est optionnel ni nullable : mesuré sur un marché vivant **et**
83
+ * sur un marché délisté, l'endpoint rend toujours les quatre, et rend `"0.0"`
84
+ * plutôt que `null` quand il n'y a rien à payer.
85
+ */
86
+ export interface HLFundingHistoryEntry {
87
+ /** Le marché concerné, tel que demandé (ex. `BTC`, `xyz:XYZ100`). */
88
+ coin: string;
89
+ /**
90
+ * Le taux **horaire** réellement appliqué, soit un huitième du taux calculé
91
+ * sur 8 heures. `"0.0"` sur un marché délisté — voir l'en-tête.
92
+ */
93
+ fundingRate: DecimalString;
94
+ /**
95
+ * La prime moyenne de l'heure : `impact_price_difference / oracle_price`,
96
+ * échantillonnée toutes les 5 secondes et moyennée. Peut être négative.
97
+ */
98
+ premium: DecimalString;
99
+ /** Début de l'heure de funding, en millisecondes. */
100
+ time: Timestamp;
101
+ }
102
+ /**
103
+ * Les paramètres de `fundingHistory`.
104
+ *
105
+ * ⚠️ À plat dans le corps de la requête, contrairement à `candleSnapshot` qui
106
+ * imbrique les siens sous une clé `req`. Deux endpoints voisins, deux formes :
107
+ * c'est le genre d'écart qui se découvre par un appel qui échoue.
108
+ */
109
+ export interface HLFundingHistoryRequest {
110
+ coin: string;
111
+ /** Inclusif, en millisecondes. Requis. */
112
+ startTime: Timestamp;
113
+ /** Inclusif. Par défaut, l'instant courant. */
114
+ endTime?: Timestamp;
115
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,4 @@
1
1
  export * from './balance.interfaces';
2
2
  export * from './meta.interfaces';
3
3
  export * from './dexs.interfaces';
4
+ export * from './funding.interfaces';
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./balance.interfaces"), exports);
18
18
  __exportStar(require("./meta.interfaces"), exports);
19
19
  __exportStar(require("./dexs.interfaces"), exports);
20
+ __exportStar(require("./funding.interfaces"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syldel/hl-shared-types",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "description": "Shared TypeScript interfaces and types for Hyperliquid integration.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",