@metamask/eth-hd-keyring 4.0.2 → 5.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 CHANGED
@@ -5,8 +5,24 @@ const {
5
5
  recoverTypedSignature,
6
6
  signTypedData,
7
7
  SignTypedDataVersion,
8
+ encrypt,
8
9
  } = require('@metamask/eth-sig-util');
9
- const ethUtil = require('ethereumjs-util');
10
+ const { wordlist } = require('@metamask/scure-bip39/dist/wordlists/english');
11
+ const oldMMForkBIP39 = require('@metamask/bip39');
12
+ const {
13
+ isValidAddress,
14
+ bufferToHex,
15
+ toBuffer,
16
+ ecrecover,
17
+ pubToAddress,
18
+ } = require('@ethereumjs/util');
19
+ const {
20
+ TransactionFactory,
21
+ Transaction: EthereumTx,
22
+ } = require('@ethereumjs/tx');
23
+
24
+ const OldHdKeyring = require('@metamask/eth-hd-keyring');
25
+ const { keccak256 } = require('ethereum-cryptography/keccak');
10
26
  const HdKeyring = require('..');
11
27
 
12
28
  // Sample account:
@@ -18,12 +34,40 @@ const sampleMnemonic =
18
34
  const firstAcct = '0x1c96099350f13d558464ec79b9be4445aa0ef579';
19
35
  const secondAcct = '0x1b00aed43a693f3a957f9feb5cc08afa031e37a0';
20
36
 
