@metamask/eth-hd-keyring 6.0.1 → 6.0.2
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 +6 -25
- package/.github/CODEOWNERS +4 -0
- package/.github/workflows/build-lint-test.yml +73 -0
- package/.github/workflows/create-release-pr.yml +41 -0
- package/.github/workflows/main.yml +70 -0
- package/.github/workflows/publish-release.yml +50 -0
- package/.yarn/releases/yarn-3.3.0.cjs +807 -0
- package/.yarnrc.yml +15 -0
- package/CHANGELOG.md +7 -5
- package/index.js +311 -0
- package/jest.config.js +4 -7
- package/package.json +7 -17
- package/{src/HDKeyring.test.ts → test/index.js} +111 -147
- package/src/HDKeyring.ts +0 -459
- package/src/errors.ts +0 -16
- package/src/index.ts +0 -1
- package/tsconfig.build.json +0 -13
- package/tsconfig.json +0 -16
package/src/HDKeyring.ts
DELETED
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
import { HDKey } from 'ethereum-cryptography/hdkey';
|
|
2
|
-
import { keccak256 } from 'ethereum-cryptography/keccak';
|
|
3
|
-
import { bytesToHex } from 'ethereum-cryptography/utils';
|
|
4
|
-
import {
|
|
5
|
-
stripHexPrefix,
|
|
6
|
-
privateToPublic,
|
|
7
|
-
publicToAddress,
|
|
8
|
-
ecsign,
|
|
9
|
-
arrToBufArr,
|
|
10
|
-
bufferToHex,
|
|
11
|
-
ECDSASignature,
|
|
12
|
-
} from '@ethereumjs/util';
|
|
13
|
-
|
|
14
|
-
import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english';
|
|
15
|
-
import {
|
|
16
|
-
concatSig,
|
|
17
|
-
decrypt,
|
|
18
|
-
getEncryptionPublicKey,
|
|
19
|
-
normalize,
|
|
20
|
-
personalSign,
|
|
21
|
-
signTypedData,
|
|
22
|
-
SignTypedDataVersion,
|
|
23
|
-
TypedDataV1,
|
|
24
|
-
TypedMessage,
|
|
25
|
-
} from '@metamask/eth-sig-util';
|
|
26
|
-
import { Hex, Keyring, Eip1024EncryptedData } from '@metamask/utils';
|
|
27
|
-
import { TxData, TypedTransaction } from '@ethereumjs/tx';
|
|
28
|
-
import { HDKeyringErrors } from './errors';
|
|
29
|
-
|
|
30
|
-
// TODO: Find out why when imported usin ES6, mnemonic changes
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
|
32
|
-
const bip39 = require('@metamask/scure-bip39');
|
|
33
|
-
|
|
34
|
-
type JsCastedBuffer = {
|
|
35
|
-
type: string;
|
|
36
|
-
data: any;
|
|
37
|
-
};
|
|
38
|
-
type KeyringOpt = {
|
|
39
|
-
mnemonic?: Buffer | JsCastedBuffer | string | Uint8Array | number[];
|
|
40
|
-
numberOfAccounts?: number;
|
|
41
|
-
hdPath?: string;
|
|
42
|
-
withAppKeyOrigin?: string;
|
|
43
|
-
version?: SignTypedDataVersion;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
type SerializedHdKeyringState = {
|
|
47
|
-
mnemonic: number[];
|
|
48
|
-
numberOfAccounts: number;
|
|
49
|
-
hdPath: string;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Options:
|
|
53
|
-
const hdPathString = `m/44'/60'/0'/0`;
|
|
54
|
-
const type = 'HD Key Tree';
|
|
55
|
-
|
|
56
|
-
export class HDKeyring implements Keyring<SerializedHdKeyringState> {
|
|
57
|
-
static type: string = type;
|
|
58
|
-
|
|
59
|
-
type: string;
|
|
60
|
-
|
|
61
|
-
#wallets: HDKey[] = [];
|
|
62
|
-
|
|
63
|
-
root: HDKey | undefined | null;
|
|
64
|
-
|
|
65
|
-
mnemonic: Uint8Array | undefined | null;
|
|
66
|
-
|
|
67
|
-
hdWallet: HDKey | undefined | null;
|
|
68
|
-
|
|
69
|
-
hdPath: string = hdPathString;
|
|
70
|
-
|
|
71
|
-
opts: KeyringOpt | undefined | null;
|
|
72
|
-
|
|
73
|
-
/* PUBLIC METHODS */
|
|
74
|
-
constructor(opts: KeyringOpt = {}) {
|
|
75
|
-
this.type = type;
|
|
76
|
-
this.#wallets = [];
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises, @typescript-eslint/promise-function-async
|
|
78
|
-
this.deserialize(opts);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
generateRandomMnemonic() {
|
|
82
|
-
this.#initFromMnemonic(bip39.generateMnemonic(wordlist));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
#uint8ArrayToString(mnemonic: Uint8Array): string {
|
|
86
|
-
const recoveredIndices = Array.from(
|
|
87
|
-
new Uint16Array(new Uint8Array(mnemonic).buffer),
|
|
88
|
-
);
|
|
89
|
-
return recoveredIndices.map((i) => wordlist[i]).join(' ');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
#stringToUint8Array(mnemonic: string): Uint8Array {
|
|
93
|
-
const indices = mnemonic.split(' ').map((word) => wordlist.indexOf(word));
|
|
94
|
-
return new Uint8Array(new Uint16Array(indices).buffer);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
#mnemonicToUint8Array(
|
|
98
|
-
mnemonic: Buffer | JsCastedBuffer | string | Uint8Array | number[],
|
|
99
|
-
): Uint8Array {
|
|
100
|
-
let mnemonicData = mnemonic;
|
|
101
|
-
// when encrypted/decrypted, buffers get cast into js object with a property type set to buffer
|
|
102
|
-
if (
|
|
103
|
-
mnemonic &&
|
|
104
|
-
typeof mnemonic !== 'string' &&
|
|
105
|
-
!ArrayBuffer.isView(mnemonic) &&
|
|
106
|
-
!Array.isArray(mnemonic) &&
|
|
107
|
-
!Buffer.isBuffer(mnemonic) &&
|
|
108
|
-
mnemonic.type === 'Buffer'
|
|
109
|
-
) {
|
|
110
|
-
mnemonicData = mnemonic.data;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
// this block is for backwards compatibility with vaults that were previously stored as buffers, number arrays or plain text strings
|
|
115
|
-
typeof mnemonicData === 'string' ||
|
|
116
|
-
Buffer.isBuffer(mnemonicData) ||
|
|
117
|
-
Array.isArray(mnemonicData)
|
|
118
|
-
) {
|
|
119
|
-
let mnemonicAsString;
|
|
120
|
-
if (Array.isArray(mnemonicData)) {
|
|
121
|
-
mnemonicAsString = Buffer.from(mnemonicData).toString();
|
|
122
|
-
} else if (Buffer.isBuffer(mnemonicData)) {
|
|
123
|
-
mnemonicAsString = mnemonicData.toString();
|
|
124
|
-
} else {
|
|
125
|
-
mnemonicAsString = mnemonicData;
|
|
126
|
-
}
|
|
127
|
-
return this.#stringToUint8Array(mnemonicAsString);
|
|
128
|
-
} else if (
|
|
129
|
-
mnemonicData instanceof Object &&
|
|
130
|
-
!(mnemonicData instanceof Uint8Array)
|
|
131
|
-
) {
|
|
132
|
-
// when encrypted/decrypted the Uint8Array becomes a js object we need to cast back to a Uint8Array
|
|
133
|
-
return Uint8Array.from(Object.values(mnemonicData));
|
|
134
|
-
}
|
|
135
|
-
return mnemonicData;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async serialize(): Promise<SerializedHdKeyringState> {
|
|
139
|
-
if (!this.mnemonic) {
|
|
140
|
-
throw new Error(HDKeyringErrors.MissingMnemonic);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const mnemonicAsString = this.#uint8ArrayToString(this.mnemonic);
|
|
144
|
-
const uint8ArrayMnemonic = new TextEncoder().encode(mnemonicAsString);
|
|
145
|
-
|
|
146
|
-
return Promise.resolve({
|
|
147
|
-
mnemonic: Array.from(uint8ArrayMnemonic),
|
|
148
|
-
numberOfAccounts: this.#wallets.length,
|
|
149
|
-
hdPath: this.hdPath,
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
154
|
-
// @ts-ignore return type is void
|
|
155
|
-
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
156
|
-
deserialize(state: KeyringOpt = {}) {
|
|
157
|
-
if (state.numberOfAccounts && !state.mnemonic) {
|
|
158
|
-
throw new Error(
|
|
159
|
-
HDKeyringErrors.DeserializeErrorNumberOfAccountWithMissingMnemonic,
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (this.root) {
|
|
164
|
-
throw new Error(HDKeyringErrors.SRPAlreadyProvided);
|
|
165
|
-
}
|
|
166
|
-
this.opts = state;
|
|
167
|
-
this.#wallets = [];
|
|
168
|
-
this.mnemonic = null;
|
|
169
|
-
this.root = null;
|
|
170
|
-
this.hdPath = state.hdPath ?? hdPathString;
|
|
171
|
-
|
|
172
|
-
if (state.mnemonic) {
|
|
173
|
-
this.#initFromMnemonic(state.mnemonic);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (state.numberOfAccounts) {
|
|
177
|
-
return this.addAccounts(state.numberOfAccounts);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return Promise.resolve([]);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async addAccounts(numberOfAccounts = 1): Promise<Hex[]> {
|
|
184
|
-
if (!this.root) {
|
|
185
|
-
throw new Error(HDKeyringErrors.NoSRPProvided);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const oldLen = this.#wallets.length;
|
|
189
|
-
const newWallets: HDKey[] = [];
|
|
190
|
-
for (let i = oldLen; i < numberOfAccounts + oldLen; i++) {
|
|
191
|
-
const wallet = this.root.deriveChild(i);
|
|
192
|
-
newWallets.push(wallet);
|
|
193
|
-
this.#wallets.push(wallet);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const hexWallets: Hex[] = newWallets.map((w) => {
|
|
197
|
-
if (!w.publicKey) {
|
|
198
|
-
throw new Error(HDKeyringErrors.MissingPublicKey);
|
|
199
|
-
}
|
|
200
|
-
// HDKey's method publicKey can return null
|
|
201
|
-
return this.#addressfromPublicKey(w.publicKey);
|
|
202
|
-
});
|
|
203
|
-
return Promise.resolve(hexWallets);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async getAccounts(): Promise<Hex[]> {
|
|
207
|
-
return Promise.resolve(
|
|
208
|
-
this.#wallets.map((w) => {
|
|
209
|
-
if (!w.publicKey) {
|
|
210
|
-
throw new Error(HDKeyringErrors.MissingPublicKey);
|
|
211
|
-
}
|
|
212
|
-
return this.#addressfromPublicKey(w.publicKey);
|
|
213
|
-
}),
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/* BASE KEYRING METHODS */
|
|
218
|
-
|
|
219
|
-
// returns an address specific to an app
|
|
220
|
-
async getAppKeyAddress(address: Hex, origin: string): Promise<Hex> {
|
|
221
|
-
if (!origin || typeof origin !== 'string') {
|
|
222
|
-
throw new Error(HDKeyringErrors.OriginNotEmpty);
|
|
223
|
-
}
|
|
224
|
-
const wallet = this.#getWalletForAccount(address, {
|
|
225
|
-
withAppKeyOrigin: origin,
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
if (!wallet.publicKey) {
|
|
229
|
-
throw new Error(HDKeyringErrors.MissingPublicKey);
|
|
230
|
-
}
|
|
231
|
-
// normalize will prefix the address with 0x
|
|
232
|
-
const appKeyAddress = normalize(
|
|
233
|
-
publicToAddress(Buffer.from(wallet.publicKey)).toString('hex'),
|
|
234
|
-
) as Hex;
|
|
235
|
-
|
|
236
|
-
return appKeyAddress;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// exportAccount should return a hex-encoded private key:
|
|
240
|
-
async exportAccount(address: Hex, opts: KeyringOpt = {}): Promise<string> {
|
|
241
|
-
const wallet = this.#getWalletForAccount(address, opts);
|
|
242
|
-
if (!wallet.privateKey) {
|
|
243
|
-
throw new Error(HDKeyringErrors.MissingPrivateKey);
|
|
244
|
-
}
|
|
245
|
-
return bytesToHex(wallet.privateKey);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// tx is an instance of the ethereumjs-transaction class.
|
|
249
|
-
async signTransaction(
|
|
250
|
-
address: Hex,
|
|
251
|
-
transaction: TypedTransaction,
|
|
252
|
-
options: KeyringOpt = {},
|
|
253
|
-
): Promise<TxData> {
|
|
254
|
-
const privKey = this.#getPrivateKeyFor(address, options);
|
|
255
|
-
const signedTx = transaction.sign(Buffer.from(privKey));
|
|
256
|
-
|
|
257
|
-
// Newer versions of Ethereumjs-tx are immutable and return a new tx object
|
|
258
|
-
return signedTx === undefined ? transaction : signedTx;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// For eth_sign, we need to sign arbitrary data:
|
|
262
|
-
async signMessage(
|
|
263
|
-
address: Hex,
|
|
264
|
-
data: string,
|
|
265
|
-
opts: KeyringOpt = {},
|
|
266
|
-
): Promise<string> {
|
|
267
|
-
const message: string = stripHexPrefix(data);
|
|
268
|
-
const privKey: Uint8Array = this.#getPrivateKeyFor(address, opts);
|
|
269
|
-
const msgSig: ECDSASignature = ecsign(
|
|
270
|
-
Buffer.from(message, 'hex'),
|
|
271
|
-
Buffer.from(privKey),
|
|
272
|
-
);
|
|
273
|
-
const rawMsgSig: string = concatSig(
|
|
274
|
-
msgSig.v as unknown as Buffer,
|
|
275
|
-
msgSig.r,
|
|
276
|
-
msgSig.s,
|
|
277
|
-
);
|
|
278
|
-
return rawMsgSig;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// For personal_sign, we need to prefix the message:
|
|
282
|
-
async signPersonalMessage(
|
|
283
|
-
address: Hex,
|
|
284
|
-
message: Hex,
|
|
285
|
-
options: Record<string, unknown> = {},
|
|
286
|
-
): Promise<string> {
|
|
287
|
-
const privKey: Uint8Array = this.#getPrivateKeyFor(address, options);
|
|
288
|
-
const privateKey = Buffer.from(privKey);
|
|
289
|
-
const sig = personalSign({ privateKey, data: message as string });
|
|
290
|
-
return sig;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// For eth_decryptMessage:
|
|
294
|
-
async decryptMessage(
|
|
295
|
-
withAccount: Hex,
|
|
296
|
-
encryptedData: Eip1024EncryptedData,
|
|
297
|
-
): Promise<string> {
|
|
298
|
-
const wallet = this.#getWalletForAccount(withAccount);
|
|
299
|
-
const { privateKey: privateKeyAsUint8Array } = wallet;
|
|
300
|
-
if (!privateKeyAsUint8Array) {
|
|
301
|
-
throw new Error(HDKeyringErrors.MissingPrivateKey);
|
|
302
|
-
}
|
|
303
|
-
const privateKeyAsHex = Buffer.from(privateKeyAsUint8Array).toString('hex');
|
|
304
|
-
const sig = decrypt({ privateKey: privateKeyAsHex, encryptedData });
|
|
305
|
-
return sig;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// personal_signTypedData, signs data along with the schema
|
|
309
|
-
async signTypedData(
|
|
310
|
-
withAccount: Hex,
|
|
311
|
-
typedData: Record<string, unknown> | TypedDataV1 | TypedMessage<any>,
|
|
312
|
-
opts: KeyringOpt = { version: SignTypedDataVersion.V1 },
|
|
313
|
-
): Promise<string> {
|
|
314
|
-
let version: SignTypedDataVersion;
|
|
315
|
-
if (
|
|
316
|
-
opts.version &&
|
|
317
|
-
Object.keys(SignTypedDataVersion).includes(opts.version as string)
|
|
318
|
-
) {
|
|
319
|
-
version = opts.version;
|
|
320
|
-
} else {
|
|
321
|
-
// Treat invalid versions as "V1"
|
|
322
|
-
version = SignTypedDataVersion.V1;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const privateKey: Uint8Array = this.#getPrivateKeyFor(withAccount, opts);
|
|
326
|
-
return signTypedData({
|
|
327
|
-
privateKey: Buffer.from(privateKey),
|
|
328
|
-
data: typedData as unknown as TypedDataV1 | TypedMessage<any>,
|
|
329
|
-
version,
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
removeAccount(account: Hex): void {
|
|
334
|
-
const address = account;
|
|
335
|
-
if (
|
|
336
|
-
!this.#wallets
|
|
337
|
-
.map(({ publicKey }) => {
|
|
338
|
-
if (!publicKey) {
|
|
339
|
-
throw new Error(HDKeyringErrors.MissingPublicKey);
|
|
340
|
-
}
|
|
341
|
-
return this.#addressfromPublicKey(publicKey);
|
|
342
|
-
})
|
|
343
|
-
.includes(address)
|
|
344
|
-
) {
|
|
345
|
-
throw new Error(
|
|
346
|
-
HDKeyringErrors.AddressNotFound.replace('$address', address),
|
|
347
|
-
);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
this.#wallets = this.#wallets.filter(({ publicKey }) => {
|
|
351
|
-
if (!publicKey) {
|
|
352
|
-
// should never be here
|
|
353
|
-
throw new Error(HDKeyringErrors.MissingPublicKey);
|
|
354
|
-
}
|
|
355
|
-
return this.#addressfromPublicKey(publicKey) !== address;
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// get public key for nacl
|
|
360
|
-
async getEncryptionPublicKey(
|
|
361
|
-
withAccount: Hex,
|
|
362
|
-
opts: KeyringOpt = {},
|
|
363
|
-
): Promise<string> {
|
|
364
|
-
const privKey = this.#getPrivateKeyFor(withAccount, opts);
|
|
365
|
-
const publicKey = getEncryptionPublicKey(
|
|
366
|
-
Buffer.from(privKey).toString('hex'),
|
|
367
|
-
);
|
|
368
|
-
return publicKey;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
#getPrivateKeyFor(address: Hex, opts: KeyringOpt = {}): Uint8Array {
|
|
372
|
-
if (!address) {
|
|
373
|
-
throw new Error(HDKeyringErrors.AddressNotProvided);
|
|
374
|
-
}
|
|
375
|
-
const wallet = this.#getWalletForAccount(address, opts);
|
|
376
|
-
if (!wallet.privateKey) {
|
|
377
|
-
throw new Error(HDKeyringErrors.MissingPrivateKey);
|
|
378
|
-
}
|
|
379
|
-
return wallet.privateKey;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
#getWalletForAccount(address: string, opts: KeyringOpt = {}): HDKey {
|
|
383
|
-
const normalizedAddress = normalize(address);
|
|
384
|
-
let wallet = this.#wallets.find(({ publicKey }) => {
|
|
385
|
-
if (!publicKey) {
|
|
386
|
-
throw new Error(HDKeyringErrors.MissingPublicKey);
|
|
387
|
-
}
|
|
388
|
-
// If a wallet is found, public key will not be null
|
|
389
|
-
return this.#addressfromPublicKey(publicKey) === normalizedAddress;
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
if (opts.withAppKeyOrigin) {
|
|
393
|
-
if (!wallet) {
|
|
394
|
-
throw new Error(HDKeyringErrors.NoMatchingAddress);
|
|
395
|
-
}
|
|
396
|
-
const { privateKey } = wallet;
|
|
397
|
-
if (!privateKey) {
|
|
398
|
-
throw new Error(HDKeyringErrors.MissingPrivateKey);
|
|
399
|
-
}
|
|
400
|
-
const appKeyOriginBuffer = Buffer.from(opts.withAppKeyOrigin, 'utf8');
|
|
401
|
-
const appKeyBuffer = Buffer.concat([privateKey, appKeyOriginBuffer]);
|
|
402
|
-
const appKeyPrivateKey = arrToBufArr(keccak256(appKeyBuffer));
|
|
403
|
-
const appKeyPublicKey = privateToPublic(appKeyPrivateKey);
|
|
404
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
405
|
-
// @ts-ignore special case for appKey
|
|
406
|
-
wallet = { privateKey: appKeyPrivateKey, publicKey: appKeyPublicKey };
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (!wallet) {
|
|
410
|
-
throw new Error(HDKeyringErrors.NoMatchingAddress);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return wallet;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/* PRIVATE / UTILITY METHODS */
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Sets appropriate properties for the keyring based on the given
|
|
420
|
-
* BIP39-compliant mnemonic.
|
|
421
|
-
*
|
|
422
|
-
* @param mnemonic - A seed phrase represented
|
|
423
|
-
* as a string, an array of UTF-8 bytes, or a Buffer. Mnemonic input
|
|
424
|
-
* passed as type buffer or array of UTF-8 bytes must be NFKD normalized.
|
|
425
|
-
*/
|
|
426
|
-
#initFromMnemonic(
|
|
427
|
-
mnemonic: string | number[] | Buffer | Uint8Array | JsCastedBuffer,
|
|
428
|
-
): void {
|
|
429
|
-
if (this.root) {
|
|
430
|
-
throw new Error(HDKeyringErrors.SRPAlreadyProvided);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
this.mnemonic = this.#mnemonicToUint8Array(mnemonic);
|
|
434
|
-
|
|
435
|
-
// validate before initializing
|
|
436
|
-
const isValid = bip39.validateMnemonic(this.mnemonic, wordlist);
|
|
437
|
-
if (!isValid) {
|
|
438
|
-
throw new Error(HDKeyringErrors.InvalidSRP);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// eslint-disable-next-line node/no-sync
|
|
442
|
-
const seed = bip39.mnemonicToSeedSync(this.mnemonic, wordlist);
|
|
443
|
-
this.hdWallet = HDKey.fromMasterSeed(seed);
|
|
444
|
-
if (!this.hdPath) {
|
|
445
|
-
throw new Error(HDKeyringErrors.MissingHdPath);
|
|
446
|
-
}
|
|
447
|
-
this.root = this.hdWallet.derive(this.hdPath);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// small helper function to convert publicKey in Uint8Array form to a publicAddress as a hex
|
|
451
|
-
#addressfromPublicKey(publicKey: Uint8Array): Hex {
|
|
452
|
-
// bufferToHex adds a 0x prefix
|
|
453
|
-
const address = bufferToHex(
|
|
454
|
-
publicToAddress(Buffer.from(publicKey), true),
|
|
455
|
-
).toLowerCase() as Hex;
|
|
456
|
-
|
|
457
|
-
return address;
|
|
458
|
-
}
|
|
459
|
-
}
|
package/src/errors.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-shadow */
|
|
2
|
-
/* eslint-disable no-unused-vars */
|
|
3
|
-
export enum HDKeyringErrors {
|
|
4
|
-
MissingMnemonic = 'Eth-Hd-Keyring: Missing mnemonic when serializing',
|
|
5
|
-
DeserializeErrorNumberOfAccountWithMissingMnemonic = 'Eth-Hd-Keyring: Deserialize method cannot be called with an opts value for numberOfAccounts and no menmonic',
|
|
6
|
-
NoSRPProvided = 'Eth-Hd-Keyring: No secret recovery phrase provided',
|
|
7
|
-
OriginNotEmpty = `Eth-Hd-Keyring: 'origin' must be a non-empty string`,
|
|
8
|
-
AddressNotFound = 'Eth-Hd-Keyring: Address $address not found in this keyring',
|
|
9
|
-
AddressNotProvided = 'Eth-Hd-Keyring: Must specify address.',
|
|
10
|
-
NoMatchingAddress = 'Eth-Hd-Keyring: Unable to find matching address.',
|
|
11
|
-
InvalidSRP = 'Eth-Hd-Keyring: Invalid secret recovery phrase provided',
|
|
12
|
-
SRPAlreadyProvided = 'Eth-Hd-Keyring: Secret recovery phrase already provided',
|
|
13
|
-
MissingHdPath = 'Eth-Hd-Keyring: Missing hd path',
|
|
14
|
-
MissingPrivateKey = 'Eth-Hd-Keyring: Missing private key in wallet',
|
|
15
|
-
MissingPublicKey = 'Eth-Hd-Keyring: Missing public key in wallet',
|
|
16
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { HDKeyring } from './HDKeyring';
|
package/tsconfig.build.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"inlineSources": true,
|
|
6
|
-
"noEmit": false,
|
|
7
|
-
"outDir": "dist",
|
|
8
|
-
"rootDir": "src",
|
|
9
|
-
"sourceMap": true
|
|
10
|
-
},
|
|
11
|
-
"include": ["./src/**/*.ts"],
|
|
12
|
-
"exclude": ["./src/**/*.test.ts"]
|
|
13
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"esModuleInterop": true,
|
|
4
|
-
"exactOptionalPropertyTypes": true,
|
|
5
|
-
"forceConsistentCasingInFileNames": true,
|
|
6
|
-
"lib": ["ES2020"],
|
|
7
|
-
"module": "CommonJS",
|
|
8
|
-
"moduleResolution": "node",
|
|
9
|
-
"noEmit": true,
|
|
10
|
-
"noErrorTruncation": true,
|
|
11
|
-
"noUncheckedIndexedAccess": true,
|
|
12
|
-
"strict": true,
|
|
13
|
-
"target": "es2020"
|
|
14
|
-
},
|
|
15
|
-
"exclude": ["./dist/**/*"]
|
|
16
|
-
}
|