@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 +21 -0
- package/README.md +506 -0
- package/dist/index.cjs +1062 -0
- package/dist/index.d.cts +851 -0
- package/dist/index.d.ts +851 -0
- package/dist/index.js +1028 -0
- package/package.json +71 -0
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
|