37
+ const notKeyringAddress = '0xbD20F6F5F1616947a39E11926E78ec94817B3931';
38
+
21
39
  describe('hd-keyring', () => {
22
40
  let keyring;
23
41
  beforeEach(() => {
24
42
  keyring = new HdKeyring();
25
43
  });
26
44
 
45
+ describe('compare old bip39 implementation with new', () => {
46
+ it('should derive the same accounts from the same mnemonics', async () => {
47
+ const mnemonics = [];
48
+ for (let i = 0; i < 99; i++) {
49
+ mnemonics.push(oldMMForkBIP39.generateMnemonic());
50
+ }
51
+
52
+ await Promise.all(
53
+ mnemonics.map(async (mnemonic) => {
54
+ const newHDKeyring = new HdKeyring({ mnemonic, numberOfAccounts: 3 });
55
+ const oldHDKeyring = new OldHdKeyring({
56
+ mnemonic,
57
+ numberOfAccounts: 3,
58
+ });
59
+ const newAccounts = await newHDKeyring.getAccounts();
60
+ const oldAccounts = await oldHDKeyring.getAccounts();
61
+ await expect(newAccounts[0]).toStrictEqual(oldAccounts[0]);
62
+
63
+ await expect(newAccounts[1]).toStrictEqual(oldAccounts[1]);
64
+
65
+ await expect(newAccounts[2]).toStrictEqual(oldAccounts[2]);
66
+ }),
67
+ );
68
+ });
69
+ });
70
+
27
71
  describe('constructor', () => {
28
72
  it('constructs with a typeof string mnemonic', async () => {
29
73
  keyring = new HdKeyring({
@@ -36,9 +80,9 @@ describe('hd-keyring', () => {
36
80
  expect(accounts[1]).toStrictEqual(secondAcct);
37
81
  });
38
82
 
39
- it('constructs with a typeof array mnemonic', async () => {
83
+ it('constructs with a typeof buffer mnemonic', async () => {
40
84
  keyring = new HdKeyring({
41
- mnemonic: Array.from(Buffer.from(sampleMnemonic, 'utf8').values()),
85
+ mnemonic: Buffer.from(sampleMnemonic, 'utf8'),
42
86
  numberOfAccounts: 2,
43
87
  });
44
88
 
@@ -47,9 +91,15 @@ describe('hd-keyring', () => {
47
91
  expect(accounts[1]).toStrictEqual(secondAcct);
48
92
  });
49
93
 
50
- it('constructs with a typeof buffer mnemonic', async () => {
94
+ it('constructs with a typeof Uint8Array mnemonic', async () => {
95
+ const indices = sampleMnemonic
96
+ .split(' ')
97
+ .map((word) => wordlist.indexOf(word));
98
+ const uInt8ArrayOfMnemonic = new Uint8Array(
99
+ new Uint16Array(indices).buffer,
100
+ );
51
101
  keyring = new HdKeyring({
52
- mnemonic: Buffer.from(sampleMnemonic, 'utf8'),
102
+ mnemonic: uInt8ArrayOfMnemonic,
53
103
  numberOfAccounts: 2,
54
104
  });
55
105
 
@@ -132,18 +182,34 @@ describe('hd-keyring', () => {
132
182
  });
133
183
 
134
184
  describe('#serialize mnemonic.', () => {
135
- it('serializes mnemonic stored as a buffer in a class variable into a buffer array and does not add accounts', async () => {
136
- keyring.generateRandomMnemonic();
185
+ it('serializes mnemonic stored as a buffer to a Uint8Array', async () => {
186
+ keyring.mnemonic = oldMMForkBIP39.generateMnemonic();
187
+ const mnemonicAsUint8Array = keyring._stringToUint8Array(
188
+ keyring.mnemonic.toString(),
189
+ );
137
190
  const output = await keyring.serialize();
138
191
  expect(output.numberOfAccounts).toBe(0);
139
- expect(Array.isArray(output.mnemonic)).toBe(true);
192
+ expect(output.mnemonic).toStrictEqual(mnemonicAsUint8Array);
193
+ });
194
+
195
+ it('serializes keyring data with mnemonic stored as a Uint8Array', async () => {
196
+ keyring.generateRandomMnemonic();
197
+ const { mnemonic } = keyring;
198
+ const hdpath = keyring.hdPath;
199
+ keyring.addAccounts(1);
200
+ const output = await keyring.serialize();
201
+ expect(output.numberOfAccounts).toBe(1);
202
+ expect(output.hdPath).toStrictEqual(hdpath);
203
+ expect(output.mnemonic).toStrictEqual(mnemonic);
140
204
  });
141
205
 
142
- it('serializes mnemonic stored as a string in a class variable into a buffer array and does not add accounts', async () => {
206
+ it('serializes mnemonic stored as a string', async () => {
143
207
  keyring.mnemonic = sampleMnemonic;
144
208
  const output = await keyring.serialize();
145
209
  expect(output.numberOfAccounts).toBe(0);
146
- expect(Array.isArray(output.mnemonic)).toBe(true);
210
+ expect(output.mnemonic).toStrictEqual(
211
+ keyring._stringToUint8Array(sampleMnemonic),
212
+ );
147
213
  });
148
214
  });
149
215
 
@@ -153,14 +219,16 @@ describe('hd-keyring', () => {
153
219
  mnemonic: sampleMnemonic,
154
220
  numberOfAccounts: 1,
155
221
  });
156
- expect(keyring.wallets).toHaveLength(1);
222
+ const accountsFirstCheck = await keyring.getAccounts();
223
+
224
+ expect(accountsFirstCheck).toHaveLength(1);
157
225
  await keyring.addAccounts(1);
158
- const accounts = await keyring.getAccounts();
159
- expect(accounts[0]).toStrictEqual(firstAcct);
160
- expect(accounts[1]).toStrictEqual(secondAcct);
161
- expect(accounts).toHaveLength(2);
226
+ const accountsSecondCheck = await keyring.getAccounts();
227
+ expect(accountsSecondCheck[0]).toStrictEqual(firstAcct);
228
+ expect(accountsSecondCheck[1]).toStrictEqual(secondAcct);
229
+ expect(accountsSecondCheck).toHaveLength(2);
162
230
  const serialized = await keyring.serialize();
163
- expect(Buffer.from(serialized.mnemonic).toString()).toStrictEqual(
231
+ expect(keyring._uint8ArrayToString(serialized.mnemonic)).toStrictEqual(
164
232
  sampleMnemonic,
165
233
  );
166
234
  });
@@ -171,7 +239,8 @@ describe('hd-keyring', () => {
171
239
  it('creates a single wallet', async () => {
172
240
  keyring.generateRandomMnemonic();
173
241
  await keyring.addAccounts();
174
- expect(keyring.wallets).toHaveLength(1);
242
+ const accounts = await keyring.getAccounts();
243
+ expect(accounts).toHaveLength(1);
175
244
  });
176
245
 
177
246
  it('throws an error when no SRP has been generated yet', async () => {
@@ -185,28 +254,9 @@ describe('hd-keyring', () => {
185
254
  it('creates that number of wallets', async () => {
186
255
  keyring.generateRandomMnemonic();
187
256
  await keyring.addAccounts(3);
188
- expect(keyring.wallets).toHaveLength(3);
189
- });
190
- });
191
- });
192
-
193
- describe('#getAccounts', () => {
194
- it('calls getAddress on each wallet', async () => {
195
- // Push a mock wallet
196
- const desiredOutput = 'foo';
197
- keyring.wallets.push({
198
- getAddress() {
199
- return {
200
- toString() {
201
- return desiredOutput;
202
- },
203
- };
204
- },
257
+ const accounts = await keyring.getAccounts();
258
+ expect(accounts).toHaveLength(3);
205
259
  });
206
-
207
- const output = await keyring.getAccounts();
208
- expect(output[0]).toBe(`0x${desiredOutput}`);
209
- expect(output).toHaveLength(1);
210
260
  });
211
261
  });
212
262
 
@@ -270,7 +320,9 @@ describe('hd-keyring', () => {
270
320
  await keyring.addAccounts(1);
271
321
  const addresses = await keyring.getAccounts();
272
322
  const address = addresses[0];
273
- const signature = await keyring.signTypedData_v1(address, typedData);
323
+ const signature = await keyring.signTypedData(address, typedData, {
324
+ version: SignTypedDataVersion.V1,
325
+ });
274
326
  const restored = recoverTypedSignature({
275
327
  data: typedData,
276
328
  signature,
@@ -297,7 +349,9 @@ describe('hd-keyring', () => {
297
349
  });
298
350
  const addresses = await keyring.getAccounts();
299
351
  const address = addresses[0];
300
- const signature = await keyring.signTypedData_v3(address, typedData);
352
+ const signature = await keyring.signTypedData(address, typedData, {
353
+ version: SignTypedDataVersion.V3,
354
+ });
301
355
  const restored = recoverTypedSignature({
302
356
  data: typedData,
303
357
  signature,
@@ -351,7 +405,9 @@ describe('hd-keyring', () => {
351
405
  await keyring.addAccounts(1);
352
406
  const addresses = await keyring.getAccounts();
353
407
  const address = addresses[0];
354
- const signature = await keyring.signTypedData_v3(address, typedData);
408
+ const signature = await keyring.signTypedData(address, typedData, {
409
+ version: SignTypedDataVersion.V3,
410
+ });
355
411
  const restored = recoverTypedSignature({
356
412
  data: typedData,
357
413
  signature,
@@ -423,129 +479,453 @@ describe('hd-keyring', () => {
423
479
  })
424
480
  */
425
481
 
426
- describe('getAppKeyAddress', () => {
427
- it('should return a public address custom to the provided app key origin', async () => {
482
+ describe('signing methods withAppKeyOrigin option', () => {
483
+ it('should signPersonalMessage with the expected key when passed a withAppKeyOrigin', async () => {
428
484
  const address = firstAcct;
485
+ const message = '0x68656c6c6f20776f726c64';
429
486
 
430
- keyring = new HdKeyring({
487
+ const privateKey = Buffer.from(
488
+ '8e82d2d74c50e5c8460f771d38a560ebe1151a9134c65a7e92b28ad0cfae7151',
489
+ 'hex',
490
+ );
491
+ const expectedSig = personalSign({ privateKey, data: message });
492
+
493
+ await keyring.deserialize({
431
494
  mnemonic: sampleMnemonic,
432
495
  numberOfAccounts: 1,
433
496
  });
434
- const appKeyAddress = await keyring.getAppKeyAddress(
435
- address,
436
- 'someapp.origin.io',
497
+ const sig = await keyring.signPersonalMessage(address, message, {
498
+ withAppKeyOrigin: 'someapp.origin.io',
499
+ });
500
+
501
+ expect(sig).toStrictEqual(expectedSig);
502
+ });
503
+
504
+ it('should signTypedData with the expected key when passed a withAppKeyOrigin', async () => {
505
+ const address = firstAcct;
506
+ const typedData = {
507
+ types: {
508
+ EIP712Domain: [],
509
+ },
510
+ domain: {},
511
+ primaryType: 'EIP712Domain',
512
+ message: {},
513
+ };
514
+
515
+ const privateKey = Buffer.from(
516
+ '8e82d2d74c50e5c8460f771d38a560ebe1151a9134c65a7e92b28ad0cfae7151',
517
+ 'hex',
437
518
  );
519
+ const expectedSig = signTypedData({
520
+ privateKey,
521
+ data: typedData,
522
+ version: SignTypedDataVersion.V3,
523
+ });
438
524
 
439
- expect(address).not.toBe(appKeyAddress);
440
- expect(ethUtil.isValidAddress(appKeyAddress)).toBe(true);
525
+ await keyring.deserialize({
526
+ mnemonic: sampleMnemonic,
527
+ numberOfAccounts: 1,
528
+ });
441
529
 
442
- const accounts = await keyring.getAccounts();
443
- expect(accounts[0]).toStrictEqual(firstAcct);
530
+ const sig = await keyring.signTypedData(address, typedData, {
531
+ withAppKeyOrigin: 'someapp.origin.io',
532
+ version: SignTypedDataVersion.V3,
533
+ });
534
+ expect(sig).toStrictEqual(expectedSig);
444
535
  });
536
+ });
445
537
 
446
- it('should return different addresses when provided different app key origins', async () => {
447
- keyring = new HdKeyring({
538
+ // /
539
+ /* TESTS FOR BASE-KEYRING METHODS */
540
+ // /
541
+
542
+ describe('#signMessage', function () {
543
+ const message =
544
+ '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0';
545
+ const expectedResult =
546
+ '0xb21867b2221db0172e970b7370825b71c57823ff8714168ce9748f32f450e2c43d0fe396eb5b5f59284b7fd108c8cf61a6180a6756bdd3d4b7b9ccc4ac6d51611b';
547
+
548
+ it('passes the dennis test', async function () {
549
+ await keyring.deserialize({
448
550
  mnemonic: sampleMnemonic,
449
551
  numberOfAccounts: 1,
450
552
  });
553
+ const result = await keyring.signMessage(firstAcct, message);
554
+ expect(result).toBe(expectedResult);
555
+ });
451
556
 
452
- const address = firstAcct;
557
+ it('reliably can decode messages it signs', async function () {
558
+ await keyring.deserialize({
559
+ mnemonic: sampleMnemonic,
560
+ numberOfAccounts: 1,
561
+ });
562
+ const localMessage = 'hello there!';
563
+ const msgHashHex = bufferToHex(keccak256(Buffer.from(localMessage)));
564
+ await keyring.addAccounts(9);
565
+ const addresses = await keyring.getAccounts();
566
+ const signatures = await Promise.all(
567
+ addresses.map(async (accountAddress) => {
568
+ return await keyring.signMessage(accountAddress, msgHashHex);
569
+ }),
570
+ );
571
+ signatures.forEach((sgn, index) => {
572
+ const accountAddress = addresses[index];
453
573
 
454
- const appKeyAddress1 = await keyring.getAppKeyAddress(
455
- address,
456
- 'someapp.origin.io',
574
+ const r = toBuffer(sgn.slice(0, 66));
575
+ const s = toBuffer(`0x${sgn.slice(66, 130)}`);
576
+ const v = BigInt(`0x${sgn.slice(130, 132)}`);
577
+ const m = toBuffer(msgHashHex);
578
+ const pub = ecrecover(m, v, r, s);
579
+ const adr = `0x${pubToAddress(pub).toString('hex')}`;
580
+
581
+ expect(adr).toBe(accountAddress);
582
+ });
583
+ });
584
+
585
+ it('throw error for invalid message', async function () {
586
+ await keyring.deserialize({
587
+ mnemonic: sampleMnemonic,
588
+ numberOfAccounts: 1,
589
+ });
590
+
591
+ await expect(keyring.signMessage(firstAcct, '')).rejects.toThrow(
592
+ 'Cannot convert 0x to a BigInt',
457
593
  );
594
+ });
458
595
 
459
- expect(ethUtil.isValidAddress(appKeyAddress1)).toBe(true);
596
+ it('throw error if empty address is passed', async function () {
597
+ await keyring.deserialize({
598
+ mnemonic: sampleMnemonic,
599
+ numberOfAccounts: 1,
600
+ });
460
601
 
461
- const appKeyAddress2 = await keyring.getAppKeyAddress(
462
- address,
463
- 'anotherapp.origin.io',
602
+ await expect(keyring.signMessage('', message)).rejects.toThrow(
603
+ 'Must specify address.',
464
604
  );
605
+ });
465
606
 
466
- expect(ethUtil.isValidAddress(appKeyAddress2)).toBe(true);
607
+ it('throw error if address not associated with the current keyring is passed', async function () {
608
+ await keyring.deserialize({
609
+ mnemonic: sampleMnemonic,
610
+ numberOfAccounts: 1,
611
+ });
467
612
 
468
- expect(appKeyAddress1).not.toBe(appKeyAddress2);
613
+ await expect(
614
+ keyring.signMessage(notKeyringAddress, message),
615
+ ).rejects.toThrow('HD Keyring - Unable to find matching address.');
469
616
  });
617
+ });
470
618
 
471
- it('should return the same address when called multiple times with the same params', async () => {
619
+ describe('#removeAccount', function () {
620
+ beforeEach(() => {
472
621
  keyring = new HdKeyring({
473
622
  mnemonic: sampleMnemonic,
474
623
  numberOfAccounts: 1,
475
624
  });
625
+ });
476
626
 
477
- const address = firstAcct;
627
+ describe('if the account exists', function () {
628
+ it('should remove that account', async function () {
629
+ const addresses = await keyring.getAccounts();
630
+ expect(addresses).toHaveLength(1);
631
+ keyring.removeAccount(addresses[0]);
632
+ const addressesAfterRemoval = await keyring.getAccounts();
633
+ expect(addressesAfterRemoval).toHaveLength(0);
634
+ });
635
+ });
636
+
637
+ describe('if the account does not exist', function () {
638
+ it('should throw an error', function () {
639
+ const unexistingAccount = '0x0000000000000000000000000000000000000000';
640
+ expect(() => keyring.removeAccount(unexistingAccount)).toThrow(
641
+ `Address ${unexistingAccount} not found in this keyring`,
642
+ );
643
+ });
644
+ });
645
+ });
478
646
 
647
+ describe('getAppKeyAddress', function () {
648
+ beforeEach(() => {
649
+ keyring = new HdKeyring({
650
+ mnemonic: sampleMnemonic,
651
+ numberOfAccounts: 1,
652
+ });
653
+ });
654
+
655
+ it('should return a public address custom to the provided app key origin', async function () {
656
+ const appKeyAddress = await keyring.getAppKeyAddress(
657
+ firstAcct,
658
+ 'someapp.origin.io',
659
+ );
660
+
661
+ expect(firstAcct).not.toBe(appKeyAddress);
662
+ expect(isValidAddress(appKeyAddress)).toBe(true);
663
+ });
664
+
665
+ it('should return different addresses when provided different app key origins', async function () {
479
666
  const appKeyAddress1 = await keyring.getAppKeyAddress(
480
- address,
667
+ firstAcct,
481
668
  'someapp.origin.io',
482
669
  );
483
670
 
484
- expect(ethUtil.isValidAddress(appKeyAddress1)).toBe(true);
671
+ expect(isValidAddress(appKeyAddress1)).toBe(true);
485
672
 
486
673
  const appKeyAddress2 = await keyring.getAppKeyAddress(
487
- address,
674
+ firstAcct,
675
+ 'anotherapp.origin.io',
676
+ );
677
+
678
+ expect(isValidAddress(appKeyAddress2)).toBe(true);
679
+ expect(appKeyAddress1).not.toBe(appKeyAddress2);
680
+ });
681
+
682
+ it('should return the same address when called multiple times with the same params', async function () {
683
+ const appKeyAddress1 = await keyring.getAppKeyAddress(
684
+ firstAcct,
488
685
  'someapp.origin.io',
489
686
  );
490
687
 
491
- expect(ethUtil.isValidAddress(appKeyAddress2)).toBe(true);
688
+ expect(isValidAddress(appKeyAddress1)).toBe(true);
492
689
 
493
- expect(appKeyAddress1).toStrictEqual(appKeyAddress2);
690
+ const appKeyAddress2 = await keyring.getAppKeyAddress(
691
+ firstAcct,
692
+ 'someapp.origin.io',
693
+ );
694
+
695
+ expect(isValidAddress(appKeyAddress2)).toBe(true);
696
+ expect(appKeyAddress1).toBe(appKeyAddress2);
494
697
  });
495
- });
496
698
 
497
- describe('signing methods withAppKeyOrigin option', () => {
498
- it('should signPersonalMessage with the expected key when passed a withAppKeyOrigin', async () => {
499
- const address = firstAcct;
500
- const message = '0x68656c6c6f20776f726c64';
699
+ it('should throw error if the provided origin is not a string', async function () {
700
+ await expect(keyring.getAppKeyAddress(firstAcct, [])).rejects.toThrow(
701
+ `'origin' must be a non-empty string`,
702
+ );
703
+ });
501
704
 
502
- const privateKey = Buffer.from(
503
- '8e82d2d74c50e5c8460f771d38a560ebe1151a9134c65a7e92b28ad0cfae7151',
504
- 'hex',
705
+ it('should throw error if the provided origin is an empty string', async function () {
706
+ await expect(keyring.getAppKeyAddress(firstAcct, '')).rejects.toThrow(
707
+ `'origin' must be a non-empty string`,
505
708
  );
506
- const expectedSig = personalSign({ privateKey, data: message });
709
+ });
710
+ });
507
711
 
508
- await keyring.deserialize({
712
+ describe('exportAccount', function () {
713
+ beforeEach(() => {
714
+ keyring = new HdKeyring({
509
715
  mnemonic: sampleMnemonic,
510
716
  numberOfAccounts: 1,
511
717
  });
512
- const sig = await keyring.signPersonalMessage(address, message, {
513
- withAppKeyOrigin: 'someapp.origin.io',
718
+ });
719
+
720
+ it('should return a hex-encoded private key', async function () {
721
+ const expectedPrivateKeyResult =
722
+ '0xd3cc16948a02a91b9fcf83735653bf3dfd82c86543fdd1e9a828bd25e8a7b68d';
723
+ const privKeyHexValue = await keyring.exportAccount(firstAcct);
724
+
725
+ expect(expectedPrivateKeyResult).toBe(`0x${privKeyHexValue}`);
726
+ });
727
+
728
+ it('throw error if account is not present', async function () {
729
+ await expect(keyring.exportAccount(notKeyringAddress)).rejects.toThrow(
730
+ 'HD Keyring - Unable to find matching address.',
731
+ );
732
+ });
733
+ });
734
+
735
+ describe('#encryptionPublicKey', function () {
736
+ const publicKey = 'LV7lWhd0mUDcvxkMU2o6uKXftu25zq4bMYdmMqppXic=';
737
+ beforeEach(() => {
738
+ keyring = new HdKeyring({
739
+ mnemonic: sampleMnemonic,
740
+ numberOfAccounts: 1,
514
741
  });
742
+ });
515
743
 
516
- expect(sig).toStrictEqual(expectedSig);
744
+ it('returns the expected value', async function () {
745
+ const encryptionPublicKey = await keyring.getEncryptionPublicKey(
746
+ firstAcct,
747
+ );
748
+ expect(publicKey).toBe(encryptionPublicKey);
517
749
  });
518
750
 
519
- it('should signTypedData with the expected key when passed a withAppKeyOrigin', async () => {
520
- const address = firstAcct;
751
+ it('throw error if address is blank', async function () {
752
+ await expect(keyring.getEncryptionPublicKey('')).rejects.toThrow(
753
+ 'Must specify address.',
754
+ );
755
+ });
756
+
757
+ it('throw error if address is not present in the keyring', async function () {
758
+ await expect(
759
+ keyring.getEncryptionPublicKey(notKeyringAddress),
760
+ ).rejects.toThrow('HD Keyring - Unable to find matching address.');
761
+ });
762
+ });
763
+
764
+ describe('#signTypedData V4 signature verification', function () {
765
+ beforeEach(() => {
766
+ keyring = new HdKeyring({
767
+ mnemonic: sampleMnemonic,
768
+ numberOfAccounts: 1,
769
+ });
770
+ });
771
+
772
+ const expectedSignature =
773
+ '0x220917664ef676d592bd709a5bffedaf69c5f6c72f13c6c4547a41d211f0923c3180893b1dec023433f11b664fabda22b74b57d21094f7798fc85b7650f8edbb1b';
774
+
775
+ it('returns the expected value', async function () {
521
776
  const typedData = {
522
777
  types: {
523
- EIP712Domain: [],
778
+ EIP712Domain: [
779
+ { name: 'name', type: 'string' },
780
+ { name: 'version', type: 'string' },
781
+ { name: 'chainId', type: 'uint256' },
782
+ { name: 'verifyingContract', type: 'address' },
783
+ ],
784
+ Person: [
785
+ { name: 'name', type: 'string' },
786
+ { name: 'wallets', type: 'address[]' },
787
+ ],
788
+ Mail: [
789
+ { name: 'from', type: 'Person' },
790
+ { name: 'to', type: 'Person[]' },
791
+ { name: 'contents', type: 'string' },
792
+ ],
793
+ Group: [
794
+ { name: 'name', type: 'string' },
795
+ { name: 'members', type: 'Person[]' },
796
+ ],
797
+ },
798
+ domain: {
799
+ name: 'Ether Mail',
800
+ version: '1',
801
+ chainId: 1,
802
+ verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
803
+ },
804
+ primaryType: 'Mail',
805
+ message: {
806
+ from: {
807
+ name: 'Cow',
808
+ wallets: [
809
+ '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
810
+ '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
811
+ ],
812
+ },
813
+ to: [
814
+ {
815
+ name: 'Bob',
816
+ wallets: [
817
+ '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
818
+ '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
819
+ '0xB0B0b0b0b0b0B000000000000000000000000000',
820
+ ],
821
+ },
822
+ ],
823
+ contents: 'Hello, Bob!',
524
824
  },
525
- domain: {},
526
- primaryType: 'EIP712Domain',
527
- message: {},
528
825
  };
529
826
 
530
- const privateKey = Buffer.from(
531
- '8e82d2d74c50e5c8460f771d38a560ebe1151a9134c65a7e92b28ad0cfae7151',
532
- 'hex',
533
- );
534
- const expectedSig = signTypedData({
535
- privateKey,
827
+ const addresses = await keyring.getAccounts();
828
+ const [address] = addresses;
829
+
830
+ const signature = await keyring.signTypedData(address, typedData, {
831
+ version: 'V4',
832
+ });
833
+ expect(signature).toBe(expectedSignature);
834
+ const restored = recoverTypedSignature({
536
835
  data: typedData,
537
- version: SignTypedDataVersion.V3,
836
+ signature,
837
+ version: SignTypedDataVersion.V4,
538
838
  });
839
+ expect(restored).toBe(address);
840
+ });
841
+ });
539
842
 
540
- await keyring.deserialize({
843
+ describe('#decryptMessage', function () {
844
+ const message = 'Hello world!';
845
+ let encryptedMessage;
846
+
847
+ beforeEach(async () => {
848
+ keyring = new HdKeyring({
541
849
  mnemonic: sampleMnemonic,
542
850
  numberOfAccounts: 1,
543
851
  });
544
852
 
545
- const sig = await keyring.signTypedData_v3(address, typedData, {
546
- withAppKeyOrigin: 'someapp.origin.io',
853
+ const encryptionPublicKey = await keyring.getEncryptionPublicKey(
854
+ firstAcct,
855
+ );
856
+ encryptedMessage = encrypt({
857
+ publicKey: encryptionPublicKey,
858
+ data: message,
859
+ version: 'x25519-xsalsa20-poly1305',
547
860
  });
548
- expect(sig).toStrictEqual(expectedSig);
861
+ });
862
+
863
+ it('returns the expected value', async function () {
864
+ const decryptedMessage = await keyring.decryptMessage(
865
+ firstAcct,
866
+ encryptedMessage,
867
+ );
868
+ expect(message).toBe(decryptedMessage);
869
+ });
870
+
871
+ it('throw error if address passed is not present in the keyring', async function () {
872
+ await expect(
873
+ keyring.decryptMessage(notKeyringAddress, encryptedMessage),
874
+ ).rejects.toThrow('HD Keyring - Unable to find matching address.');
875
+ });
876
+
877
+ it('throw error if wrong encrypted data object is passed', async function () {
878
+ await expect(keyring.decryptMessage(firstAcct, {})).rejects.toThrow(
879
+ 'Encryption type/version not supported.',
880
+ );
881
+ });
882
+ });
883
+
884
+ describe('#signTransaction', function () {
885
+ beforeEach(() => {
886
+ keyring = new HdKeyring({
887
+ mnemonic: sampleMnemonic,
888
+ numberOfAccounts: 1,
889
+ });
890
+ });
891
+
892
+ const txParams = {
893
+ from: firstAcct,
894
+ nonce: '0x00',
895
+ gasPrice: '0x09184e72a000',
896
+ gasLimit: '0x2710',
897
+ to: firstAcct,
898
+ value: '0x1000',
899
+ };
900
+
901
+ it('returns a signed legacy tx object', async function () {
902
+ const tx = new EthereumTx(txParams);
903
+ expect(tx.isSigned()).toBe(false);
904
+
905
+ const signed = await keyring.signTransaction(firstAcct, tx);
906
+ expect(signed.isSigned()).toBe(true);
907
+ });
908
+
909
+ it('returns a signed tx object', async function () {
910
+ const tx = TransactionFactory.fromTxData(txParams);
911
+ expect(tx.isSigned()).toBe(false);
912
+
913
+ const signed = await keyring.signTransaction(firstAcct, tx);
914
+ expect(signed.isSigned()).toBe(true);
915
+ });
916
+
917
+ it('returns rejected promise if empty address is passed', async function () {
918
+ const tx = TransactionFactory.fromTxData(txParams);
919
+ await expect(keyring.signTransaction('', tx)).rejects.toThrow(
920
+ 'Must specify address.',
921
+ );
922
+ });
923
+
924
+ it('throw error if wrong address is passed', async function () {
925
+ const tx = TransactionFactory.fromTxData(txParams);
926
+ await expect(
927
+ keyring.signTransaction(notKeyringAddress, tx),
928
+ ).rejects.toThrow('HD Keyring - Unable to find matching address.');
549
929
  });
550
930
  });
551
931
  });