@metamask/eth-hd-keyring 8.0.0 → 9.0.1

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/test/index.js DELETED
@@ -1,960 +0,0 @@
1
- const {
2
- TransactionFactory,
3
- Transaction: EthereumTx,
4
- } = require('@ethereumjs/tx');
5
- const {
6
- isValidAddress,
7
- bufferToHex,
8
- toBuffer,
9
- ecrecover,
10
- pubToAddress,
11
- } = require('@ethereumjs/util');
12
- const oldMMForkBIP39 = require('@metamask/bip39');
13
- const OldHdKeyring = require('@metamask/eth-hd-keyring');
14
- const {
15
- normalize,
16
- personalSign,
17
- recoverPersonalSignature,
18
- recoverTypedSignature,
19
- signTypedData,
20
- SignTypedDataVersion,
21
- encrypt,
22
- } = require('@metamask/eth-sig-util');
23
- const { wordlist } = require('@metamask/scure-bip39/dist/wordlists/english');
24
- const { keccak256 } = require('ethereum-cryptography/keccak');
25
-
26
- const HdKeyring = require('..');
27
-
28
- // Sample account:
29
- const privKeyHex =
30
- 'b8a9c05beeedb25df85f8d641538cbffedf67216048de9c678ee26260eb91952';
31
-
32
- const sampleMnemonic =
33
- 'finish oppose decorate face calm tragic certain desk hour urge dinosaur mango';
34
- const firstAcct = '0x1c96099350f13d558464ec79b9be4445aa0ef579';
35
- const secondAcct = '0x1b00aed43a693f3a957f9feb5cc08afa031e37a0';
36
-
37
- const notKeyringAddress = '0xbD20F6F5F1616947a39E11926E78ec94817B3931';
38
-
39
- describe('hd-keyring', () => {
40
- describe('compare old bip39 implementation with new', () => {
41
- it('should derive the same accounts from the same mnemonics', async () => {
42
- const mnemonics = [];
43
- for (let i = 0; i < 99; i++) {
44
- mnemonics.push(oldMMForkBIP39.generateMnemonic());
45
- }
46
-
47
- await Promise.all(
48
- mnemonics.map(async (mnemonic) => {
49
- const newHDKeyring = new HdKeyring({ mnemonic, numberOfAccounts: 3 });
50
- const oldHDKeyring = new OldHdKeyring({
51
- mnemonic,
52
- numberOfAccounts: 3,
53
- });
54
- const newAccounts = await newHDKeyring.getAccounts();
55
- const oldAccounts = await oldHDKeyring.getAccounts();
56
- await expect(newAccounts[0]).toStrictEqual(oldAccounts[0]);
57
-
58
- await expect(newAccounts[1]).toStrictEqual(oldAccounts[1]);
59
-
60
- await expect(newAccounts[2]).toStrictEqual(oldAccounts[2]);
61
- }),
62
- );
63
- });
64
- });
65
-
66
- describe('constructor', () => {
67
- it('constructs with a typeof string mnemonic', async () => {
68
- const keyring = new HdKeyring({
69
- mnemonic: sampleMnemonic,
70
- numberOfAccounts: 2,
71
- });
72
-
73
- const accounts = await keyring.getAccounts();
74
- expect(accounts[0]).toStrictEqual(firstAcct);
75
- expect(accounts[1]).toStrictEqual(secondAcct);
76
- });
77
-
78
- it('constructs with a typeof buffer mnemonic', async () => {
79
- const keyring = new HdKeyring({
80
- mnemonic: Buffer.from(sampleMnemonic, 'utf8'),
81
- numberOfAccounts: 2,
82
- });
83
-
84
- const accounts = await keyring.getAccounts();
85
- expect(accounts[0]).toStrictEqual(firstAcct);
86
- expect(accounts[1]).toStrictEqual(secondAcct);
87
- });
88
-
89
- it('constructs with a typeof Uint8Array mnemonic', async () => {
90
- const indices = sampleMnemonic
91
- .split(' ')
92
- .map((word) => wordlist.indexOf(word));
93
- const uInt8ArrayOfMnemonic = new Uint8Array(
94
- new Uint16Array(indices).buffer,
95
- );
96
- const keyring = new HdKeyring({
97
- mnemonic: uInt8ArrayOfMnemonic,
98
- numberOfAccounts: 2,
99
- });
100
-
101
- const accounts = await keyring.getAccounts();
102
- expect(accounts[0]).toStrictEqual(firstAcct);
103
- expect(accounts[1]).toStrictEqual(secondAcct);
104
- });
105
-
106
- it('throws on invalid mnemonic', () => {
107
- expect(
108
- () =>
109
- new HdKeyring({
110
- mnemonic: 'abc xyz',
111
- numberOfAccounts: 2,
112
- }),
113
- ).toThrow('Eth-Hd-Keyring: Invalid secret recovery phrase provided');
114
- });
115
-
116
- it('throws when numberOfAccounts is passed with no mnemonic', () => {
117
- expect(
118
- () =>
119
- new HdKeyring({
120
- numberOfAccounts: 2,
121
- }),
122
- ).toThrow(
123
- 'Eth-Hd-Keyring: Deserialize method cannot be called with an opts value for numberOfAccounts and no menmonic',
124
- );
125
- });
126
- });
127
-
128
- describe('re-initialization protection', () => {
129
- const alreadyProvidedError =
130
- 'Eth-Hd-Keyring: Secret recovery phrase already provided';
131
- it('double generateRandomMnemonic', () => {
132
- const keyring = new HdKeyring();
133
- keyring.generateRandomMnemonic();
134
- expect(() => {
135
- keyring.generateRandomMnemonic();
136
- }).toThrow(alreadyProvidedError);
137
- });
138
-
139
- it('constructor + generateRandomMnemonic', () => {
140
- const keyring = new HdKeyring({
141
- mnemonic: sampleMnemonic,
142
- numberOfAccounts: 2,
143
- });
144
-
145
- expect(() => {
146
- keyring.generateRandomMnemonic();
147
- }).toThrow(alreadyProvidedError);
148
- });
149
-
150
- it('constructor + deserialize', () => {
151
- const keyring = new HdKeyring({
152
- mnemonic: sampleMnemonic,
153
- numberOfAccounts: 2,
154
- });
155
-
156
- expect(() => {
157
- keyring.deserialize({
158
- mnemonic: sampleMnemonic,
159
- numberOfAccounts: 1,
160
- });
161
- }).toThrow(alreadyProvidedError);
162
- });
163
- });
164
-
165
- describe('Keyring.type', () => {
166
- it('is a class property that returns the type string.', () => {
167
- const { type } = HdKeyring;
168
- expect(typeof type).toBe('string');
169
- });
170
- });
171
-
172
- describe('#type', () => {
173
- it('returns the correct value', () => {
174
- const keyring = new HdKeyring();
175
-
176
- const { type } = keyring;
177
- const correct = HdKeyring.type;
178
- expect(type).toStrictEqual(correct);
179
- });
180
- });
181
-
182
- describe('#serialize mnemonic.', () => {
183
- it('serializes the mnemonic in the same format as previous version (an array of utf8 encoded bytes)', async () => {
184
- const keyring = new HdKeyring({
185
- mnemonic: sampleMnemonic,
186
- });
187
- // uses previous version of eth-hd-keyring to ensure backwards compatibility
188
- const oldHDKeyring = new OldHdKeyring({ mnemonic: sampleMnemonic });
189
- const { mnemonic: oldKeyringSerializedMnemonic } =
190
- await oldHDKeyring.serialize();
191
-
192
- const output = await keyring.serialize();
193
- expect(output.mnemonic).toStrictEqual(oldKeyringSerializedMnemonic);
194
- });
195
-
196
- it('serializes mnemonic passed in as a string to an array of utf8 encoded bytes', async () => {
197
- const keyring = new HdKeyring({
198
- mnemonic: sampleMnemonic,
199
- });
200
- const output = await keyring.serialize();
201
- // this Buffer.from(...).toString() is the method of converting from an array of utf8 encoded bytes back to a string
202
- const mnemonicAsString = Buffer.from(output.mnemonic).toString();
203
- expect(mnemonicAsString).toStrictEqual(sampleMnemonic);
204
- });
205
-
206
- it('serializes mnemonic passed in as a an array of utf8 encoded bytes in the same format', async () => {
207
- const uint8Array = new TextEncoder('utf-8').encode(sampleMnemonic);
208
- const mnemonicAsArrayOfUtf8EncodedBytes = Array.from(uint8Array);
209
- const keyring = new HdKeyring({
210
- mnemonic: mnemonicAsArrayOfUtf8EncodedBytes,
211
- });
212
-
213
- const output = await keyring.serialize();
214
- // this Buffer.from(...).toString() is the method of converting from an array of utf8 encoded bytes back to a string
215
- const mnemonicAsString = Buffer.from(output.mnemonic).toString();
216
- expect(mnemonicAsString).toStrictEqual(sampleMnemonic);
217
- });
218
- });
219
-
220
- describe('#deserialize a private key', () => {
221
- it('serializes what it deserializes', async () => {
222
- const keyring = new HdKeyring();
223
- await keyring.deserialize({
224
- mnemonic: sampleMnemonic,
225
- numberOfAccounts: 1,
226
- });
227
- const accountsFirstCheck = await keyring.getAccounts();
228
-
229
- expect(accountsFirstCheck).toHaveLength(1);
230
- await keyring.addAccounts(1);
231
- const accountsSecondCheck = await keyring.getAccounts();
232
- expect(accountsSecondCheck[0]).toStrictEqual(firstAcct);
233
- expect(accountsSecondCheck[1]).toStrictEqual(secondAcct);
234
- expect(accountsSecondCheck).toHaveLength(2);
235
- const serialized = await keyring.serialize();
236
- expect(Buffer.from(serialized.mnemonic).toString()).toStrictEqual(
237
- sampleMnemonic,
238
- );
239
- });
240
- });
241
-
242
- describe('#addAccounts', () => {
243
- describe('with no arguments', () => {
244
- it('creates a single wallet', async () => {
245
- const keyring = new HdKeyring();
246
- keyring.generateRandomMnemonic();
247
- await keyring.addAccounts();
248
- const accounts = await keyring.getAccounts();
249
- expect(accounts).toHaveLength(1);
250
- });
251
-
252
- it('throws an error when no SRP has been generated yet', async () => {
253
- const keyring = new HdKeyring();
254
- expect(() => keyring.addAccounts()).toThrow(
255
- 'Eth-Hd-Keyring: No secret recovery phrase provided',
256
- );
257
- });
258
- });
259
-
260
- describe('with a numeric argument', () => {
261
- it('creates that number of wallets', async () => {
262
- const keyring = new HdKeyring();
263
- keyring.generateRandomMnemonic();
264
- await keyring.addAccounts(3);
265
- const accounts = await keyring.getAccounts();
266
- expect(accounts).toHaveLength(3);
267
- });
268
- });
269
- });
270
-
271
- describe('#signPersonalMessage', () => {
272
- it('returns the expected value', async () => {
273
- const keyring = new HdKeyring();
274
-
275
- const address = firstAcct;
276
- const message = '0x68656c6c6f20776f726c64';
277
-
278
- await keyring.deserialize({
279
- mnemonic: sampleMnemonic,
280
- numberOfAccounts: 1,
281
- });
282
- const signature = await keyring.signPersonalMessage(address, message);
283
- expect(signature).not.toBe(message);
284
-
285
- const restored = recoverPersonalSignature({
286
- data: message,
287
- signature,
288
- });
289
-
290
- expect(restored).toStrictEqual(normalize(address));
291
- });
292
- });
293
-
294
- describe('#signTypedData', () => {
295
- it('can recover a basic signature', async () => {
296
- const keyring = new HdKeyring();
297
- Buffer.from(privKeyHex, 'hex');
298
- const typedData = [
299
- {
300
- type: 'string',
301
- name: 'message',
302
- value: 'Hi, Alice!',
303
- },
304
- ];
305
- keyring.generateRandomMnemonic();
306
- await keyring.addAccounts(1);
307
- const addresses = await keyring.getAccounts();
308
- const address = addresses[0];
309
- const signature = await keyring.signTypedData(address, typedData);
310
- const restored = recoverTypedSignature({
311
- data: typedData,
312
- signature,
313
- version: SignTypedDataVersion.V1,
314
- });
315
- expect(restored).toStrictEqual(address);
316
- });
317
- });
318
-
319
- describe('#signTypedData_v1', () => {
320
- const typedData = [
321
- {
322
- type: 'string',
323
- name: 'message',
324
- value: 'Hi, Alice!',
325
- },
326
- ];
327
-
328
- it('signs in a compliant and recoverable way', async () => {
329
- const keyring = new HdKeyring();
330
- keyring.generateRandomMnemonic();
331
- await keyring.addAccounts(1);
332
- const addresses = await keyring.getAccounts();
333
- const address = addresses[0];
334
- const signature = await keyring.signTypedData(address, typedData, {
335
- version: SignTypedDataVersion.V1,
336
- });
337
- const restored = recoverTypedSignature({
338
- data: typedData,
339
- signature,
340
- version: SignTypedDataVersion.V1,
341
- });
342
- expect(restored).toStrictEqual(address);
343
- });
344
- });
345
-
346
- describe('#signTypedData_v3', () => {
347
- it('signs in a compliant and recoverable way', async () => {
348
- const keyring = new HdKeyring();
349
- const typedData = {
350
- types: {
351
- EIP712Domain: [],
352
- },
353
- domain: {},
354
- primaryType: 'EIP712Domain',
355
- message: {},
356
- };
357
-
358
- await keyring.deserialize({
359
- mnemonic: sampleMnemonic,
360
- numberOfAccounts: 1,
361
- });
362
- const addresses = await keyring.getAccounts();
363
- const address = addresses[0];
364
- const signature = await keyring.signTypedData(address, typedData, {
365
- version: SignTypedDataVersion.V3,
366
- });
367
- const restored = recoverTypedSignature({
368
- data: typedData,
369
- signature,
370
- version: SignTypedDataVersion.V3,
371
- });
372
- expect(restored).toStrictEqual(address);
373
- });
374
- });
375
-
376
- describe('#signTypedData_v3 signature verification', () => {
377
- it('signs in a recoverable way.', async () => {
378
- const keyring = new HdKeyring();
379
- const typedData = {
380
- types: {
381
- EIP712Domain: [
382
- { name: 'name', type: 'string' },
383
- { name: 'version', type: 'string' },
384
- { name: 'chainId', type: 'uint256' },
385
- { name: 'verifyingContract', type: 'address' },
386
- ],
387
- Person: [
388
- { name: 'name', type: 'string' },
389
- { name: 'wallet', type: 'address' },
390
- ],
391
- Mail: [
392
- { name: 'from', type: 'Person' },
393
- { name: 'to', type: 'Person' },
394
- { name: 'contents', type: 'string' },
395
- ],
396
- },
397
- primaryType: 'Mail',
398
- domain: {
399
- name: 'Ether Mail',
400
- version: '1',
401
- chainId: 1,
402
- verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
403
- },
404
- message: {
405
- from: {
406
- name: 'Cow',
407
- wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
408
- },
409
- to: {
410
- name: 'Bob',
411
- wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
412
- },
413
- contents: 'Hello, Bob!',
414
- },
415
- };
416
-
417
- keyring.generateRandomMnemonic();
418
- await keyring.addAccounts(1);
419
- const addresses = await keyring.getAccounts();
420
- const address = addresses[0];
421
- const signature = await keyring.signTypedData(address, typedData, {
422
- version: SignTypedDataVersion.V3,
423
- });
424
- const restored = recoverTypedSignature({
425
- data: typedData,
426
- signature,
427
- version: SignTypedDataVersion.V3,
428
- });
429
- expect(restored).toStrictEqual(address);
430
- });
431
- });
432
-
433
- describe('custom hd paths', () => {
434
- it('can deserialize with an hdPath param and generate the same accounts.', async () => {
435
- const keyring = new HdKeyring();
436
- const hdPathString = `m/44'/60'/0'/0`;
437
- keyring.deserialize({
438
- mnemonic: sampleMnemonic,
439
- numberOfAccounts: 1,
440
- hdPath: hdPathString,
441
- });
442
- const addresses = await keyring.getAccounts();
443
- expect(addresses[0]).toStrictEqual(firstAcct);
444
- const serialized = await keyring.serialize();
445
- expect(serialized.hdPath).toStrictEqual(hdPathString);
446
- });
447
-
448
- it('can deserialize with an hdPath param and generate different accounts.', async () => {
449
- const keyring = new HdKeyring();
450
- const hdPathString = `m/44'/60'/0'/1`;
451
- keyring.deserialize({
452
- mnemonic: sampleMnemonic,
453
- numberOfAccounts: 1,
454
- hdPath: hdPathString,
455
- });
456
- const addresses = await keyring.getAccounts();
457
- expect(addresses[0]).not.toBe(firstAcct);
458
- const serialized = await keyring.serialize();
459
- expect(serialized.hdPath).toStrictEqual(hdPathString);
460
- });
461
- });
462
-
463
- // eslint-disable-next-line
464
- /*
465
- describe('create and restore 1k accounts', function () {
466
- it('should restore same accounts with no problem', async function () {
467
- this.timeout(20000)
468
-
469
- for (let i = 0; i < 1e3; i++) {
470
-
471
- const keyring = new HdKeyring({
472
- numberOfAccounts: 1,
473
- })
474
- const originalAccounts = await keyring.getAccounts()
475
- const serialized = await keyring.serialize()
476
- const mnemonic = serialized.mnemonic
477
-
478
- const keyring = new HdKeyring({
479
- numberOfAccounts: 1,
480
- mnemonic,
481
- })
482
- const restoredAccounts = await keyring.getAccounts()
483
-
484
- const first = originalAccounts[0]
485
- const restored = restoredAccounts[0]
486
- const msg = `Should restore same account from mnemonic: "${mnemonic}"`
487
- assert.equal(restoredAccounts[0], originalAccounts[0], msg)
488
-
489
- }
490
-
491
- return true
492
- })
493
- })
494
- */
495
-
496
- describe('signing methods withAppKeyOrigin option', () => {
497
- it('should signPersonalMessage with the expected key when passed a withAppKeyOrigin', async () => {
498
- const keyring = new HdKeyring();
499
- const address = firstAcct;
500
- const message = '0x68656c6c6f20776f726c64';
501
-
502
- const privateKey = Buffer.from(
503
- '8e82d2d74c50e5c8460f771d38a560ebe1151a9134c65a7e92b28ad0cfae7151',
504
- 'hex',
505
- );
506
- const expectedSig = personalSign({ privateKey, data: message });
507
-
508
- await keyring.deserialize({
509
- mnemonic: sampleMnemonic,
510
- numberOfAccounts: 1,
511
- });
512
- const sig = await keyring.signPersonalMessage(address, message, {
513
- withAppKeyOrigin: 'someapp.origin.io',
514
- });
515
-
516
- expect(sig).toStrictEqual(expectedSig);
517
- });
518
-
519
- it('should signTypedData with the expected key when passed a withAppKeyOrigin', async () => {
520
- const keyring = new HdKeyring();
521
- const address = firstAcct;
522
- const typedData = {
523
- types: {
524
- EIP712Domain: [],
525
- },
526
- domain: {},
527
- primaryType: 'EIP712Domain',
528
- message: {},
529
- };
530
-
531
- const privateKey = Buffer.from(
532
- '8e82d2d74c50e5c8460f771d38a560ebe1151a9134c65a7e92b28ad0cfae7151',
533
- 'hex',
534
- );
535
- const expectedSig = signTypedData({
536
- privateKey,
537
- data: typedData,
538
- version: SignTypedDataVersion.V3,
539
- });
540
-
541
- await keyring.deserialize({
542
- mnemonic: sampleMnemonic,
543
- numberOfAccounts: 1,
544
- });
545
-
546
- const sig = await keyring.signTypedData(address, typedData, {
547
- withAppKeyOrigin: 'someapp.origin.io',
548
- version: SignTypedDataVersion.V3,
549
- });
550
- expect(sig).toStrictEqual(expectedSig);
551
- });
552
- });
553
-
554
- // /
555
- /* TESTS FOR BASE-KEYRING METHODS */
556
- // /
557
-
558
- describe('#signMessage', function () {
559
- const message =
560
- '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0';
561
- const expectedResult =
562
- '0xb21867b2221db0172e970b7370825b71c57823ff8714168ce9748f32f450e2c43d0fe396eb5b5f59284b7fd108c8cf61a6180a6756bdd3d4b7b9ccc4ac6d51611b';
563
-
564
- it('passes the dennis test', async function () {
565
- const keyring = new HdKeyring();
566
- await keyring.deserialize({
567
- mnemonic: sampleMnemonic,
568
- numberOfAccounts: 1,
569
- });
570
- const result = await keyring.signMessage(firstAcct, message);
571
- expect(result).toBe(expectedResult);
572
- });
573
-
574
- it('reliably can decode messages it signs', async function () {
575
- const keyring = new HdKeyring();
576
- await keyring.deserialize({
577
- mnemonic: sampleMnemonic,
578
- numberOfAccounts: 1,
579
- });
580
- const localMessage = 'hello there!';
581
- const msgHashHex = bufferToHex(
582
- Buffer.from(keccak256(Buffer.from(localMessage))),
583
- );
584
- await keyring.addAccounts(9);
585
- const addresses = await keyring.getAccounts();
586
- const signatures = await Promise.all(
587
- addresses.map(async (accountAddress) => {
588
- return await keyring.signMessage(accountAddress, msgHashHex);
589
- }),
590
- );
591
- signatures.forEach((sgn, index) => {
592
- const accountAddress = addresses[index];
593
-
594
- const r = toBuffer(sgn.slice(0, 66));
595
- const s = toBuffer(`0x${sgn.slice(66, 130)}`);
596
- const v = BigInt(`0x${sgn.slice(130, 132)}`);
597
- const m = toBuffer(msgHashHex);
598
- const pub = ecrecover(m, v, r, s);
599
- const adr = `0x${pubToAddress(pub).toString('hex')}`;
600
-
601
- expect(adr).toBe(accountAddress);
602
- });
603
- });
604
-
605
- it('throw error for invalid message', async function () {
606
- const keyring = new HdKeyring();
607
- await keyring.deserialize({
608
- mnemonic: sampleMnemonic,
609
- numberOfAccounts: 1,
610
- });
611
-
612
- await expect(keyring.signMessage(firstAcct, '')).rejects.toThrow(
613
- 'Value must be a hexadecimal string',
614
- );
615
- });
616
-
617
- it('throw error if empty address is passed', async function () {
618
- const keyring = new HdKeyring();
619
- await keyring.deserialize({
620
- mnemonic: sampleMnemonic,
621
- numberOfAccounts: 1,
622
- });
623
-
624
- await expect(keyring.signMessage('', message)).rejects.toThrow(
625
- 'Must specify address.',
626
- );
627
- });
628
-
629
- it('throw error if address not associated with the current keyring is passed', async function () {
630
- const keyring = new HdKeyring();
631
- await keyring.deserialize({
632
- mnemonic: sampleMnemonic,
633
- numberOfAccounts: 1,
634
- });
635
-
636
- await expect(
637
- keyring.signMessage(notKeyringAddress, message),
638
- ).rejects.toThrow('HD Keyring - Unable to find matching address.');
639
- });
640
- });
641
-
642
- describe('#removeAccount', function () {
643
- let keyring;
644
- beforeEach(() => {
645
- keyring = new HdKeyring({
646
- mnemonic: sampleMnemonic,
647
- numberOfAccounts: 1,
648
- });
649
- });
650
-
651
- describe('if the account exists', function () {
652
- it('should remove that account', async function () {
653
- const addresses = await keyring.getAccounts();
654
- expect(addresses).toHaveLength(1);
655
- keyring.removeAccount(addresses[0]);
656
- const addressesAfterRemoval = await keyring.getAccounts();
657
- expect(addressesAfterRemoval).toHaveLength(0);
658
- });
659
- });
660
-
661
- describe('if the account does not exist', function () {
662
- it('should throw an error', function () {
663
- const unexistingAccount = '0x0000000000000000000000000000000000000000';
664
- expect(() => keyring.removeAccount(unexistingAccount)).toThrow(
665
- `Address ${unexistingAccount} not found in this keyring`,
666
- );
667
- });
668
- });
669
- });
670
-
671
- describe('getAppKeyAddress', function () {
672
- let keyring;
673
- beforeEach(() => {
674
- keyring = new HdKeyring({
675
- mnemonic: sampleMnemonic,
676
- numberOfAccounts: 1,
677
- });
678
- });
679
-
680
- it('should return a public address custom to the provided app key origin', async function () {
681
- const appKeyAddress = await keyring.getAppKeyAddress(
682
- firstAcct,
683
- 'someapp.origin.io',
684
- );
685
-
686
- expect(firstAcct).not.toBe(appKeyAddress);
687
- expect(isValidAddress(appKeyAddress)).toBe(true);
688
- });
689
-
690
- it('should return different addresses when provided different app key origins', async function () {
691
- const appKeyAddress1 = await keyring.getAppKeyAddress(
692
- firstAcct,
693
- 'someapp.origin.io',
694
- );
695
-
696
- expect(isValidAddress(appKeyAddress1)).toBe(true);
697
-
698
- const appKeyAddress2 = await keyring.getAppKeyAddress(
699
- firstAcct,
700
- 'anotherapp.origin.io',
701
- );
702
-
703
- expect(isValidAddress(appKeyAddress2)).toBe(true);
704
- expect(appKeyAddress1).not.toBe(appKeyAddress2);
705
- });
706
-
707
- it('should return the same address when called multiple times with the same params', async function () {
708
- const appKeyAddress1 = await keyring.getAppKeyAddress(
709
- firstAcct,
710
- 'someapp.origin.io',
711
- );
712
-
713
- expect(isValidAddress(appKeyAddress1)).toBe(true);
714
-
715
- const appKeyAddress2 = await keyring.getAppKeyAddress(
716
- firstAcct,
717
- 'someapp.origin.io',
718
- );
719
-
720
- expect(isValidAddress(appKeyAddress2)).toBe(true);
721
- expect(appKeyAddress1).toBe(appKeyAddress2);
722
- });
723
-
724
- it('should throw error if the provided origin is not a string', async function () {
725
- await expect(keyring.getAppKeyAddress(firstAcct, [])).rejects.toThrow(
726
- `'origin' must be a non-empty string`,
727
- );
728
- });
729
-
730
- it('should throw error if the provided origin is an empty string', async function () {
731
- await expect(keyring.getAppKeyAddress(firstAcct, '')).rejects.toThrow(
732
- `'origin' must be a non-empty string`,
733
- );
734
- });
735
- });
736
-
737
- describe('exportAccount', function () {
738
- let keyring;
739
- beforeEach(() => {
740
- keyring = new HdKeyring({
741
- mnemonic: sampleMnemonic,
742
- numberOfAccounts: 1,
743
- });
744
- });
745
-
746
- it('should return a hex-encoded private key', async function () {
747
- const expectedPrivateKeyResult =
748
- '0xd3cc16948a02a91b9fcf83735653bf3dfd82c86543fdd1e9a828bd25e8a7b68d';
749
- const privKeyHexValue = await keyring.exportAccount(firstAcct);
750
-
751
- expect(expectedPrivateKeyResult).toBe(`0x${privKeyHexValue}`);
752
- });
753
-
754
- it('throw error if account is not present', async function () {
755
- await expect(keyring.exportAccount(notKeyringAddress)).rejects.toThrow(
756
- 'HD Keyring - Unable to find matching address.',
757
- );
758
- });
759
- });
760
-
761
- describe('#encryptionPublicKey', function () {
762
- const publicKey = 'LV7lWhd0mUDcvxkMU2o6uKXftu25zq4bMYdmMqppXic=';
763
- let keyring;
764
- beforeEach(() => {
765
- keyring = new HdKeyring({
766
- mnemonic: sampleMnemonic,
767
- numberOfAccounts: 1,
768
- });
769
- });
770
-
771
- it('returns the expected value', async function () {
772
- const encryptionPublicKey = await keyring.getEncryptionPublicKey(
773
- firstAcct,
774
- );
775
- expect(publicKey).toBe(encryptionPublicKey);
776
- });
777
-
778
- it('throw error if address is blank', async function () {
779
- await expect(keyring.getEncryptionPublicKey('')).rejects.toThrow(
780
- 'Must specify address.',
781
- );
782
- });
783
-
784
- it('throw error if address is not present in the keyring', async function () {
785
- await expect(
786
- keyring.getEncryptionPublicKey(notKeyringAddress),
787
- ).rejects.toThrow('HD Keyring - Unable to find matching address.');
788
- });
789
- });
790
-
791
- describe('#signTypedData V4 signature verification', function () {
792
- let keyring;
793
- beforeEach(() => {
794
- keyring = new HdKeyring({
795
- mnemonic: sampleMnemonic,
796
- numberOfAccounts: 1,
797
- });
798
- });
799
-
800
- const expectedSignature =
801
- '0x220917664ef676d592bd709a5bffedaf69c5f6c72f13c6c4547a41d211f0923c3180893b1dec023433f11b664fabda22b74b57d21094f7798fc85b7650f8edbb1b';
802
-
803
- it('returns the expected value', async function () {
804
- const typedData = {
805
- types: {
806
- EIP712Domain: [
807
- { name: 'name', type: 'string' },
808
- { name: 'version', type: 'string' },
809
- { name: 'chainId', type: 'uint256' },
810
- { name: 'verifyingContract', type: 'address' },
811
- ],
812
- Person: [
813
- { name: 'name', type: 'string' },
814
- { name: 'wallets', type: 'address[]' },
815
- ],
816
- Mail: [
817
- { name: 'from', type: 'Person' },
818
- { name: 'to', type: 'Person[]' },
819
- { name: 'contents', type: 'string' },
820
- ],
821
- Group: [
822
- { name: 'name', type: 'string' },
823
- { name: 'members', type: 'Person[]' },
824
- ],
825
- },
826
- domain: {
827
- name: 'Ether Mail',
828
- version: '1',
829
- chainId: 1,
830
- verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
831
- },
832
- primaryType: 'Mail',
833
- message: {
834
- from: {
835
- name: 'Cow',
836
- wallets: [
837
- '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
838
- '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
839
- ],
840
- },
841
- to: [
842
- {
843
- name: 'Bob',
844
- wallets: [
845
- '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
846
- '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
847
- '0xB0B0b0b0b0b0B000000000000000000000000000',
848
- ],
849
- },
850
- ],
851
- contents: 'Hello, Bob!',
852
- },
853
- };
854
-
855
- const addresses = await keyring.getAccounts();
856
- const [address] = addresses;
857
-
858
- const signature = await keyring.signTypedData(address, typedData, {
859
- version: 'V4',
860
- });
861
- expect(signature).toBe(expectedSignature);
862
- const restored = recoverTypedSignature({
863
- data: typedData,
864
- signature,
865
- version: SignTypedDataVersion.V4,
866
- });
867
- expect(restored).toBe(address);
868
- });
869
- });
870
-
871
- describe('#decryptMessage', function () {
872
- const message = 'Hello world!';
873
- let encryptedMessage, keyring;
874
-
875
- beforeEach(async () => {
876
- keyring = new HdKeyring({
877
- mnemonic: sampleMnemonic,
878
- numberOfAccounts: 1,
879
- });
880
-
881
- const encryptionPublicKey = await keyring.getEncryptionPublicKey(
882
- firstAcct,
883
- );
884
- encryptedMessage = encrypt({
885
- publicKey: encryptionPublicKey,
886
- data: message,
887
- version: 'x25519-xsalsa20-poly1305',
888
- });
889
- });
890
-
891
- it('returns the expected value', async function () {
892
- const decryptedMessage = await keyring.decryptMessage(
893
- firstAcct,
894
- encryptedMessage,
895
- );
896
- expect(message).toBe(decryptedMessage);
897
- });
898
-
899
- it('throw error if address passed is not present in the keyring', async function () {
900
- await expect(
901
- keyring.decryptMessage(notKeyringAddress, encryptedMessage),
902
- ).rejects.toThrow('HD Keyring - Unable to find matching address.');
903
- });
904
-
905
- it('throw error if wrong encrypted data object is passed', async function () {
906
- await expect(keyring.decryptMessage(firstAcct, {})).rejects.toThrow(
907
- 'Encryption type/version not supported.',
908
- );
909
- });
910
- });
911
-
912
- describe('#signTransaction', function () {
913
- let keyring;
914
- beforeEach(() => {
915
- keyring = new HdKeyring({
916
- mnemonic: sampleMnemonic,
917
- numberOfAccounts: 1,
918
- });
919
- });
920
-
921
- const txParams = {
922
- from: firstAcct,
923
- nonce: '0x00',
924
- gasPrice: '0x09184e72a000',
925
- gasLimit: '0x2710',
926
- to: firstAcct,
927
- value: '0x1000',
928
- };
929
-
930
- it('returns a signed legacy tx object', async function () {
931
- const tx = new EthereumTx(txParams);
932
- expect(tx.isSigned()).toBe(false);
933
-
934
- const signed = await keyring.signTransaction(firstAcct, tx);
935
- expect(signed.isSigned()).toBe(true);
936
- });
937
-
938
- it('returns a signed tx object', async function () {
939
- const tx = TransactionFactory.fromTxData(txParams);
940
- expect(tx.isSigned()).toBe(false);
941
-
942
- const signed = await keyring.signTransaction(firstAcct, tx);
943
- expect(signed.isSigned()).toBe(true);
944
- });
945
-
946
- it('returns rejected promise if empty address is passed', async function () {
947
- const tx = TransactionFactory.fromTxData(txParams);
948
- await expect(keyring.signTransaction('', tx)).rejects.toThrow(
949
- 'Must specify address.',
950
- );
951
- });
952
-
953
- it('throw error if wrong address is passed', async function () {
954
- const tx = TransactionFactory.fromTxData(txParams);
955
- await expect(
956
- keyring.signTransaction(notKeyringAddress, tx),
957
- ).rejects.toThrow('HD Keyring - Unable to find matching address.');
958
- });
959
- });
960
- });