@metamask/eth-hd-keyring 6.0.0 → 7.0.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/.eslintrc.js +25 -6
- package/.nvmrc +1 -1
- package/CHANGELOG.md +25 -1
- package/README.md +1 -1
- package/jest.config.js +7 -4
- package/package.json +24 -12
- package/{test/index.js → src/HDKeyring.test.ts} +148 -112
- package/src/HDKeyring.ts +460 -0
- package/src/errors.ts +16 -0
- package/src/index.ts +1 -0
- package/tsconfig.build.json +13 -0
- package/tsconfig.json +16 -0
- package/.yarnrc +0 -1
- package/index.js +0 -311
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
2
|
normalize,
|
|
3
3
|
personalSign,
|
|
4
4
|
recoverPersonalSignature,
|
|
@@ -6,24 +6,27 @@ const {
|
|
|
6
6
|
signTypedData,
|
|
7
7
|
SignTypedDataVersion,
|
|
8
8
|
encrypt,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
EthEncryptedData,
|
|
10
|
+
} from '@metamask/eth-sig-util';
|
|
11
|
+
import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english';
|
|
12
|
+
import { generateMnemonic as oldMMForkBIP39GenerateMnemonic } from '@metamask/bip39';
|
|
13
|
+
import {
|
|
13
14
|
isValidAddress,
|
|
14
15
|
bufferToHex,
|
|
15
16
|
toBuffer,
|
|
16
17
|
ecrecover,
|
|
17
18
|
pubToAddress,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
} from '@ethereumjs/util';
|
|
20
|
+
import { TransactionFactory, Transaction as EthereumTx } from '@ethereumjs/tx';
|
|
21
|
+
import { keccak256 } from 'ethereum-cryptography/keccak';
|
|
22
|
+
import { Eip1024EncryptedData, Hex, add0x, assert } from '@metamask/utils';
|
|
23
|
+
|
|
24
|
+
// we do not want to add this to dependency
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
26
|
+
// @ts-ignore - TS7016: Could not find a declaration file for module
|
|
27
|
+
// eslint-disable-next-line node/no-unpublished-import
|
|
28
|
+
import OldHDKeyring from '@metamask/eth-hd-keyring';
|
|
29
|
+
import { HDKeyring } from './HDKeyring';
|
|
27
30
|
|
|
28
31
|
// Sample account:
|
|
29
32
|
const privKeyHex =
|
|
@@ -39,25 +42,23 @@ const notKeyringAddress = '0xbD20F6F5F1616947a39E11926E78ec94817B3931';
|
|
|
39
42
|
describe('hd-keyring', () => {
|
|
40
43
|
describe('compare old bip39 implementation with new', () => {
|
|
41
44
|
it('should derive the same accounts from the same mnemonics', async () => {
|
|
42
|
-
const mnemonics = [];
|
|
45
|
+
const mnemonics: Buffer[] = [];
|
|
43
46
|
for (let i = 0; i < 99; i++) {
|
|
44
|
-
mnemonics.push(
|
|
47
|
+
mnemonics.push(oldMMForkBIP39GenerateMnemonic());
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
await Promise.all(
|
|
48
51
|
mnemonics.map(async (mnemonic) => {
|
|
49
|
-
const newHDKeyring = new
|
|
50
|
-
const oldHDKeyring = new
|
|
52
|
+
const newHDKeyring = new HDKeyring({ mnemonic, numberOfAccounts: 3 });
|
|
53
|
+
const oldHDKeyring = new OldHDKeyring({
|
|
51
54
|
mnemonic,
|
|
52
55
|
numberOfAccounts: 3,
|
|
53
56
|
});
|
|
54
57
|
const newAccounts = await newHDKeyring.getAccounts();
|
|
55
58
|
const oldAccounts = await oldHDKeyring.getAccounts();
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
await expect(newAccounts[2]).toStrictEqual(oldAccounts[2]);
|
|
59
|
+
expect(newAccounts[0]).toStrictEqual(oldAccounts[0]);
|
|
60
|
+
expect(newAccounts[1]).toStrictEqual(oldAccounts[1]);
|
|
61
|
+
expect(newAccounts[2]).toStrictEqual(oldAccounts[2]);
|
|
61
62
|
}),
|
|
62
63
|
);
|
|
63
64
|
});
|
|
@@ -65,7 +66,7 @@ describe('hd-keyring', () => {
|
|
|
65
66
|
|
|
66
67
|
describe('constructor', () => {
|
|
67
68
|
it('constructs with a typeof string mnemonic', async () => {
|
|
68
|
-
const keyring = new
|
|
69
|
+
const keyring = new HDKeyring({
|
|
69
70
|
mnemonic: sampleMnemonic,
|
|
70
71
|
numberOfAccounts: 2,
|
|
71
72
|
});
|
|
@@ -76,7 +77,7 @@ describe('hd-keyring', () => {
|
|
|
76
77
|
});
|
|
77
78
|
|
|
78
79
|
it('constructs with a typeof buffer mnemonic', async () => {
|
|
79
|
-
const keyring = new
|
|
80
|
+
const keyring = new HDKeyring({
|
|
80
81
|
mnemonic: Buffer.from(sampleMnemonic, 'utf8'),
|
|
81
82
|
numberOfAccounts: 2,
|
|
82
83
|
});
|
|
@@ -93,7 +94,7 @@ describe('hd-keyring', () => {
|
|
|
93
94
|
const uInt8ArrayOfMnemonic = new Uint8Array(
|
|
94
95
|
new Uint16Array(indices).buffer,
|
|
95
96
|
);
|
|
96
|
-
const keyring = new
|
|
97
|
+
const keyring = new HDKeyring({
|
|
97
98
|
mnemonic: uInt8ArrayOfMnemonic,
|
|
98
99
|
numberOfAccounts: 2,
|
|
99
100
|
});
|
|
@@ -103,23 +104,35 @@ describe('hd-keyring', () => {
|
|
|
103
104
|
expect(accounts[1]).toStrictEqual(secondAcct);
|
|
104
105
|
});
|
|
105
106
|
|
|
107
|
+
it('constructs with jscasted buffer', async () => {
|
|
108
|
+
const jscastedBuffer = Buffer.from(sampleMnemonic).toJSON();
|
|
109
|
+
const keyring = new HDKeyring({
|
|
110
|
+
mnemonic: jscastedBuffer,
|
|
111
|
+
numberOfAccounts: 2,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const accounts = await keyring.getAccounts();
|
|
115
|
+
expect(accounts[0]).toStrictEqual(firstAcct);
|
|
116
|
+
expect(accounts[1]).toStrictEqual(secondAcct);
|
|
117
|
+
});
|
|
118
|
+
|
|
106
119
|
it('throws on invalid mnemonic', () => {
|
|
107
120
|
expect(
|
|
108
121
|
() =>
|
|
109
|
-
new
|
|
122
|
+
new HDKeyring({
|
|
110
123
|
mnemonic: 'abc xyz',
|
|
111
124
|
numberOfAccounts: 2,
|
|
112
125
|
}),
|
|
113
126
|
).toThrow('Eth-Hd-Keyring: Invalid secret recovery phrase provided');
|
|
114
127
|
});
|
|
115
128
|
|
|
116
|
-
it('throws when numberOfAccounts is passed with no mnemonic', () => {
|
|
117
|
-
expect(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
).toThrow(
|
|
129
|
+
it('throws when numberOfAccounts is passed with no mnemonic', async () => {
|
|
130
|
+
expect(() => {
|
|
131
|
+
// eslint-disable-next-line no-new
|
|
132
|
+
new HDKeyring({
|
|
133
|
+
numberOfAccounts: 1,
|
|
134
|
+
});
|
|
135
|
+
}).toThrow(
|
|
123
136
|
'Eth-Hd-Keyring: Deserialize method cannot be called with an opts value for numberOfAccounts and no menmonic',
|
|
124
137
|
);
|
|
125
138
|
});
|
|
@@ -129,7 +142,7 @@ describe('hd-keyring', () => {
|
|
|
129
142
|
const alreadyProvidedError =
|
|
130
143
|
'Eth-Hd-Keyring: Secret recovery phrase already provided';
|
|
131
144
|
it('double generateRandomMnemonic', () => {
|
|
132
|
-
const keyring = new
|
|
145
|
+
const keyring = new HDKeyring();
|
|
133
146
|
keyring.generateRandomMnemonic();
|
|
134
147
|
expect(() => {
|
|
135
148
|
keyring.generateRandomMnemonic();
|
|
@@ -137,7 +150,7 @@ describe('hd-keyring', () => {
|
|
|
137
150
|
});
|
|
138
151
|
|
|
139
152
|
it('constructor + generateRandomMnemonic', () => {
|
|
140
|
-
const keyring = new
|
|
153
|
+
const keyring = new HDKeyring({
|
|
141
154
|
mnemonic: sampleMnemonic,
|
|
142
155
|
numberOfAccounts: 2,
|
|
143
156
|
});
|
|
@@ -148,12 +161,13 @@ describe('hd-keyring', () => {
|
|
|
148
161
|
});
|
|
149
162
|
|
|
150
163
|
it('constructor + deserialize', () => {
|
|
151
|
-
const keyring = new
|
|
164
|
+
const keyring = new HDKeyring({
|
|
152
165
|
mnemonic: sampleMnemonic,
|
|
153
166
|
numberOfAccounts: 2,
|
|
154
167
|
});
|
|
155
168
|
|
|
156
169
|
expect(() => {
|
|
170
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
157
171
|
keyring.deserialize({
|
|
158
172
|
mnemonic: sampleMnemonic,
|
|
159
173
|
numberOfAccounts: 1,
|
|
@@ -164,28 +178,28 @@ describe('hd-keyring', () => {
|
|
|
164
178
|
|
|
165
179
|
describe('Keyring.type', () => {
|
|
166
180
|
it('is a class property that returns the type string.', () => {
|
|
167
|
-
const { type } =
|
|
181
|
+
const { type } = HDKeyring;
|
|
168
182
|
expect(typeof type).toBe('string');
|
|
169
183
|
});
|
|
170
184
|
});
|
|
171
185
|
|
|
172
186
|
describe('#type', () => {
|
|
173
187
|
it('returns the correct value', () => {
|
|
174
|
-
const keyring = new
|
|
188
|
+
const keyring = new HDKeyring();
|
|
175
189
|
|
|
176
190
|
const { type } = keyring;
|
|
177
|
-
const correct =
|
|
191
|
+
const correct = HDKeyring.type;
|
|
178
192
|
expect(type).toStrictEqual(correct);
|
|
179
193
|
});
|
|
180
194
|
});
|
|
181
195
|
|
|
182
196
|
describe('#serialize mnemonic.', () => {
|
|
183
197
|
it('serializes the mnemonic in the same format as previous version (an array of utf8 encoded bytes)', async () => {
|
|
184
|
-
const keyring = new
|
|
198
|
+
const keyring = new HDKeyring({
|
|
185
199
|
mnemonic: sampleMnemonic,
|
|
186
200
|
});
|
|
187
201
|
// uses previous version of eth-hd-keyring to ensure backwards compatibility
|
|
188
|
-
const oldHDKeyring = new
|
|
202
|
+
const oldHDKeyring = new OldHDKeyring({ mnemonic: sampleMnemonic });
|
|
189
203
|
const { mnemonic: oldKeyringSerializedMnemonic } =
|
|
190
204
|
await oldHDKeyring.serialize();
|
|
191
205
|
|
|
@@ -194,7 +208,7 @@ describe('hd-keyring', () => {
|
|
|
194
208
|
});
|
|
195
209
|
|
|
196
210
|
it('serializes mnemonic passed in as a string to an array of utf8 encoded bytes', async () => {
|
|
197
|
-
const keyring = new
|
|
211
|
+
const keyring = new HDKeyring({
|
|
198
212
|
mnemonic: sampleMnemonic,
|
|
199
213
|
});
|
|
200
214
|
const output = await keyring.serialize();
|
|
@@ -204,9 +218,9 @@ describe('hd-keyring', () => {
|
|
|
204
218
|
});
|
|
205
219
|
|
|
206
220
|
it('serializes mnemonic passed in as a an array of utf8 encoded bytes in the same format', async () => {
|
|
207
|
-
const uint8Array = new TextEncoder(
|
|
221
|
+
const uint8Array = new TextEncoder().encode(sampleMnemonic);
|
|
208
222
|
const mnemonicAsArrayOfUtf8EncodedBytes = Array.from(uint8Array);
|
|
209
|
-
const keyring = new
|
|
223
|
+
const keyring = new HDKeyring({
|
|
210
224
|
mnemonic: mnemonicAsArrayOfUtf8EncodedBytes,
|
|
211
225
|
});
|
|
212
226
|
|
|
@@ -215,11 +229,18 @@ describe('hd-keyring', () => {
|
|
|
215
229
|
const mnemonicAsString = Buffer.from(output.mnemonic).toString();
|
|
216
230
|
expect(mnemonicAsString).toStrictEqual(sampleMnemonic);
|
|
217
231
|
});
|
|
232
|
+
|
|
233
|
+
it('throws if mnemnoic is not set', async () => {
|
|
234
|
+
const keyring = new HDKeyring({});
|
|
235
|
+
await expect(keyring.serialize()).rejects.toThrow(
|
|
236
|
+
'Eth-Hd-Keyring: Missing mnemonic when serializing',
|
|
237
|
+
);
|
|
238
|
+
});
|
|
218
239
|
});
|
|
219
240
|
|
|
220
241
|
describe('#deserialize a private key', () => {
|
|
221
242
|
it('serializes what it deserializes', async () => {
|
|
222
|
-
const keyring = new
|
|
243
|
+
const keyring = new HDKeyring();
|
|
223
244
|
await keyring.deserialize({
|
|
224
245
|
mnemonic: sampleMnemonic,
|
|
225
246
|
numberOfAccounts: 1,
|
|
@@ -242,7 +263,7 @@ describe('hd-keyring', () => {
|
|
|
242
263
|
describe('#addAccounts', () => {
|
|
243
264
|
describe('with no arguments', () => {
|
|
244
265
|
it('creates a single wallet', async () => {
|
|
245
|
-
const keyring = new
|
|
266
|
+
const keyring = new HDKeyring();
|
|
246
267
|
keyring.generateRandomMnemonic();
|
|
247
268
|
await keyring.addAccounts();
|
|
248
269
|
const accounts = await keyring.getAccounts();
|
|
@@ -250,8 +271,8 @@ describe('hd-keyring', () => {
|
|
|
250
271
|
});
|
|
251
272
|
|
|
252
273
|
it('throws an error when no SRP has been generated yet', async () => {
|
|
253
|
-
const keyring = new
|
|
254
|
-
expect(
|
|
274
|
+
const keyring = new HDKeyring();
|
|
275
|
+
await expect(keyring.addAccounts()).rejects.toThrow(
|
|
255
276
|
'Eth-Hd-Keyring: No secret recovery phrase provided',
|
|
256
277
|
);
|
|
257
278
|
});
|
|
@@ -259,7 +280,7 @@ describe('hd-keyring', () => {
|
|
|
259
280
|
|
|
260
281
|
describe('with a numeric argument', () => {
|
|
261
282
|
it('creates that number of wallets', async () => {
|
|
262
|
-
const keyring = new
|
|
283
|
+
const keyring = new HDKeyring();
|
|
263
284
|
keyring.generateRandomMnemonic();
|
|
264
285
|
await keyring.addAccounts(3);
|
|
265
286
|
const accounts = await keyring.getAccounts();
|
|
@@ -270,7 +291,7 @@ describe('hd-keyring', () => {
|
|
|
270
291
|
|
|
271
292
|
describe('#signPersonalMessage', () => {
|
|
272
293
|
it('returns the expected value', async () => {
|
|
273
|
-
const keyring = new
|
|
294
|
+
const keyring = new HDKeyring();
|
|
274
295
|
|
|
275
296
|
const address = firstAcct;
|
|
276
297
|
const message = '0x68656c6c6f20776f726c64';
|
|
@@ -293,7 +314,7 @@ describe('hd-keyring', () => {
|
|
|
293
314
|
|
|
294
315
|
describe('#signTypedData', () => {
|
|
295
316
|
it('can recover a basic signature', async () => {
|
|
296
|
-
const keyring = new
|
|
317
|
+
const keyring = new HDKeyring();
|
|
297
318
|
Buffer.from(privKeyHex, 'hex');
|
|
298
319
|
const typedData = [
|
|
299
320
|
{
|
|
@@ -304,8 +325,9 @@ describe('hd-keyring', () => {
|
|
|
304
325
|
];
|
|
305
326
|
keyring.generateRandomMnemonic();
|
|
306
327
|
await keyring.addAccounts(1);
|
|
307
|
-
const
|
|
308
|
-
|
|
328
|
+
const [rawAddress] = await keyring.getAccounts();
|
|
329
|
+
assert(rawAddress, 'addresses is empty');
|
|
330
|
+
const address = add0x(rawAddress);
|
|
309
331
|
const signature = await keyring.signTypedData(address, typedData);
|
|
310
332
|
const restored = recoverTypedSignature({
|
|
311
333
|
data: typedData,
|
|
@@ -326,11 +348,12 @@ describe('hd-keyring', () => {
|
|
|
326
348
|
];
|
|
327
349
|
|
|
328
350
|
it('signs in a compliant and recoverable way', async () => {
|
|
329
|
-
const keyring = new
|
|
351
|
+
const keyring = new HDKeyring();
|
|
330
352
|
keyring.generateRandomMnemonic();
|
|
331
353
|
await keyring.addAccounts(1);
|
|
332
|
-
const
|
|
333
|
-
|
|
354
|
+
const [rawAddress] = await keyring.getAccounts();
|
|
355
|
+
assert(rawAddress, 'addresses is empty');
|
|
356
|
+
const address = add0x(rawAddress);
|
|
334
357
|
const signature = await keyring.signTypedData(address, typedData, {
|
|
335
358
|
version: SignTypedDataVersion.V1,
|
|
336
359
|
});
|
|
@@ -345,13 +368,13 @@ describe('hd-keyring', () => {
|
|
|
345
368
|
|
|
346
369
|
describe('#signTypedData_v3', () => {
|
|
347
370
|
it('signs in a compliant and recoverable way', async () => {
|
|
348
|
-
const keyring = new
|
|
371
|
+
const keyring = new HDKeyring();
|
|
349
372
|
const typedData = {
|
|
350
373
|
types: {
|
|
351
374
|
EIP712Domain: [],
|
|
352
375
|
},
|
|
353
376
|
domain: {},
|
|
354
|
-
primaryType: 'EIP712Domain',
|
|
377
|
+
primaryType: 'EIP712Domain' as const,
|
|
355
378
|
message: {},
|
|
356
379
|
};
|
|
357
380
|
|
|
@@ -359,8 +382,9 @@ describe('hd-keyring', () => {
|
|
|
359
382
|
mnemonic: sampleMnemonic,
|
|
360
383
|
numberOfAccounts: 1,
|
|
361
384
|
});
|
|
362
|
-
const
|
|
363
|
-
|
|
385
|
+
const [rawAddress] = await keyring.getAccounts();
|
|
386
|
+
assert(rawAddress, 'addresses is empty');
|
|
387
|
+
const address = add0x(rawAddress);
|
|
364
388
|
const signature = await keyring.signTypedData(address, typedData, {
|
|
365
389
|
version: SignTypedDataVersion.V3,
|
|
366
390
|
});
|
|
@@ -375,7 +399,7 @@ describe('hd-keyring', () => {
|
|
|
375
399
|
|
|
376
400
|
describe('#signTypedData_v3 signature verification', () => {
|
|
377
401
|
it('signs in a recoverable way.', async () => {
|
|
378
|
-
const keyring = new
|
|
402
|
+
const keyring = new HDKeyring();
|
|
379
403
|
const typedData = {
|
|
380
404
|
types: {
|
|
381
405
|
EIP712Domain: [
|
|
@@ -394,7 +418,7 @@ describe('hd-keyring', () => {
|
|
|
394
418
|
{ name: 'contents', type: 'string' },
|
|
395
419
|
],
|
|
396
420
|
},
|
|
397
|
-
primaryType: 'Mail',
|
|
421
|
+
primaryType: 'Mail' as const,
|
|
398
422
|
domain: {
|
|
399
423
|
name: 'Ether Mail',
|
|
400
424
|
version: '1',
|
|
@@ -416,8 +440,9 @@ describe('hd-keyring', () => {
|
|
|
416
440
|
|
|
417
441
|
keyring.generateRandomMnemonic();
|
|
418
442
|
await keyring.addAccounts(1);
|
|
419
|
-
const
|
|
420
|
-
|
|
443
|
+
const [rawAddress] = await keyring.getAccounts();
|
|
444
|
+
assert(rawAddress, 'addresses is empty');
|
|
445
|
+
const address = add0x(rawAddress);
|
|
421
446
|
const signature = await keyring.signTypedData(address, typedData, {
|
|
422
447
|
version: SignTypedDataVersion.V3,
|
|
423
448
|
});
|
|
@@ -432,9 +457,9 @@ describe('hd-keyring', () => {
|
|
|
432
457
|
|
|
433
458
|
describe('custom hd paths', () => {
|
|
434
459
|
it('can deserialize with an hdPath param and generate the same accounts.', async () => {
|
|
435
|
-
const keyring = new
|
|
460
|
+
const keyring = new HDKeyring();
|
|
436
461
|
const hdPathString = `m/44'/60'/0'/0`;
|
|
437
|
-
keyring.deserialize({
|
|
462
|
+
await keyring.deserialize({
|
|
438
463
|
mnemonic: sampleMnemonic,
|
|
439
464
|
numberOfAccounts: 1,
|
|
440
465
|
hdPath: hdPathString,
|
|
@@ -446,9 +471,9 @@ describe('hd-keyring', () => {
|
|
|
446
471
|
});
|
|
447
472
|
|
|
448
473
|
it('can deserialize with an hdPath param and generate different accounts.', async () => {
|
|
449
|
-
const keyring = new
|
|
474
|
+
const keyring = new HDKeyring();
|
|
450
475
|
const hdPathString = `m/44'/60'/0'/1`;
|
|
451
|
-
keyring.deserialize({
|
|
476
|
+
await keyring.deserialize({
|
|
452
477
|
mnemonic: sampleMnemonic,
|
|
453
478
|
numberOfAccounts: 1,
|
|
454
479
|
hdPath: hdPathString,
|
|
@@ -468,14 +493,14 @@ describe('hd-keyring', () => {
|
|
|
468
493
|
|
|
469
494
|
for (let i = 0; i < 1e3; i++) {
|
|
470
495
|
|
|
471
|
-
const keyring = new
|
|
496
|
+
const keyring = new HDKeyring({
|
|
472
497
|
numberOfAccounts: 1,
|
|
473
498
|
})
|
|
474
499
|
const originalAccounts = await keyring.getAccounts()
|
|
475
500
|
const serialized = await keyring.serialize()
|
|
476
501
|
const mnemonic = serialized.mnemonic
|
|
477
502
|
|
|
478
|
-
const keyring = new
|
|
503
|
+
const keyring = new HDKeyring({
|
|
479
504
|
numberOfAccounts: 1,
|
|
480
505
|
mnemonic,
|
|
481
506
|
})
|
|
@@ -495,7 +520,7 @@ describe('hd-keyring', () => {
|
|
|
495
520
|
|
|
496
521
|
describe('signing methods withAppKeyOrigin option', () => {
|
|
497
522
|
it('should signPersonalMessage with the expected key when passed a withAppKeyOrigin', async () => {
|
|
498
|
-
const keyring = new
|
|
523
|
+
const keyring = new HDKeyring();
|
|
499
524
|
const address = firstAcct;
|
|
500
525
|
const message = '0x68656c6c6f20776f726c64';
|
|
501
526
|
|
|
@@ -517,14 +542,14 @@ describe('hd-keyring', () => {
|
|
|
517
542
|
});
|
|
518
543
|
|
|
519
544
|
it('should signTypedData with the expected key when passed a withAppKeyOrigin', async () => {
|
|
520
|
-
const keyring = new
|
|
545
|
+
const keyring = new HDKeyring();
|
|
521
546
|
const address = firstAcct;
|
|
522
547
|
const typedData = {
|
|
523
548
|
types: {
|
|
524
549
|
EIP712Domain: [],
|
|
525
550
|
},
|
|
526
551
|
domain: {},
|
|
527
|
-
primaryType: 'EIP712Domain',
|
|
552
|
+
primaryType: 'EIP712Domain' as const,
|
|
528
553
|
message: {},
|
|
529
554
|
};
|
|
530
555
|
|
|
@@ -562,7 +587,7 @@ describe('hd-keyring', () => {
|
|
|
562
587
|
'0xb21867b2221db0172e970b7370825b71c57823ff8714168ce9748f32f450e2c43d0fe396eb5b5f59284b7fd108c8cf61a6180a6756bdd3d4b7b9ccc4ac6d51611b';
|
|
563
588
|
|
|
564
589
|
it('passes the dennis test', async function () {
|
|
565
|
-
const keyring = new
|
|
590
|
+
const keyring = new HDKeyring();
|
|
566
591
|
await keyring.deserialize({
|
|
567
592
|
mnemonic: sampleMnemonic,
|
|
568
593
|
numberOfAccounts: 1,
|
|
@@ -572,17 +597,19 @@ describe('hd-keyring', () => {
|
|
|
572
597
|
});
|
|
573
598
|
|
|
574
599
|
it('reliably can decode messages it signs', async function () {
|
|
575
|
-
const keyring = new
|
|
600
|
+
const keyring = new HDKeyring();
|
|
576
601
|
await keyring.deserialize({
|
|
577
602
|
mnemonic: sampleMnemonic,
|
|
578
603
|
numberOfAccounts: 1,
|
|
579
604
|
});
|
|
580
605
|
const localMessage = 'hello there!';
|
|
581
|
-
const msgHashHex = bufferToHex(
|
|
606
|
+
const msgHashHex = bufferToHex(
|
|
607
|
+
Buffer.from(keccak256(Buffer.from(localMessage))),
|
|
608
|
+
) as Hex;
|
|
582
609
|
await keyring.addAccounts(9);
|
|
583
610
|
const addresses = await keyring.getAccounts();
|
|
584
611
|
const signatures = await Promise.all(
|
|
585
|
-
addresses.map(async (accountAddress) => {
|
|
612
|
+
addresses.map(async (accountAddress: Hex) => {
|
|
586
613
|
return await keyring.signMessage(accountAddress, msgHashHex);
|
|
587
614
|
}),
|
|
588
615
|
);
|
|
@@ -601,31 +628,32 @@ describe('hd-keyring', () => {
|
|
|
601
628
|
});
|
|
602
629
|
|
|
603
630
|
it('throw error for invalid message', async function () {
|
|
604
|
-
const keyring = new
|
|
631
|
+
const keyring = new HDKeyring();
|
|
605
632
|
await keyring.deserialize({
|
|
606
633
|
mnemonic: sampleMnemonic,
|
|
607
634
|
numberOfAccounts: 1,
|
|
608
635
|
});
|
|
609
636
|
|
|
610
637
|
await expect(keyring.signMessage(firstAcct, '')).rejects.toThrow(
|
|
611
|
-
'
|
|
638
|
+
'Value must be a hexadecimal string',
|
|
612
639
|
);
|
|
613
640
|
});
|
|
614
641
|
|
|
615
642
|
it('throw error if empty address is passed', async function () {
|
|
616
|
-
const keyring = new
|
|
643
|
+
const keyring = new HDKeyring();
|
|
617
644
|
await keyring.deserialize({
|
|
618
645
|
mnemonic: sampleMnemonic,
|
|
619
646
|
numberOfAccounts: 1,
|
|
620
647
|
});
|
|
621
648
|
|
|
649
|
+
// @ts-expect-error we inputting an invalid address
|
|
622
650
|
await expect(keyring.signMessage('', message)).rejects.toThrow(
|
|
623
651
|
'Must specify address.',
|
|
624
652
|
);
|
|
625
653
|
});
|
|
626
654
|
|
|
627
655
|
it('throw error if address not associated with the current keyring is passed', async function () {
|
|
628
|
-
const keyring = new
|
|
656
|
+
const keyring = new HDKeyring();
|
|
629
657
|
await keyring.deserialize({
|
|
630
658
|
mnemonic: sampleMnemonic,
|
|
631
659
|
numberOfAccounts: 1,
|
|
@@ -633,14 +661,14 @@ describe('hd-keyring', () => {
|
|
|
633
661
|
|
|
634
662
|
await expect(
|
|
635
663
|
keyring.signMessage(notKeyringAddress, message),
|
|
636
|
-
).rejects.toThrow('
|
|
664
|
+
).rejects.toThrow('Eth-Hd-Keyring: Unable to find matching address.');
|
|
637
665
|
});
|
|
638
666
|
});
|
|
639
667
|
|
|
640
668
|
describe('#removeAccount', function () {
|
|
641
|
-
let keyring;
|
|
669
|
+
let keyring: HDKeyring;
|
|
642
670
|
beforeEach(() => {
|
|
643
|
-
keyring = new
|
|
671
|
+
keyring = new HDKeyring({
|
|
644
672
|
mnemonic: sampleMnemonic,
|
|
645
673
|
numberOfAccounts: 1,
|
|
646
674
|
});
|
|
@@ -648,9 +676,12 @@ describe('hd-keyring', () => {
|
|
|
648
676
|
|
|
649
677
|
describe('if the account exists', function () {
|
|
650
678
|
it('should remove that account', async function () {
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
679
|
+
const rawAddresses = await keyring.getAccounts();
|
|
680
|
+
const [rawAddress] = rawAddresses;
|
|
681
|
+
expect(rawAddresses).toHaveLength(1);
|
|
682
|
+
assert(rawAddress, 'rawAddress should be empty');
|
|
683
|
+
const address = add0x(rawAddress);
|
|
684
|
+
keyring.removeAccount(address);
|
|
654
685
|
const addressesAfterRemoval = await keyring.getAccounts();
|
|
655
686
|
expect(addressesAfterRemoval).toHaveLength(0);
|
|
656
687
|
});
|
|
@@ -667,9 +698,9 @@ describe('hd-keyring', () => {
|
|
|
667
698
|
});
|
|
668
699
|
|
|
669
700
|
describe('getAppKeyAddress', function () {
|
|
670
|
-
let keyring;
|
|
701
|
+
let keyring: HDKeyring;
|
|
671
702
|
beforeEach(() => {
|
|
672
|
-
keyring = new
|
|
703
|
+
keyring = new HDKeyring({
|
|
673
704
|
mnemonic: sampleMnemonic,
|
|
674
705
|
numberOfAccounts: 1,
|
|
675
706
|
});
|
|
@@ -720,6 +751,7 @@ describe('hd-keyring', () => {
|
|
|
720
751
|
});
|
|
721
752
|
|
|
722
753
|
it('should throw error if the provided origin is not a string', async function () {
|
|
754
|
+
// @ts-expect-error we are providing an incorrect origin key
|
|
723
755
|
await expect(keyring.getAppKeyAddress(firstAcct, [])).rejects.toThrow(
|
|
724
756
|
`'origin' must be a non-empty string`,
|
|
725
757
|
);
|
|
@@ -733,9 +765,9 @@ describe('hd-keyring', () => {
|
|
|
733
765
|
});
|
|
734
766
|
|
|
735
767
|
describe('exportAccount', function () {
|
|
736
|
-
let keyring;
|
|
768
|
+
let keyring: HDKeyring;
|
|
737
769
|
beforeEach(() => {
|
|
738
|
-
keyring = new
|
|
770
|
+
keyring = new HDKeyring({
|
|
739
771
|
mnemonic: sampleMnemonic,
|
|
740
772
|
numberOfAccounts: 1,
|
|
741
773
|
});
|
|
@@ -751,16 +783,16 @@ describe('hd-keyring', () => {
|
|
|
751
783
|
|
|
752
784
|
it('throw error if account is not present', async function () {
|
|
753
785
|
await expect(keyring.exportAccount(notKeyringAddress)).rejects.toThrow(
|
|
754
|
-
'
|
|
786
|
+
'Eth-Hd-Keyring: Unable to find matching address.',
|
|
755
787
|
);
|
|
756
788
|
});
|
|
757
789
|
});
|
|
758
790
|
|
|
759
791
|
describe('#encryptionPublicKey', function () {
|
|
760
792
|
const publicKey = 'LV7lWhd0mUDcvxkMU2o6uKXftu25zq4bMYdmMqppXic=';
|
|
761
|
-
let keyring;
|
|
793
|
+
let keyring: HDKeyring;
|
|
762
794
|
beforeEach(() => {
|
|
763
|
-
keyring = new
|
|
795
|
+
keyring = new HDKeyring({
|
|
764
796
|
mnemonic: sampleMnemonic,
|
|
765
797
|
numberOfAccounts: 1,
|
|
766
798
|
});
|
|
@@ -774,6 +806,7 @@ describe('hd-keyring', () => {
|
|
|
774
806
|
});
|
|
775
807
|
|
|
776
808
|
it('throw error if address is blank', async function () {
|
|
809
|
+
// @ts-expect-error provide an invalid key
|
|
777
810
|
await expect(keyring.getEncryptionPublicKey('')).rejects.toThrow(
|
|
778
811
|
'Must specify address.',
|
|
779
812
|
);
|
|
@@ -782,14 +815,14 @@ describe('hd-keyring', () => {
|
|
|
782
815
|
it('throw error if address is not present in the keyring', async function () {
|
|
783
816
|
await expect(
|
|
784
817
|
keyring.getEncryptionPublicKey(notKeyringAddress),
|
|
785
|
-
).rejects.toThrow('
|
|
818
|
+
).rejects.toThrow('Eth-Hd-Keyring: Unable to find matching address.');
|
|
786
819
|
});
|
|
787
820
|
});
|
|
788
821
|
|
|
789
822
|
describe('#signTypedData V4 signature verification', function () {
|
|
790
|
-
let keyring;
|
|
823
|
+
let keyring: HDKeyring;
|
|
791
824
|
beforeEach(() => {
|
|
792
|
-
keyring = new
|
|
825
|
+
keyring = new HDKeyring({
|
|
793
826
|
mnemonic: sampleMnemonic,
|
|
794
827
|
numberOfAccounts: 1,
|
|
795
828
|
});
|
|
@@ -827,7 +860,7 @@ describe('hd-keyring', () => {
|
|
|
827
860
|
chainId: 1,
|
|
828
861
|
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
|
|
829
862
|
},
|
|
830
|
-
primaryType: 'Mail',
|
|
863
|
+
primaryType: 'Mail' as const,
|
|
831
864
|
message: {
|
|
832
865
|
from: {
|
|
833
866
|
name: 'Cow',
|
|
@@ -853,8 +886,8 @@ describe('hd-keyring', () => {
|
|
|
853
886
|
const addresses = await keyring.getAccounts();
|
|
854
887
|
const [address] = addresses;
|
|
855
888
|
|
|
856
|
-
const signature = await keyring.signTypedData(address, typedData, {
|
|
857
|
-
version:
|
|
889
|
+
const signature = await keyring.signTypedData(address as Hex, typedData, {
|
|
890
|
+
version: SignTypedDataVersion.V4,
|
|
858
891
|
});
|
|
859
892
|
expect(signature).toBe(expectedSignature);
|
|
860
893
|
const restored = recoverTypedSignature({
|
|
@@ -868,10 +901,10 @@ describe('hd-keyring', () => {
|
|
|
868
901
|
|
|
869
902
|
describe('#decryptMessage', function () {
|
|
870
903
|
const message = 'Hello world!';
|
|
871
|
-
let encryptedMessage, keyring;
|
|
904
|
+
let encryptedMessage: EthEncryptedData, keyring: HDKeyring;
|
|
872
905
|
|
|
873
906
|
beforeEach(async () => {
|
|
874
|
-
keyring = new
|
|
907
|
+
keyring = new HDKeyring({
|
|
875
908
|
mnemonic: sampleMnemonic,
|
|
876
909
|
numberOfAccounts: 1,
|
|
877
910
|
});
|
|
@@ -897,20 +930,20 @@ describe('hd-keyring', () => {
|
|
|
897
930
|
it('throw error if address passed is not present in the keyring', async function () {
|
|
898
931
|
await expect(
|
|
899
932
|
keyring.decryptMessage(notKeyringAddress, encryptedMessage),
|
|
900
|
-
).rejects.toThrow('
|
|
933
|
+
).rejects.toThrow('Eth-Hd-Keyring: Unable to find matching address.');
|
|
901
934
|
});
|
|
902
935
|
|
|
903
936
|
it('throw error if wrong encrypted data object is passed', async function () {
|
|
904
|
-
await expect(
|
|
905
|
-
|
|
906
|
-
);
|
|
937
|
+
await expect(
|
|
938
|
+
keyring.decryptMessage(firstAcct, {} as Eip1024EncryptedData),
|
|
939
|
+
).rejects.toThrow('Encryption type/version not supported.');
|
|
907
940
|
});
|
|
908
941
|
});
|
|
909
942
|
|
|
910
943
|
describe('#signTransaction', function () {
|
|
911
|
-
let keyring;
|
|
944
|
+
let keyring: HDKeyring;
|
|
912
945
|
beforeEach(() => {
|
|
913
|
-
keyring = new
|
|
946
|
+
keyring = new HDKeyring({
|
|
914
947
|
mnemonic: sampleMnemonic,
|
|
915
948
|
numberOfAccounts: 1,
|
|
916
949
|
});
|
|
@@ -930,7 +963,8 @@ describe('hd-keyring', () => {
|
|
|
930
963
|
expect(tx.isSigned()).toBe(false);
|
|
931
964
|
|
|
932
965
|
const signed = await keyring.signTransaction(firstAcct, tx);
|
|
933
|
-
|
|
966
|
+
const signedTx = TransactionFactory.fromTxData(signed);
|
|
967
|
+
expect(signedTx.isSigned()).toBe(true);
|
|
934
968
|
});
|
|
935
969
|
|
|
936
970
|
it('returns a signed tx object', async function () {
|
|
@@ -938,11 +972,13 @@ describe('hd-keyring', () => {
|
|
|
938
972
|
expect(tx.isSigned()).toBe(false);
|
|
939
973
|
|
|
940
974
|
const signed = await keyring.signTransaction(firstAcct, tx);
|
|
941
|
-
|
|
975
|
+
const signedTx = TransactionFactory.fromTxData(signed);
|
|
976
|
+
expect(signedTx.isSigned()).toBe(true);
|
|
942
977
|
});
|
|
943
978
|
|
|
944
979
|
it('returns rejected promise if empty address is passed', async function () {
|
|
945
980
|
const tx = TransactionFactory.fromTxData(txParams);
|
|
981
|
+
// @ts-expect-error provide invalid address
|
|
946
982
|
await expect(keyring.signTransaction('', tx)).rejects.toThrow(
|
|
947
983
|
'Must specify address.',
|
|
948
984
|
);
|
|
@@ -952,7 +988,7 @@ describe('hd-keyring', () => {
|
|
|
952
988
|
const tx = TransactionFactory.fromTxData(txParams);
|
|
953
989
|
await expect(
|
|
954
990
|
keyring.signTransaction(notKeyringAddress, tx),
|
|
955
|
-
).rejects.toThrow('
|
|
991
|
+
).rejects.toThrow('Eth-Hd-Keyring: Unable to find matching address.');
|
|
956
992
|
});
|
|
957
993
|
});
|
|
958
994
|
});
|