@neuraiproject/neurai-key 2.8.3 → 2.8.5

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.
@@ -0,0 +1,543 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Neurai-Key Verifier</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
16
+ background: #f5f5f5;
17
+ min-height: 100vh;
18
+ padding: 20px;
19
+ }
20
+
21
+ .container {
22
+ max-width: 900px;
23
+ margin: 0 auto;
24
+ background: white;
25
+ border-radius: 8px;
26
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
27
+ padding: 40px;
28
+ }
29
+
30
+ h1 {
31
+ color: #2c3e50;
32
+ text-align: center;
33
+ margin-bottom: 8px;
34
+ font-size: 2em;
35
+ font-weight: 600;
36
+ }
37
+
38
+ .subtitle {
39
+ text-align: center;
40
+ color: #7f8c8d;
41
+ margin-bottom: 30px;
42
+ font-size: 0.95em;
43
+ }
44
+
45
+ .input-section {
46
+ background: #fafafa;
47
+ padding: 20px;
48
+ border-radius: 6px;
49
+ margin-bottom: 25px;
50
+ border: 1px solid #e0e0e0;
51
+ }
52
+
53
+ label {
54
+ display: block;
55
+ color: #2c3e50;
56
+ font-weight: 500;
57
+ margin-bottom: 8px;
58
+ font-size: 0.95em;
59
+ }
60
+
61
+ textarea {
62
+ width: 100%;
63
+ padding: 12px;
64
+ border: 1px solid #d0d0d0;
65
+ border-radius: 4px;
66
+ font-size: 14px;
67
+ font-family: 'Courier New', monospace;
68
+ resize: vertical;
69
+ min-height: 100px;
70
+ transition: border-color 0.2s;
71
+ }
72
+
73
+ textarea:focus {
74
+ outline: none;
75
+ border-color: #3498db;
76
+ }
77
+
78
+ .network-selector {
79
+ margin: 15px 0;
80
+ }
81
+
82
+ select {
83
+ width: 100%;
84
+ padding: 10px 12px;
85
+ border: 1px solid #d0d0d0;
86
+ border-radius: 4px;
87
+ font-size: 14px;
88
+ background: white;
89
+ cursor: pointer;
90
+ transition: border-color 0.2s;
91
+ }
92
+
93
+ select:focus {
94
+ outline: none;
95
+ border-color: #3498db;
96
+ }
97
+
98
+ .button-group {
99
+ display: flex;
100
+ gap: 10px;
101
+ margin-top: 20px;
102
+ }
103
+
104
+ button {
105
+ flex: 1;
106
+ padding: 12px 24px;
107
+ font-size: 14px;
108
+ font-weight: 500;
109
+ border: none;
110
+ border-radius: 4px;
111
+ cursor: pointer;
112
+ transition: all 0.2s;
113
+ }
114
+
115
+ .btn-primary {
116
+ background: #3498db;
117
+ color: white;
118
+ }
119
+
120
+ .btn-primary:hover {
121
+ background: #2980b9;
122
+ }
123
+
124
+ .btn-secondary {
125
+ background: #95a5a6;
126
+ color: white;
127
+ }
128
+
129
+ .btn-secondary:hover {
130
+ background: #7f8c8d;
131
+ }
132
+
133
+ .btn-generate {
134
+ background: #27ae60;
135
+ color: white;
136
+ }
137
+
138
+ .btn-generate:hover {
139
+ background: #229954;
140
+ }
141
+
142
+ .results {
143
+ margin-top: 30px;
144
+ }
145
+
146
+ .address-card {
147
+ background: #fafafa;
148
+ padding: 15px;
149
+ border-radius: 4px;
150
+ margin-bottom: 15px;
151
+ border-left: 3px solid #3498db;
152
+ border: 1px solid #e0e0e0;
153
+ border-left: 3px solid #3498db;
154
+ }
155
+
156
+ .address-card:hover {
157
+ background: #f5f5f5;
158
+ }
159
+
160
+ .address-header {
161
+ font-size: 1em;
162
+ font-weight: 600;
163
+ color: #2c3e50;
164
+ margin-bottom: 12px;
165
+ display: flex;
166
+ justify-content: space-between;
167
+ align-items: center;
168
+ }
169
+
170
+ .address-type {
171
+ font-size: 0.75em;
172
+ background: #3498db;
173
+ color: white;
174
+ padding: 4px 8px;
175
+ border-radius: 3px;
176
+ font-weight: 500;
177
+ }
178
+
179
+ .address-info {
180
+ margin: 10px 0;
181
+ display: flex;
182
+ align-items: center;
183
+ gap: 10px;
184
+ }
185
+
186
+ .info-label {
187
+ font-weight: 600;
188
+ color: #555;
189
+ display: inline-block;
190
+ width: 120px;
191
+ font-size: 0.9em;
192
+ flex-shrink: 0;
193
+ }
194
+
195
+ .info-value {
196
+ font-family: 'Courier New', monospace;
197
+ color: #2c3e50;
198
+ word-break: break-all;
199
+ background: white;
200
+ padding: 8px 10px;
201
+ border-radius: 3px;
202
+ font-size: 0.85em;
203
+ border: 1px solid #e0e0e0;
204
+ flex: 1 1 auto;
205
+ min-width: 0;
206
+ overflow: hidden;
207
+ }
208
+
209
+ .error {
210
+ background: #fee;
211
+ color: #c53030;
212
+ padding: 12px;
213
+ border-radius: 4px;
214
+ margin: 15px 0;
215
+ border-left: 3px solid #fc8181;
216
+ font-size: 0.9em;
217
+ }
218
+
219
+ .success {
220
+ background: #f0fff4;
221
+ color: #22543d;
222
+ padding: 12px;
223
+ border-radius: 4px;
224
+ margin: 15px 0;
225
+ border-left: 3px solid #68d391;
226
+ font-size: 0.9em;
227
+ }
228
+
229
+ .info {
230
+ background: #e6f7ff;
231
+ color: #003a70;
232
+ padding: 12px;
233
+ border-radius: 4px;
234
+ margin: 15px 0;
235
+ border-left: 3px solid #69c0ff;
236
+ font-size: 0.9em;
237
+ }
238
+
239
+ .loading {
240
+ text-align: center;
241
+ padding: 30px;
242
+ color: #7f8c8d;
243
+ font-size: 1em;
244
+ }
245
+
246
+ .hidden {
247
+ display: none;
248
+ }
249
+
250
+ .copy-btn {
251
+ background: transparent;
252
+ color: #555;
253
+ border: none;
254
+ padding: 6px 8px;
255
+ border-radius: 3px;
256
+ cursor: pointer;
257
+ font-size: 1.2em;
258
+ transition: all 0.2s;
259
+ flex: 0 0 auto;
260
+ width: auto;
261
+ line-height: 1;
262
+ display: inline-flex;
263
+ align-items: center;
264
+ justify-content: center;
265
+ }
266
+
267
+ .copy-btn:hover {
268
+ color: #27ae60;
269
+ transform: scale(1.1);
270
+ }
271
+
272
+ @media (max-width: 768px) {
273
+ .container {
274
+ padding: 20px;
275
+ }
276
+
277
+ h1 {
278
+ font-size: 1.8em;
279
+ }
280
+
281
+ .button-group {
282
+ flex-direction: column;
283
+ }
284
+
285
+ .info-label {
286
+ display: block;
287
+ margin-bottom: 5px;
288
+ }
289
+
290
+ .info-value {
291
+ display: block;
292
+ max-width: 100%;
293
+ }
294
+ }
295
+ </style>
296
+ </head>
297
+ <body>
298
+ <div class="container">
299
+ <h1>Neurai Key Verifier</h1>
300
+ <p class="subtitle">Generate and verify addresses from your mnemonic (12 or 24 words)</p>
301
+
302
+ <div class="input-section">
303
+ <label for="mnemonic">Mnemonic Phrase (12 or 24 words):</label>
304
+ <textarea
305
+ id="mnemonic"
306
+ placeholder="Enter your mnemonic phrase here, separated by spaces. Example: word1 word2 word3..."
307
+ ></textarea>
308
+
309
+ <div class="network-selector">
310
+ <label for="network">Network:</label>
311
+ <select id="network">
312
+ <option value="xna">Neurai Mainnet (XNA)</option>
313
+ <option value="xna-test">Neurai Testnet (XNA-TEST)</option>
314
+ </select>
315
+ </div>
316
+
317
+ <div class="network-selector">
318
+ <label for="passphrase">Passphrase (Optional - BIP39 25th word):</label>
319
+ <input
320
+ type="text"
321
+ id="passphrase"
322
+ placeholder="Enter optional passphrase for extra security"
323
+ style="width: 100%; padding: 12px; border: 1px solid #d0d0d0; border-radius: 4px; font-size: 14px;"
324
+ />
325
+ <small style="color: #7f8c8d; font-size: 0.85em; display: block; margin-top: 5px;">
326
+ ⚠️ Warning: Different passphrases create different wallets. If you use a passphrase, you'll need both the mnemonic AND passphrase to recover your wallet.
327
+ </small>
328
+ </div>
329
+
330
+ <div class="button-group">
331
+ <button class="btn-primary" onclick="verificarYGenerar()">
332
+ Verify and Generate Addresses
333
+ </button>
334
+ <button class="btn-generate" onclick="generarNuevoMnemonic()">
335
+ Generate New Mnemonic
336
+ </button>
337
+ <button class="btn-secondary" onclick="limpiar()">
338
+ Clear
339
+ </button>
340
+ </div>
341
+ </div>
342
+
343
+ <div id="message"></div>
344
+ <div id="results" class="results"></div>
345
+ </div>
346
+
347
+ <script src="./NeuraiKey.js"></script>
348
+ <script>
349
+ function mostrarMensaje(mensaje, tipo) {
350
+ const messageDiv = document.getElementById('message');
351
+ messageDiv.className = tipo;
352
+ messageDiv.innerHTML = mensaje;
353
+ messageDiv.classList.remove('hidden');
354
+ }
355
+
356
+ function ocultarMensaje() {
357
+ const messageDiv = document.getElementById('message');
358
+ messageDiv.classList.add('hidden');
359
+ }
360
+
361
+ function limpiar() {
362
+ document.getElementById('mnemonic').value = '';
363
+ document.getElementById('passphrase').value = '';
364
+ document.getElementById('results').innerHTML = '';
365
+ ocultarMensaje();
366
+ }
367
+
368
+ function generarNuevoMnemonic() {
369
+ try {
370
+ const mnemonic = NeuraiKey.generateMnemonic();
371
+ document.getElementById('mnemonic').value = mnemonic;
372
+ mostrarMensaje('New mnemonic generated. Save it in a safe place!', 'success');
373
+ document.getElementById('results').innerHTML = '';
374
+ } catch (error) {
375
+ mostrarMensaje(`Error generating mnemonic: ${error.message}`, 'error');
376
+ }
377
+ }
378
+
379
+ function copiarTexto(texto, boton) {
380
+ navigator.clipboard.writeText(texto).then(() => {
381
+ const textoOriginal = boton.textContent;
382
+ boton.textContent = '✓';
383
+ setTimeout(() => {
384
+ boton.textContent = textoOriginal;
385
+ }, 2000);
386
+ }).catch(err => {
387
+ alert('Error copying: ' + err);
388
+ });
389
+ }
390
+
391
+ function verificarYGenerar() {
392
+ ocultarMensaje();
393
+ const resultsDiv = document.getElementById('results');
394
+ resultsDiv.innerHTML = '<div class="loading">Generating addresses...</div>';
395
+
396
+ setTimeout(() => {
397
+ try {
398
+ const mnemonic = document.getElementById('mnemonic').value.trim();
399
+ const network = document.getElementById('network').value;
400
+ const passphrase = document.getElementById('passphrase').value; // Obtener passphrase
401
+
402
+ if (!mnemonic) {
403
+ mostrarMensaje('Please enter a mnemonic phrase', 'error');
404
+ resultsDiv.innerHTML = '';
405
+ return;
406
+ }
407
+
408
+ // Validar que sea un mnemonic válido
409
+ const palabras = mnemonic.split(/\s+/).filter(p => p.length > 0);
410
+ if (palabras.length !== 12 && palabras.length !== 24) {
411
+ mostrarMensaje('Mnemonic must have exactly 12 or 24 words. Words found: ' + palabras.length, 'error');
412
+ resultsDiv.innerHTML = '';
413
+ return;
414
+ }
415
+
416
+ // Validar el mnemonic con bip39
417
+ if (!NeuraiKey.validateMnemonic || typeof NeuraiKey.validateMnemonic !== 'function') {
418
+ // Si no existe validateMnemonic, intentar generar una dirección para validar
419
+ try {
420
+ NeuraiKey.getAddressPair(network, mnemonic, 0, 0, passphrase);
421
+ } catch (e) {
422
+ mostrarMensaje('Invalid mnemonic: ' + e.message, 'error');
423
+ resultsDiv.innerHTML = '';
424
+ return;
425
+ }
426
+ }
427
+
428
+ const passphraseMsg = passphrase ? ' with passphrase' : '';
429
+ mostrarMensaje(`Valid mnemonic (${palabras.length} words). Generating addresses on ${network}${passphraseMsg}...`, 'success');
430
+
431
+ let html = '';
432
+
433
+ // Generar las primeras 5 direcciones
434
+ for (let i = 0; i < 5; i++) {
435
+ const addressPair = NeuraiKey.getAddressPair(network, mnemonic, 0, i, passphrase); // Usar passphrase
436
+
437
+ // Dirección Externa (para recibir)
438
+ html += `
439
+ <div class="address-card">
440
+ <div class="address-header">
441
+ <span>Address #${i + 1} - External (Receive)</span>
442
+ <span class="address-type">EXTERNAL</span>
443
+ </div>
444
+ <div class="address-info">
445
+ <span class="info-label">Address:</span>
446
+ <span class="info-value">${addressPair.external.address}</span>
447
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.external.address}', this)">📋</button>
448
+ </div>
449
+ <div class="address-info">
450
+ <span class="info-label">Path:</span>
451
+ <span class="info-value">${addressPair.external.path}</span>
452
+ </div>
453
+ <div class="address-info">
454
+ <span class="info-label">Public Key:</span>
455
+ <span class="info-value">${addressPair.external.publicKey}</span>
456
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.external.publicKey}', this)">📋</button>
457
+ </div>
458
+ <div class="address-info">
459
+ <span class="info-label">Private Key:</span>
460
+ <span class="info-value">${addressPair.external.privateKey}</span>
461
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.external.privateKey}', this)">📋</button>
462
+ </div>
463
+ <div class="address-info">
464
+ <span class="info-label">WIF:</span>
465
+ <span class="info-value">${addressPair.external.WIF}</span>
466
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.external.WIF}', this)">📋</button>
467
+ </div>
468
+ </div>
469
+
470
+ <div class="address-card">
471
+ <div class="address-header">
472
+ <span>Address #${i + 1} - Internal (Change)</span>
473
+ <span class="address-type" style="background: #f5576c;">INTERNAL</span>
474
+ </div>
475
+ <div class="address-info">
476
+ <span class="info-label">Address:</span>
477
+ <span class="info-value">${addressPair.internal.address}</span>
478
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.internal.address}', this)">📋</button>
479
+ </div>
480
+ <div class="address-info">
481
+ <span class="info-label">Path:</span>
482
+ <span class="info-value">${addressPair.internal.path}</span>
483
+ </div>
484
+ <div class="address-info">
485
+ <span class="info-label">Public Key:</span>
486
+ <span class="info-value">${addressPair.internal.publicKey}</span>
487
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.internal.publicKey}', this)">📋</button>
488
+ </div>
489
+ <div class="address-info">
490
+ <span class="info-label">Private Key:</span>
491
+ <span class="info-value">${addressPair.internal.privateKey}</span>
492
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.internal.privateKey}', this)">📋</button>
493
+ </div>
494
+ <div class="address-info">
495
+ <span class="info-label">WIF:</span>
496
+ <span class="info-value">${addressPair.internal.WIF}</span>
497
+ <button class="copy-btn" onclick="copiarTexto('${addressPair.internal.WIF}', this)">📋</button>
498
+ </div>
499
+ </div>
500
+ `;
501
+ }
502
+
503
+ resultsDiv.innerHTML = html;
504
+
505
+ // Agregar mensaje informativo
506
+ const infoDiv = document.createElement('div');
507
+ infoDiv.className = 'info';
508
+ const passphraseInfo = passphrase ? '<br>- 🔐 <strong>Passphrase used:</strong> Remember you need BOTH mnemonic and passphrase to recover these addresses!' : '';
509
+ infoDiv.innerHTML = `
510
+ <strong>Information:</strong><br>
511
+ - The first 5 addresses (external and internal) have been generated<br>
512
+ - <strong>External</strong> addresses are used to receive payments<br>
513
+ - <strong>Internal</strong> addresses are used as change addresses<br>
514
+ - Each pair follows the BIP44 standard with path m/44'/175'/0'/change/index<br>
515
+ - Public keys can be converted back into addresses with <code>NeuraiKey.publicKeyToAddress</code>${passphraseInfo}
516
+ `;
517
+ resultsDiv.appendChild(infoDiv);
518
+
519
+ } catch (error) {
520
+ mostrarMensaje(`Error: ${error.message}`, 'error');
521
+ resultsDiv.innerHTML = '';
522
+ }
523
+ }, 100);
524
+ }
525
+
526
+ // Permitir verificar con Enter
527
+ document.getElementById('mnemonic').addEventListener('keypress', function(e) {
528
+ if (e.key === 'Enter' && !e.shiftKey) {
529
+ e.preventDefault();
530
+ verificarYGenerar();
531
+ }
532
+ });
533
+
534
+ // También permitir verificar con Enter en el campo de passphrase
535
+ document.getElementById('passphrase').addEventListener('keypress', function(e) {
536
+ if (e.key === 'Enter') {
537
+ e.preventDefault();
538
+ verificarYGenerar();
539
+ }
540
+ });
541
+ </script>
542
+ </body>
543
+ </html>
package/test.js CHANGED
@@ -7,49 +7,94 @@ test("Random mnemonic should contain 12 words", () => {
7
7
 
8
8
  test("Validate address on main-net", () => {
9
9
  const network = "xna";
10
- const mnemonic =
11
- "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
10
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
12
11
  const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
13
- expect(address.external.address).toBe("RKbP9SMo2KTKWsiTrEDhTWPuaTwfuPiN8G");
12
+ expect(address.external.address).toBe("NLdcSXGQvCVf2RTKhx7GZom34f1JADhBTp");
14
13
  });
15
14
 
16
15
  test("Validate address on test-net", () => {
17
16
  const network = "xna-test";
18
- const mnemonic =
19
- "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
17
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
20
18
  const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
21
- expect(address.external.address).toBe("n1nUspcdAaDAMfx2ksZJ5cDa7UKVEGstrX");
19
+ expect(address.external.address).toBe("tPXGaMRNwZuV1UKSrD9gABPscrJWUmedQ9");
20
+ });
21
+
22
+ test("Validate address with passphrase on main-net", () => {
23
+ const network = "xna";
24
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
25
+ const passphrase = "my secret passphrase";
26
+ const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1, passphrase);
27
+ // With passphrase, the address should be different from the one without passphrase
28
+ expect(address.external.address).not.toBe("NLdcSXGQvCVf2RTKhx7GZom34f1JADhBTp");
29
+ // Verify it generates consistently with the same passphrase
30
+ const address2 = NeuraiKey.getAddressPair(network, mnemonic, 0, 1, passphrase);
31
+ expect(address.external.address).toBe(address2.external.address);
32
+ });
33
+
34
+ test("Different passphrases generate different addresses", () => {
35
+ const network = "xna";
36
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
37
+ const passphrase1 = "passphrase1";
38
+ const passphrase2 = "passphrase2";
39
+
40
+ const address1 = NeuraiKey.getAddressPair(network, mnemonic, 0, 0, passphrase1);
41
+ const address2 = NeuraiKey.getAddressPair(network, mnemonic, 0, 0, passphrase2);
42
+
43
+ expect(address1.external.address).not.toBe(address2.external.address);
44
+ });
45
+
46
+ test("Empty passphrase equals no passphrase", () => {
47
+ const network = "xna";
48
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
49
+
50
+ const addressWithEmpty = NeuraiKey.getAddressPair(network, mnemonic, 0, 1, "");
51
+ const addressWithoutPassphrase = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
52
+
53
+ expect(addressWithEmpty.external.address).toBe(addressWithoutPassphrase.external.address);
54
+ expect(addressWithEmpty.external.address).toBe("NLdcSXGQvCVf2RTKhx7GZom34f1JADhBTp");
22
55
  });
23
56
 
24
57
  test("Validate Wallet Import Format (WIF) main-net ", () => {
25
58
  const network = "xna";
26
- const mnemonic =
27
- "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
59
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
28
60
  const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
29
61
 
30
- expect(address.internal.address).toBe("RLnvUoy29k3QiQgtR6PL416rSNfHTuwhyU");
31
- expect(address.external.WIF).toBe(
32
- "KyWuYcev1hJ7YJZTjWx8coXNRm4jRbMEhgVVVC8vDcTaKRCMASUE"
62
+ expect(address.internal.address).toBe("NQM5zP6jkwDgCZ2UQiUicW4e3YcWc4NY4S");
63
+ expect(address.external.WIF).toBe("KwWavecys1Qskgzwsyv6CNeTospWkvMeLzx3dLqeV4xAJEMXF8Qq");
64
+ });
65
+
66
+ test("Convert external public key to main-net address", () => {
67
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
68
+ const pair = NeuraiKey.getAddressPair("xna", mnemonic, 0, 1);
69
+
70
+ expect(NeuraiKey.publicKeyToAddress("xna", pair.external.publicKey)).toBe(
71
+ pair.external.address
33
72
  );
34
73
  });
35
74
 
36
75
  test("Validate Wallet Import Format (WIF) test-net ", () => {
37
76
  const network = "xna-test";
38
- const mnemonic =
39
- "orphan resemble brain dwarf bus fancy horn among cricket logic duty crater";
77
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
40
78
  const address = NeuraiKey.getAddressPair(network, mnemonic, 0, 1);
41
79
 
42
- expect(address.external.WIF).toBe(
43
- "cPchRRmzZXtPeFLHfrh8qcwaRaziJCS4gcAMBVVQh1EiehNyBtKB"
80
+ expect(address.external.WIF).toBe("cSfwLzc9DNj4PdzyGK1sAZzxNwih2HaezMrT8w4MXyhf8qhaHJiE");
81
+ });
82
+
83
+ test("Convert external public key to test-net address", () => {
84
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
85
+ const pair = NeuraiKey.getAddressPair("xna-test", mnemonic, 0, 1);
86
+
87
+ expect(NeuraiKey.publicKeyToAddress("xna-test", pair.external.publicKey)).toBe(
88
+ pair.external.address
44
89
  );
45
90
  });
46
91
 
47
92
  test("Validate get public address from Wallet Import Format (WIF) main-net ", () => {
48
93
  const network = "xna";
49
- const WIF = "KyWuYcev1hJ7YJZTjWx8coXNRm4jRbMEhgVVVC8vDcTaKRCMASUE";
94
+ const WIF = "KwWavecys1Qskgzwsyv6CNeTospWkvMeLzx3dLqeV4xAJEMXF8Qq";
50
95
  const addressObject = NeuraiKey.getAddressByWIF(network, WIF);
51
96
 
52
- expect(addressObject.address).toBe("RKbP9SMo2KTKWsiTrEDhTWPuaTwfuPiN8G");
97
+ expect(addressObject.address).toBe("NLdcSXGQvCVf2RTKhx7GZom34f1JADhBTp");
53
98
  });
54
99
 
55
100
  test("Valid bytes to mnemonic", () => {
@@ -73,14 +118,14 @@ test("Non valid bytes to mnemonic should fail", () => {
73
118
  describe("Validate diff languages", () => {
74
119
  it("Should accept spanish mnemonic", () => {
75
120
  const m =
76
- "velero nuera pepino reír barro reforma negar rumbo atento separar pesa puma";
121
+ "velero nuera pepino reír barro reforma negar rumbo atento separar pesa puma";
77
122
  const valid = NeuraiKey.isMnemonicValid(m);
78
123
  expect(valid).toBe(true);
79
124
  });
80
125
 
81
126
  it("Should accept French mnemonic", () => {
82
127
  const m =
83
- "vaseux mixte ozone quiétude besogne punaise membre réussir avarice samedi pantalon poney";
128
+ "vaseux mixte ozone quiétude besogne punaise membre réussir avarice samedi pantalon poney";
84
129
  const valid = NeuraiKey.isMnemonicValid(m);
85
130
  expect(valid).toBe(true);
86
131
  });
@@ -123,4 +168,4 @@ describe("generateAddress", () => {
123
168
  });
124
169
 
125
170
  // Add more tests if needed to cover different scenarios
126
- });
171
+ });
package/types.ts CHANGED
@@ -2,6 +2,7 @@ export interface IAddressObject {
2
2
  address: string;
3
3
  mnemonic?: string;
4
4
  path: string;
5
+ publicKey: string;
5
6
  privateKey: string;
6
7
  WIF: string;
7
8
  }