@empereur-rouge/pms-sdk 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 empereur-rouge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,506 @@
1
+ # @empereur-rouge/pms-sdk
2
+
3
+ SDK TypeScript officiel pour interagir avec le réseau **PMS** (Planetary Monetary System).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @empereur-rouge/pms-sdk
9
+ # ou
10
+ yarn add @empereur-rouge/pms-sdk
11
+ # ou
12
+ pnpm add @empereur-rouge/pms-sdk
13
+ ```
14
+
15
+ ## Structure de l'API
16
+
17
+ Le SDK est organisé en deux niveaux :
18
+
19
+ | Import | Usage | Contenu |
20
+ |--------|-------|--------|
21
+ | `@empereur-rouge/pms-sdk` | 99% des cas | `PmsWallet`, `PmsClient`, utils simples |
22
+ | `@empereur-rouge/pms-sdk/src/advanced` | Power users | `computeBlockId`, crypto, types bas niveau |
23
+
24
+ ## Démarrage Rapide
25
+
26
+ ```typescript
27
+ import { PmsWallet, PmsClient } from "@empereur-rouge/pms-sdk";
28
+
29
+ // 1. Créer un wallet
30
+ const wallet = PmsWallet.generate();
31
+ console.log("Mnemonic:", wallet.mnemonic);
32
+ console.log("Address:", wallet.address);
33
+
34
+ // 2. Connecter au réseau
35
+ const client = new PmsClient({
36
+ nodeUrl: "https://node.pms.network"
37
+ });
38
+
39
+ // 3. Consulter la balance
40
+ const balance = await client.getBalance(wallet.address);
41
+ console.log("Balance:", balance);
42
+
43
+ // 4. Envoyer des tokens
44
+ const result = await client.send({
45
+ to: "04abc123...",
46
+ amount: "10.0",
47
+ wallet,
48
+ });
49
+ console.log("Transaction:", result.block_id);
50
+ ```
51
+
52
+ ---
53
+
54
+ ## API Reference
55
+
56
+ ### `PmsWallet` - Gestion des Wallets
57
+
58
+ Le wallet gère les clés cryptographiques (secp256k1) et permet de signer des transactions.
59
+
60
+ #### Création de Wallet
61
+
62
+ ```typescript
63
+ // Générer un nouveau wallet (24 mots)
64
+ const wallet = PmsWallet.generate();
65
+
66
+ // Restaurer depuis un mnemonic
67
+ const restored = PmsWallet.fromMnemonic("word1 word2 ... word24");
68
+
69
+ // Importer depuis une clé privée (hex)
70
+ const imported = PmsWallet.fromPrivateKey("abc123...");
71
+
72
+ // Créer depuis une seed (32 bytes)
73
+ const seeded = PmsWallet.fromSeed(new Uint8Array(32));
74
+ ```
75
+
76
+ #### Propriétés
77
+
78
+ | Propriété | Type | Description |
79
+ |-----------|------|-------------|
80
+ | `address` | `string` | Adresse publique (clé publique hex non compressée, commence par `04`) |
81
+ | `publicKeyHex` | `string` | Clé publique en hexadécimal (identique à `address`) |
82
+ | `x25519PublicKeyHex` | `string` | Clé publique X25519 pour le chiffrement |
83
+ | `mnemonic` | `string \| undefined` | Phrase mnémonique (24 mots) si disponible |
84
+
85
+ #### Méthodes
86
+
87
+ ```typescript
88
+ // Signer un message
89
+ const signature: string = wallet.sign(messageBytes);
90
+
91
+ // Exporter la clé privée (hex)
92
+ const privateKey: string = wallet.exportPrivateKey();
93
+
94
+ // Vérifier une signature (statique)
95
+ const isValid: boolean = PmsWallet.verify(message, signature, publicKeyHex);
96
+ ```
97
+
98
+ #### Validation de Mnemonic
99
+
100
+ ```typescript
101
+ import { isValidMnemonic } from "@empereur-rouge/pms-sdk";
102
+
103
+ if (isValidMnemonic(userInput)) {
104
+ const wallet = PmsWallet.fromMnemonic(userInput);
105
+ }
106
+ ```
107
+
108
+ ---
109
+
110
+ ### `PmsClient` - Client API
111
+
112
+ Le client permet d'interagir avec l'API REST des nœuds PMS.
113
+
114
+ #### Configuration
115
+
116
+ ```typescript
117
+ const client = new PmsClient({
118
+ nodeUrl: "https://node.pms.network", // URL du nœud principal
119
+ seedNodes: [ // Optionnel: nœuds de secours
120
+ "https://node2.pms.network",
121
+ "https://node3.pms.network",
122
+ ],
123
+ networkId: "pms-mainnet", // Défaut: "pms-mainnet"
124
+ protocolVersion: 1, // Défaut: 1
125
+ timeout: 30000, // Timeout en ms (défaut: 30s)
126
+ enableRacing: true, // Racing pattern (défaut: true)
127
+ });
128
+ ```
129
+
130
+ #### Méthodes de Lecture
131
+
132
+ ```typescript
133
+ // Récupérer les tips du DAG (blocs les plus récents)
134
+ const tips: string[] = await client.getTips();
135
+ // Réponse: ["4aa21b8f570005b4088c53149c9afedc528d7a47127e915744a1811c11d5956c", "..."]
136
+ ```
137
+
138
+ ```typescript
139
+ // Récupérer un bloc par son ID
140
+ const block: Block = await client.getBlock(blockId);
141
+ // Réponse:
142
+ // {
143
+ // id: "4aa21b8f570005b4088c53149c9afedc528d7a47127e915744a1811c11d5956c",
144
+ // parents: ["abc123...", "def456..."],
145
+ // payload: { Plain: { TxUtxo: { ... } } },
146
+ // nonce: 12345
147
+ // }
148
+ ```
149
+
150
+ ```typescript
151
+ // Récupérer le supply total
152
+ const supply: SupplyInfo = await client.getSupply();
153
+ // Réponse:
154
+ // {
155
+ // circulating: "1000000.00000000",
156
+ // utxo_count: 42567
157
+ // }
158
+ ```
159
+
160
+ ```typescript
161
+ // Récupérer les UTXOs d'une adresse
162
+ const utxos: Utxo[] = await client.getUtxos(address);
163
+ // Réponse:
164
+ // [
165
+ // {
166
+ // address: "04abc123...",
167
+ // amount: "50.00000000",
168
+ // outpoint: { txid: "tx123...", index: 0 }
169
+ // },
170
+ // {
171
+ // address: "04abc123...",
172
+ // amount: "25.50000000",
173
+ // outpoint: { txid: "tx456...", index: 1 }
174
+ // }
175
+ // ]
176
+ ```
177
+
178
+ ```typescript
179
+ // Récupérer la balance d'une adresse
180
+ const balance: string = await client.getBalance(address);
181
+ // Réponse: "75.50000000"
182
+ ```
183
+
184
+ ```typescript
185
+ // Récupérer balance + UTXOs détaillés
186
+ const info: BalanceInfo = await client.getBalanceInfo(address);
187
+ // Réponse:
188
+ // {
189
+ // address: "04abc123...",
190
+ // balance: "75.50000000",
191
+ // utxos: [{ address: "...", amount: "...", outpoint: {...} }, ...]
192
+ // }
193
+ ```
194
+
195
+ ```typescript
196
+ // Récupérer l'historique (Transactions, Mints, Rewards)
197
+ const history = await client.getHistory(address, { limit: 50 });
198
+ // Réponse:
199
+ // {
200
+ // address: "04abc123...",
201
+ // count: 50,
202
+ // items: [
203
+ // { block_id: "...", ts_ms: 1700000000000, payload_type: "Reward", payload: { ... } },
204
+ // { block_id: "...", ts_ms: 1700000050000, payload_type: "TxUtxo", payload: { ... } }
205
+ // ]
206
+ // }
207
+
208
+ // Récupérer l'historique avec déchiffrement automatique des rewards
209
+ // (Nécessite le wallet pour déchiffrer les EncryptedRewards)
210
+ const historyWithDecrypt = await client.getHistory(address, {
211
+ limit: 50,
212
+ decryptionWallet: myWallet
213
+ });
214
+ // Les items "EncryptedReward" déchiffrés apparaîtront comme des "Reward" standards
215
+ ```
216
+
217
+ #### Méthodes d'Écriture (Transactions)
218
+
219
+ ```typescript
220
+ // Envoyer des tokens
221
+ const result = await client.send({
222
+ to: "04destinataire...",
223
+ amount: "100.0",
224
+ wallet: myWallet,
225
+ memo: "Paiement optionnel", // Optionnel
226
+ });
227
+ // Réponse:
228
+ // {
229
+ // status: "inserted", // ou "already_exists"
230
+ // block_id: "7f3a2b1c..."
231
+ // }
232
+ ```
233
+
234
+ ---
235
+
236
+ ### NFT - Non-Fungible Tokens
237
+
238
+ Le SDK supporte les opérations NFT natives du réseau PMS.
239
+
240
+ #### Mint NFT (Standard)
241
+
242
+ La création de NFT est **sécurisée** par le Coordinateur.
243
+
244
+ ```typescript
245
+ // Le server (Coordinateur) signe et chiffre le NFT pour vous.
246
+ const result = await client.mintNft({
247
+ tokenId: "unique-nft-001",
248
+ metadata: {
249
+ name: "Mon NFT",
250
+ description: "Description du NFT",
251
+ uri: "ipfs://QmXxx...",
252
+ nft_type: "art",
253
+ },
254
+ wallet: myWallet, // Votre wallet personnel
255
+ });
256
+ // Réponse:
257
+ // {
258
+ // status: "inserted",
259
+ // token_id: "unique-nft-001",
260
+ // block_id: "a1b2c3d4e5f6..."
261
+ // }
262
+ ```
263
+
264
+ > [!NOTE]
265
+ > Les métadonnées sont automatiquement **chiffrées** par le serveur pour le propriétaire et le Coordinateur.
266
+
267
+ #### Mint Cube (NFT avec Rareté)
268
+
269
+ Les Cubes sont des NFTs spéciaux avec rareté et attributs générés par un backend Authority.
270
+
271
+ ```typescript
272
+ // Mint un cube pour un utilisateur
273
+ const result = await client.mintCube({
274
+ wallet: myWallet,
275
+ generatorUrl: "https://cube-generator.example.com", // Backend Authority
276
+ });
277
+ // Réponse (MintCubeResponse):
278
+ // {
279
+ // status: "inserted",
280
+ // block_id: "9f8e7d6c5b4a...",
281
+ // token_id: "a1b2c3d4e5f6...64chars...",
282
+ // rarity: "Legendary",
283
+ // roll: 75,
284
+ // attributes: {
285
+ // weight: 50.5,
286
+ // size: 30.2,
287
+ // density: 2.5
288
+ // }
289
+ // }
290
+ ```
291
+
292
+ **Raretés possibles :**
293
+
294
+ | Rareté | Probabilité | Cubes sur 10M |
295
+ |--------|-------------|---------------|
296
+ | Unique | 1/1,000,000 | 10 |
297
+ | Legendary | 1/100,000 | 100 |
298
+ | Rare | 1/10,000 | 1,000 |
299
+ | Uncommon | 1/1,000 | 10,000 |
300
+ | Common | 1/100 | 100,000 |
301
+ | Basic | ~99% | ~9,888,890 |
302
+
303
+ #### Burn NFT
304
+
305
+ ```typescript
306
+ // Détruit un NFT (seul le propriétaire peut brûler)
307
+ const result = await client.burnNft({
308
+ tokenId: "nft-to-destroy",
309
+ wallet: ownerWallet,
310
+ });
311
+ // Réponse:
312
+ // {
313
+ // status: "inserted",
314
+ // block_id: "1a2b3c4d5e6f...",
315
+ // refund: { // Uniquement pour les Cubes authentiques
316
+ // amount: "1.23456789",
317
+ // recipient: "04abc123..."
318
+ // }
319
+ // }
320
+ ```
321
+
322
+ > [!TIP]
323
+ > Les Cubes avec une signature Authority valide génèrent un **remboursement automatique** calculé selon leurs attributs.
324
+
325
+ #### Batch Burn (Destruction Multiple)
326
+
327
+ Pour détruire plusieurs NFTs en une seule transaction (économie de frais) :
328
+
329
+ ```typescript
330
+ const result = await client.burnNfts({
331
+ tokenIds: ["token-1", "token-2", "token-3"],
332
+ wallet: ownerWallet,
333
+ });
334
+ // Réponse:
335
+ // {
336
+ // status: "burned",
337
+ // token_id: "batch",
338
+ // token_ids: ["token-1", "token-2", "token-3"],
339
+ // refund: { ... } // Remboursement cumulé
340
+ // }
341
+ ```
342
+
343
+ ---
344
+
345
+ ### API Avancée
346
+
347
+ Pour les cas d'usage avancés (construction manuelle de blocs, chiffrement custom), importez depuis le module `advanced` :
348
+
349
+ ```typescript
350
+ import {
351
+ computeBlockId,
352
+ checkPowBits,
353
+ encryptPayload,
354
+ decryptPayload,
355
+ generateX25519Keypair,
356
+ deriveX25519PublicKey,
357
+ } from "@empereur-rouge/pms-sdk/src/advanced";
358
+
359
+ import type {
360
+ WireBlock,
361
+ PayloadEnvelope,
362
+ TxUtxo,
363
+ } from "@empereur-rouge/pms-sdk/src/advanced";
364
+ ```
365
+
366
+ > [!WARNING]
367
+ > L'API avancée peut changer sans préavis. Préférez l'API publique pour la stabilité.
368
+
369
+ ---
370
+
371
+ ### Utilitaires (API Publique)
372
+
373
+ ```typescript
374
+ import {
375
+ parseAmount,
376
+ formatAmount,
377
+ toHex,
378
+ fromHex,
379
+ } from "@empereur-rouge/pms-sdk";
380
+
381
+ // Convertir les montants
382
+ const sats = parseAmount("10.5"); // -> 1050000000n
383
+ const formatted = formatAmount(sats); // -> "10.50000000"
384
+
385
+ // Conversions hex
386
+ const hex = toHex(new Uint8Array([1, 2, 3]));
387
+ const bytes = fromHex("010203");
388
+ ```
389
+
390
+ ---
391
+
392
+ ## Types TypeScript
393
+
394
+ Tous les types sont exportés et documentés :
395
+
396
+ ```typescript
397
+ import type {
398
+ // Configuration
399
+ PmsClientConfig,
400
+
401
+ // Réponses API
402
+ SubmitResponse,
403
+ BalanceInfo,
404
+ SupplyInfo,
405
+
406
+ // NFT
407
+ NftMetadata,
408
+ MintCubeResponse,
409
+ BurnNftResponse,
410
+ CubeAttributes,
411
+
412
+ // Blocs & Transactions (lecture)
413
+ Block,
414
+ Utxo,
415
+
416
+ // Historique
417
+ WalletHistoryResp,
418
+ HistoryItem,
419
+ } from "@empereur-rouge/pms-sdk";
420
+
421
+ // Types bas niveau (API avancée)
422
+ import type {
423
+ WireBlock,
424
+ PayloadEnvelope,
425
+ TxUtxo,
426
+ OutputRef,
427
+ TxOutput,
428
+ } from "@empereur-rouge/pms-sdk/src/advanced";
429
+ ```
430
+
431
+ ---
432
+
433
+ ## Sécurité
434
+
435
+ ### Coordinateur et Minting
436
+
437
+ En production, seul le **Coordinateur** peut créer de nouveaux NFTs (y compris les Cubes). Cette restriction est appliquée au niveau du backend via la clé `coordinator_pk`.
438
+
439
+ Les NFTs authentiques sont identifiés par le `creator` qui correspond à la clé publique du Coordinateur.
440
+
441
+ ### Chiffrement
442
+
443
+ Le SDK utilise :
444
+ - **secp256k1** pour les signatures (ECDSA, DER-encoded)
445
+ - **X25519** pour l'échange de clés
446
+ - **AES-256-GCM** pour le chiffrement symétrique
447
+
448
+ ### Bonnes Pratiques
449
+
450
+ ```typescript
451
+ // ✅ Stocker le mnemonic de façon sécurisée
452
+ const wallet = PmsWallet.generate();
453
+ // Sauvegarder wallet.mnemonic dans un stockage sécurisé
454
+
455
+ // ✅ Ne jamais exposer la clé privée
456
+ const privateKey = wallet.exportPrivateKey();
457
+ // Ne pas logger ou transmettre cette valeur
458
+
459
+ // ✅ Vérifier les signatures avant d'accepter des données
460
+ const isValid = PmsWallet.verify(message, signature, senderPubKey);
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Racing Pattern
466
+
467
+ Le SDK utilise un "racing pattern" pour la soumission des transactions :
468
+
469
+ 1. Le client maintient une liste de nœuds connus
470
+ 2. Lors de `submitBlock()`, la transaction est envoyée à **tous** les nœuds en parallèle
471
+ 3. La première réponse positive est retournée
472
+ 4. Les autres requêtes sont annulées
473
+
474
+ Cela améliore :
475
+ - La **latence** (premier nœud qui répond)
476
+ - La **fiabilité** (tolérance aux pannes)
477
+ - La **propagation** (le bloc atteint plusieurs nœuds rapidement)
478
+
479
+ ```typescript
480
+ // Désactiver si non souhaité
481
+ const client = new PmsClient({
482
+ nodeUrl: "...",
483
+ enableRacing: false,
484
+ });
485
+ ```
486
+
487
+ ---
488
+
489
+ ## Tests
490
+
491
+ ```bash
492
+ # Lancer les tests
493
+ npm test
494
+
495
+ # Mode watch
496
+ npm run test:watch
497
+
498
+ # Couverture
499
+ npm run test:coverage
500
+ ```
501
+
502
+ ---
503
+
504
+ ## Licence
505
+
506
+ MIT © PMS Team