@syldel/hl-shared-types 0.0.16 → 0.0.17

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
@@ -16,6 +16,33 @@ Ce package centralise les définitions TypeScript pour l'écosystème **Hyperliq
16
16
  * **Account** : États du compte, positions Perp et soldes Spot.
17
17
  * **Market** : Métadonnées des actifs et résumés de marché.
18
18
  * **Orders** : Définitions des ordres ouverts et historiques.
19
+ * **Format** : les règles de **tick et de lot** d'Hyperliquid — la seule logique exécutable
20
+ du package, et la seule qui décide ce qui part vers l'exchange.
21
+
22
+ ---
23
+
24
+ ## ⚠️ `format/` : du code, pas seulement des types
25
+
26
+ `formatPrice`, `formatSize`, `priceDecimals` et `snapPrice` appliquent les règles de
27
+ [tick and lot size](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size)
28
+ d'Hyperliquid. Elles vivent ici pour qu'il n'en existe **qu'une seule implémentation** :
29
+ le gateway les applique en sortie, et le bot doit pouvoir savoir *avant d'envoyer* ce qui
30
+ sera posé. Deux implémentations, c'est la garantie qu'un émetteur croira un jour avoir posé
31
+ autre chose que ce qui l'a été — ce qui s'est produit, et se paie sur un stop loss.
32
+
33
+ Trois conséquences pour qui touche à ce dossier :
34
+
35
+ * **aucune dépendance**, ici moins qu'ailleurs : le consommateur de ce code est le processus
36
+ qui signe les transactions ;
37
+ * **rien ne passe par `Number`** — tout le calcul se fait sur les chiffres écrits, en
38
+ `BigInt` ;
39
+ * **la conformité se prouve** : `test/tick-and-lot.spec.ts` rejoue *tous* les exemples de la
40
+ documentation, sourcés et datés. `npm run build` lance les tests avant de compiler — une
41
+ logique exécutable non testée ne se publie pas.
42
+
43
+ ```bash
44
+ npm test
45
+ ```
19
46
 
20
47
  ---
21
48
 
@@ -0,0 +1 @@
1
+ export * from './tick-and-lot';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./tick-and-lot"), exports);
@@ -0,0 +1,89 @@
1
+ /**
2
+ * ============================================================================
3
+ * PRIX ET TAILLES : LES RÈGLES DE TICK ET DE LOT D'HYPERLIQUID
4
+ *
5
+ * Source : https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
6
+ * relevée le 2026-09-23. Deux règles, et une exception :
7
+ *
8
+ * - **taille** : tronquée à `szDecimals`, propre à chaque actif (réponse `meta`) ;
9
+ * - **prix** : au plus 5 chiffres significatifs, ET au plus
10
+ * `MAX_DECIMALS - szDecimals` décimales, `MAX_DECIMALS` valant 6 en perp et
11
+ * 8 en spot ;
12
+ * - **un prix entier est toujours accepté**, quel que soit son nombre de
13
+ * chiffres significatifs (`123456` est valide là où `12345.6` ne l'est pas).
14
+ *
15
+ * Ce module vit ici, et non dans le gateway ou le bot, pour qu'il n'en existe
16
+ * **qu'une seule implémentation** : un prix mal écrit est refusé par
17
+ * Hyperliquid, ou accepté sous une forme tronquée qui n'est plus celle qu'on
18
+ * voulait. Sur un stop loss, la différence entre les deux, c'est une position
19
+ * protégée et une position qui ne l'est pas. Deux implémentations, c'est la
20
+ * garantie qu'un émetteur croira un jour avoir posé autre chose que ce qui
21
+ * l'a été.
22
+ *
23
+ * ⚠️ Un faux gateway de test, lui, doit garder sa **copie indépendante** : s'il
24
+ * importait ces fonctions, un défaut s'y annulerait des deux côtés et aucun
25
+ * test ne le verrait.
26
+ *
27
+ * Rien ne passe par `Number` : tout le calcul se fait sur les chiffres écrits,
28
+ * en `BigInt`. Un `parseFloat` réintroduirait exactement l'erreur d'arrondi que
29
+ * ces règles servent à éviter.
30
+ * ============================================================================
31
+ */
32
+ /** Marché visé : les deux n'ont pas le même plafond de décimales. */
33
+ export type HLMarketType = 'perp' | 'spot';
34
+ /**
35
+ * Sens de l'arrondi. `truncate` va vers zéro — c'est ce que fait Hyperliquid,
36
+ * et le seul sens autorisé pour une taille. `up` et `down` vont vers +∞ et
37
+ * −∞, ce qui ne diffère de `truncate` que sur une valeur négative.
38
+ */
39
+ export type RoundingMode = 'truncate' | 'up' | 'down' | 'nearest';
40
+ /** Levée plutôt que de rendre une valeur que l'exchange refuserait. */
41
+ export declare class TickAndLotError extends Error {
42
+ constructor(message: string);
43
+ }
44
+ /** `MAX_DECIMALS` de la documentation, par type de marché. */
45
+ export declare const MAX_PRICE_DECIMALS: Readonly<Record<HLMarketType, number>>;
46
+ /** Le plafond de chiffres significatifs d'un prix non entier. */
47
+ export declare const MAX_PRICE_SIGNIFICANT_DIGITS = 5;
48
+ /**
49
+ * Arrondit une valeur à `decimals` décimales, dans le sens demandé, sans
50
+ * jamais passer par un flottant.
51
+ */
52
+ export declare function roundDecimal(value: string | number, decimals: number, mode?: RoundingMode): string;
53
+ /**
54
+ * Le nombre de décimales que ce prix a le droit d'avoir — les deux règles
55
+ * réunies en un seul nombre.
56
+ *
57
+ * Le plancher à zéro **est** l'exception des entiers : quand les chiffres
58
+ * significatifs en réclameraient moins que zéro décimale (un prix au-delà de
59
+ * 99 999), la documentation autorise malgré tout n'importe quel entier, donc
60
+ * on s'arrête à l'entier plutôt que de raboter aussi les unités.
61
+ */
62
+ export declare function priceDecimals(price: string | number, szDecimals: number, type?: HLMarketType): number;
63
+ /**
64
+ * Le prix, réécrit comme Hyperliquid l'accepte : tronqué à ce que
65
+ * `priceDecimals` autorise.
66
+ *
67
+ * @throws {TickAndLotError} si la valeur est illisible, ou tronquée à zéro.
68
+ */
69
+ export declare function formatPrice(price: string | number, szDecimals: number, type?: HLMarketType): string;
70
+ /**
71
+ * La taille, réécrite comme Hyperliquid l'accepte : **tronquée** à
72
+ * `szDecimals`, jamais arrondie. Arrondir vers le haut, ce serait trader plus
73
+ * que ce qui a été calculé — dépasser une position sur un ordre `reduceOnly`,
74
+ * ou le collatéral sur une ouverture.
75
+ *
76
+ * @throws {TickAndLotError} si la valeur est illisible, ou tronquée à zéro.
77
+ */
78
+ export declare function formatSize(size: string | number, szDecimals: number): string;
79
+ /**
80
+ * Pose un prix sur la grille de l'actif **dans un sens choisi**, et garantit
81
+ * que le résultat en est un point fixe : `formatPrice(snapPrice(p)) === snapPrice(p)`.
82
+ *
83
+ * C'est ce que `formatPrice` seul ne sait pas faire — il tronque toujours.
84
+ * Un émetteur qui veut qu'un stop ne s'éloigne jamais de son ancre a besoin du
85
+ * sens opposé, et il a besoin que le formatage final ne défasse pas ce choix.
86
+ *
87
+ * @throws {TickAndLotError} si la valeur est illisible, ou ramenée à zéro.
88
+ */
89
+ export declare function snapPrice(price: string | number, szDecimals: number, type?: HLMarketType, mode?: RoundingMode): string;
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ /**
3
+ * ============================================================================
4
+ * PRIX ET TAILLES : LES RÈGLES DE TICK ET DE LOT D'HYPERLIQUID
5
+ *
6
+ * Source : https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
7
+ * relevée le 2026-09-23. Deux règles, et une exception :
8
+ *
9
+ * - **taille** : tronquée à `szDecimals`, propre à chaque actif (réponse `meta`) ;
10
+ * - **prix** : au plus 5 chiffres significatifs, ET au plus
11
+ * `MAX_DECIMALS - szDecimals` décimales, `MAX_DECIMALS` valant 6 en perp et
12
+ * 8 en spot ;
13
+ * - **un prix entier est toujours accepté**, quel que soit son nombre de
14
+ * chiffres significatifs (`123456` est valide là où `12345.6` ne l'est pas).
15
+ *
16
+ * Ce module vit ici, et non dans le gateway ou le bot, pour qu'il n'en existe
17
+ * **qu'une seule implémentation** : un prix mal écrit est refusé par
18
+ * Hyperliquid, ou accepté sous une forme tronquée qui n'est plus celle qu'on
19
+ * voulait. Sur un stop loss, la différence entre les deux, c'est une position
20
+ * protégée et une position qui ne l'est pas. Deux implémentations, c'est la
21
+ * garantie qu'un émetteur croira un jour avoir posé autre chose que ce qui
22
+ * l'a été.
23
+ *
24
+ * ⚠️ Un faux gateway de test, lui, doit garder sa **copie indépendante** : s'il
25
+ * importait ces fonctions, un défaut s'y annulerait des deux côtés et aucun
26
+ * test ne le verrait.
27
+ *
28
+ * Rien ne passe par `Number` : tout le calcul se fait sur les chiffres écrits,
29
+ * en `BigInt`. Un `parseFloat` réintroduirait exactement l'erreur d'arrondi que
30
+ * ces règles servent à éviter.
31
+ * ============================================================================
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.MAX_PRICE_SIGNIFICANT_DIGITS = exports.MAX_PRICE_DECIMALS = exports.TickAndLotError = void 0;
35
+ exports.roundDecimal = roundDecimal;
36
+ exports.priceDecimals = priceDecimals;
37
+ exports.formatPrice = formatPrice;
38
+ exports.formatSize = formatSize;
39
+ exports.snapPrice = snapPrice;
40
+ /** Levée plutôt que de rendre une valeur que l'exchange refuserait. */
41
+ class TickAndLotError extends Error {
42
+ constructor(message) {
43
+ super(message);
44
+ this.name = 'TickAndLotError';
45
+ }
46
+ }
47
+ exports.TickAndLotError = TickAndLotError;
48
+ /** `MAX_DECIMALS` de la documentation, par type de marché. */
49
+ exports.MAX_PRICE_DECIMALS = {
50
+ perp: 6,
51
+ spot: 8,
52
+ };
53
+ /** Le plafond de chiffres significatifs d'un prix non entier. */
54
+ exports.MAX_PRICE_SIGNIFICANT_DIGITS = 5;
55
+ /** Un décimal simple, signe optionnel : `12`, `-0.5`, `.75`, `3.`. */
56
+ const PLAIN_DECIMAL = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/;
57
+ const EXPONENTIAL = /^([+-]?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/;
58
+ /**
59
+ * Réécrit une notation scientifique en décimal simple. `String(0.0000001)`
60
+ * rend `'1e-7'`, que la documentation n'accepte pas et que nous refuserions
61
+ * plus loin : autant l'écrire correctement ici.
62
+ */
63
+ function expandExponential(text) {
64
+ const match = EXPONENTIAL.exec(text);
65
+ if (!match)
66
+ return text;
67
+ const [, sign, int, frac = '', exponentText] = match;
68
+ const digits = `${int}${frac}`;
69
+ const pointIndex = int.length + Number(exponentText);
70
+ if (pointIndex <= 0) {
71
+ return `${sign}0.${'0'.repeat(-pointIndex)}${digits}`;
72
+ }
73
+ if (pointIndex >= digits.length) {
74
+ return `${sign}${digits}${'0'.repeat(pointIndex - digits.length)}`;
75
+ }
76
+ return `${sign}${digits.slice(0, pointIndex)}.${digits.slice(pointIndex)}`;
77
+ }
78
+ /**
79
+ * Rend le texte décimal d'une valeur.
80
+ *
81
+ * Un `number` est une valeur **calculée** : on l'écrit exactement, notation
82
+ * scientifique dépliée. Une `string` est un texte qui vient déjà d'ailleurs —
83
+ * d'un DTO, de l'API — et doit donc être un décimal simple : une notation
84
+ * scientifique y signale qu'un flottant s'est glissé en amont, et la laisser
85
+ * passer masquerait le défaut.
86
+ */
87
+ function toDecimalText(value, field) {
88
+ if (typeof value === 'number') {
89
+ if (!Number.isFinite(value)) {
90
+ throw new TickAndLotError(`${field} is not finite: ${String(value)}`);
91
+ }
92
+ return expandExponential(String(value));
93
+ }
94
+ const text = String(value).trim();
95
+ if (!PLAIN_DECIMAL.test(text)) {
96
+ throw new TickAndLotError(`${field} is not a plain decimal string: ${JSON.stringify(value)}`);
97
+ }
98
+ return text;
99
+ }
100
+ function split(text) {
101
+ const negative = text.startsWith('-');
102
+ const [int = '', frac = ''] = text.replace(/^[+-]/, '').split('.');
103
+ return { negative, int: int || '0', frac };
104
+ }
105
+ /** Réécrit une valeur mise à l'échelle, sans zéro de queue ni `-0`. */
106
+ function formatUnits(negative, units, decimals) {
107
+ const digits = units.toString().padStart(decimals + 1, '0');
108
+ const int = digits.slice(0, digits.length - decimals);
109
+ const frac = decimals > 0 ? digits.slice(digits.length - decimals).replace(/0+$/, '') : '';
110
+ const body = frac ? `${int}.${frac}` : int;
111
+ return negative && units !== 0n ? `-${body}` : body;
112
+ }
113
+ function assertWholeCount(value, field) {
114
+ if (!Number.isInteger(value) || value < 0) {
115
+ throw new TickAndLotError(`${field} must be a non-negative integer: ${String(value)}`);
116
+ }
117
+ }
118
+ /**
119
+ * L'exposant décimal de la valeur — `2` pour 345, `-3` pour 0,001234 — ou
120
+ * `null` pour zéro, qui n'en a pas.
121
+ */
122
+ function log10Floor(text) {
123
+ const { int, frac } = split(text);
124
+ const significantInt = int.replace(/^0+/, '');
125
+ if (significantInt)
126
+ return significantInt.length - 1;
127
+ const leadingZeros = /^0*/.exec(frac)?.[0].length ?? 0;
128
+ if (leadingZeros === frac.length)
129
+ return null;
130
+ return -(leadingZeros + 1);
131
+ }
132
+ /**
133
+ * Arrondit une valeur à `decimals` décimales, dans le sens demandé, sans
134
+ * jamais passer par un flottant.
135
+ */
136
+ function roundDecimal(value, decimals, mode = 'truncate') {
137
+ assertWholeCount(decimals, 'decimals');
138
+ const { negative, int, frac } = split(toDecimalText(value, 'value'));
139
+ const kept = frac.slice(0, decimals).padEnd(decimals, '0');
140
+ const dropped = frac.slice(decimals);
141
+ let units = BigInt(`${int}${kept}`);
142
+ if (/[1-9]/.test(dropped)) {
143
+ const awayFromZero = mode === 'nearest'
144
+ ? dropped.charAt(0) >= '5'
145
+ : mode === 'up'
146
+ ? !negative
147
+ : mode === 'down'
148
+ ? negative
149
+ : false;
150
+ if (awayFromZero)
151
+ units += 1n;
152
+ }
153
+ return formatUnits(negative, units, decimals);
154
+ }
155
+ /**
156
+ * Le nombre de décimales que ce prix a le droit d'avoir — les deux règles
157
+ * réunies en un seul nombre.
158
+ *
159
+ * Le plancher à zéro **est** l'exception des entiers : quand les chiffres
160
+ * significatifs en réclameraient moins que zéro décimale (un prix au-delà de
161
+ * 99 999), la documentation autorise malgré tout n'importe quel entier, donc
162
+ * on s'arrête à l'entier plutôt que de raboter aussi les unités.
163
+ */
164
+ function priceDecimals(price, szDecimals, type = 'perp') {
165
+ assertWholeCount(szDecimals, 'szDecimals');
166
+ const byDecimals = Math.max(exports.MAX_PRICE_DECIMALS[type] - szDecimals, 0);
167
+ const magnitude = log10Floor(toDecimalText(price, 'price'));
168
+ if (magnitude === null)
169
+ return byDecimals;
170
+ const bySignificantDigits = exports.MAX_PRICE_SIGNIFICANT_DIGITS - 1 - magnitude;
171
+ return Math.min(byDecimals, Math.max(bySignificantDigits, 0));
172
+ }
173
+ /**
174
+ * Le prix, réécrit comme Hyperliquid l'accepte : tronqué à ce que
175
+ * `priceDecimals` autorise.
176
+ *
177
+ * @throws {TickAndLotError} si la valeur est illisible, ou tronquée à zéro.
178
+ */
179
+ function formatPrice(price, szDecimals, type = 'perp') {
180
+ const decimals = priceDecimals(price, szDecimals, type);
181
+ const formatted = roundDecimal(price, decimals, 'truncate');
182
+ if (formatted === '0') {
183
+ throw new TickAndLotError('Price is too small and was truncated to 0');
184
+ }
185
+ return formatted;
186
+ }
187
+ /**
188
+ * La taille, réécrite comme Hyperliquid l'accepte : **tronquée** à
189
+ * `szDecimals`, jamais arrondie. Arrondir vers le haut, ce serait trader plus
190
+ * que ce qui a été calculé — dépasser une position sur un ordre `reduceOnly`,
191
+ * ou le collatéral sur une ouverture.
192
+ *
193
+ * @throws {TickAndLotError} si la valeur est illisible, ou tronquée à zéro.
194
+ */
195
+ function formatSize(size, szDecimals) {
196
+ assertWholeCount(szDecimals, 'szDecimals');
197
+ const formatted = roundDecimal(size, szDecimals, 'truncate');
198
+ if (formatted === '0') {
199
+ throw new TickAndLotError('Size is too small and was truncated to 0');
200
+ }
201
+ return formatted;
202
+ }
203
+ /**
204
+ * Pose un prix sur la grille de l'actif **dans un sens choisi**, et garantit
205
+ * que le résultat en est un point fixe : `formatPrice(snapPrice(p)) === snapPrice(p)`.
206
+ *
207
+ * C'est ce que `formatPrice` seul ne sait pas faire — il tronque toujours.
208
+ * Un émetteur qui veut qu'un stop ne s'éloigne jamais de son ancre a besoin du
209
+ * sens opposé, et il a besoin que le formatage final ne défasse pas ce choix.
210
+ *
211
+ * @throws {TickAndLotError} si la valeur est illisible, ou ramenée à zéro.
212
+ */
213
+ function snapPrice(price, szDecimals, type = 'perp', mode = 'truncate') {
214
+ const snapped = roundDecimal(price, priceDecimals(price, szDecimals, type), mode);
215
+ // Un arrondi vers l'extérieur peut franchir un palier — 9,9999 devient 10 —
216
+ // et la grille change avec l'ordre de grandeur. On la recalcule une fois.
217
+ const settled = roundDecimal(snapped, priceDecimals(snapped, szDecimals, type), mode);
218
+ if (settled === '0') {
219
+ throw new TickAndLotError('Price is too small and was snapped to 0');
220
+ }
221
+ if (formatPrice(settled, szDecimals, type) !== settled) {
222
+ throw new TickAndLotError(`snapPrice produced ${settled}, which is not on the grid for szDecimals ${szDecimals}`);
223
+ }
224
+ return settled;
225
+ }
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './interfaces';
2
+ export * from './format';
package/dist/index.js CHANGED
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./interfaces"), exports);
18
+ __exportStar(require("./format"), exports);
package/package.json CHANGED
@@ -1,50 +1,54 @@
1
- {
2
- "name": "@syldel/hl-shared-types",
3
- "version": "0.0.16",
4
- "description": "Shared TypeScript interfaces and types for Hyperliquid integration.",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/Syldel/hl-shared-types.git"
10
- },
11
- "bugs": {
12
- "url": "https://github.com/Syldel/hl-shared-types/issues"
13
- },
14
- "homepage": "https://github.com/Syldel/hl-shared-types#readme",
15
- "files": [
16
- "dist"
17
- ],
18
- "scripts": {
19
- "lint": "eslint .",
20
- "lint:fix": "eslint . --fix",
21
- "clean": "rm -rf dist",
22
- "build": "npm run lint && npm run clean && tsc",
23
- "prepublishOnly": "npm run build",
24
- "release": "npm run build && npm version patch && npm publish"
25
- },
26
- "publishConfig": {
27
- "access": "public"
28
- },
29
- "keywords": [
30
- "hyperliquid",
31
- "trading",
32
- "types",
33
- "interfaces",
34
- "crypto",
35
- "exchange",
36
- "defi"
37
- ],
38
- "author": "Syl. D.",
39
- "license": "ISC",
40
- "devDependencies": {
41
- "eslint": "^9.39.2",
42
- "eslint-config-prettier": "^10.1.8",
43
- "eslint-plugin-jsonc": "^2.21.0",
44
- "eslint-plugin-prettier": "^5.5.5",
45
- "jsonc-eslint-parser": "^2.4.2",
46
- "prettier": "^3.8.0",
47
- "typescript": "^5.3.3",
48
- "typescript-eslint": "^8.53.0"
49
- }
50
- }
1
+ {
2
+ "name": "@syldel/hl-shared-types",
3
+ "version": "0.0.17",
4
+ "description": "Shared TypeScript interfaces and types for Hyperliquid integration.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Syldel/hl-shared-types.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/Syldel/hl-shared-types/issues"
13
+ },
14
+ "homepage": "https://github.com/Syldel/hl-shared-types#readme",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "test": "jest",
20
+ "lint": "eslint .",
21
+ "lint:fix": "eslint . --fix",
22
+ "clean": "rm -rf dist",
23
+ "build": "npm run lint && npm run test && npm run clean && tsc",
24
+ "prepublishOnly": "npm run build",
25
+ "release": "npm run build && npm version patch && npm publish"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "keywords": [
31
+ "hyperliquid",
32
+ "trading",
33
+ "types",
34
+ "interfaces",
35
+ "crypto",
36
+ "exchange",
37
+ "defi"
38
+ ],
39
+ "author": "Syl. D.",
40
+ "license": "ISC",
41
+ "devDependencies": {
42
+ "@types/jest": "^30.0.0",
43
+ "eslint": "^9.39.2",
44
+ "eslint-config-prettier": "^10.1.8",
45
+ "eslint-plugin-jsonc": "^2.21.0",
46
+ "eslint-plugin-prettier": "^5.5.5",
47
+ "jest": "^30.5.2",
48
+ "jsonc-eslint-parser": "^2.4.2",
49
+ "prettier": "^3.8.0",
50
+ "ts-jest": "^29.4.13",
51
+ "typescript": "^5.3.3",
52
+ "typescript-eslint": "^8.53.0"
53
+ }
54
+ }