@metamask/eth-simple-keyring 5.0.0 → 5.1.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/CHANGELOG.md +17 -3
- package/README.md +3 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/simple-keyring.d.ts +34 -0
- package/dist/simple-keyring.js +178 -0
- package/dist/simple-keyring.js.map +1 -0
- package/package.json +51 -31
- package/index.js +0 -206
- package/test/index.js +0 -759
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [5.1.1]
|
|
10
|
+
### Fixed
|
|
11
|
+
- Treat `undefined` and `null` as empty array in deserialize function ([#166](https://github.com/MetaMask/eth-simple-keyring/pull/166))
|
|
12
|
+
|
|
13
|
+
## [5.1.0]
|
|
14
|
+
### Changed
|
|
15
|
+
- Export TypeScript interfaces ([#140](https://github.com/MetaMask/eth-simple-keyring/pull/140))
|
|
16
|
+
- Update all dependencies ([#140](https://github.com/MetaMask/eth-simple-keyring/pull/140)) ([#149](https://github.com/MetaMask/eth-simple-keyring/pull/149))
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Add `validateMessage` option to `signMessage` to configure if runtime-validation should be done that input string is hex (default: `true`) ([#148](https://github.com/MetaMask/eth-simple-keyring/pull/148))
|
|
20
|
+
|
|
9
21
|
## [5.0.0]
|
|
10
22
|
### Changed
|
|
11
23
|
- **BREAKING:** Makes version-specific `signTypedData` methods private ([#84](https://github.com/MetaMask/eth-simple-keyring/pull/84))
|
|
@@ -14,12 +26,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
14
26
|
- Consumers should not use this property as it is intended for internal use only.
|
|
15
27
|
- **BREAKING:** Makes `getPrivateKeyFor` a private method ([#83](https://github.com/MetaMask/eth-simple-keyring/pull/83))
|
|
16
28
|
- Consumers who wish to get the private key for a given account should use the `exportAccount` method.
|
|
17
|
-
- **BREAKING:** Set the minimum Node.js version to
|
|
29
|
+
- **BREAKING:** Set the minimum Node.js version to 14 ([#68](https://github.com/MetaMask/eth-simple-keyring/pull/68)) ([#109](https://github.com/MetaMask/eth-simple-keyring/pull/109))
|
|
18
30
|
- Always return rejected Promise upon failure ([#85](https://github.com/MetaMask/eth-simple-keyring/pull/85))
|
|
19
31
|
|
|
20
32
|
### Removed
|
|
21
33
|
- **BREAKING:** Remove redundant `newGethSignMessage` method ([#72](https://github.com/MetaMask/eth-simple-keyring/pull/72))
|
|
22
|
-
- Consumers can use `signPersonalMessage` method as a replacement for `newGethSignMessage`.
|
|
34
|
+
- Consumers can use `signPersonalMessage` method as a replacement for `newGethSignMessage`.
|
|
23
35
|
|
|
24
|
-
[Unreleased]: https://github.com/MetaMask/eth-simple-keyring/compare/v5.
|
|
36
|
+
[Unreleased]: https://github.com/MetaMask/eth-simple-keyring/compare/v5.1.1...HEAD
|
|
37
|
+
[5.1.1]: https://github.com/MetaMask/eth-simple-keyring/compare/v5.1.0...v5.1.1
|
|
38
|
+
[5.1.0]: https://github.com/MetaMask/eth-simple-keyring/compare/v5.0.0...v5.1.0
|
|
25
39
|
[5.0.0]: https://github.com/MetaMask/eth-simple-keyring/releases/tag/v5.0.0
|
package/README.md
CHANGED
|
@@ -81,11 +81,13 @@ removes the specified account from the list of accounts.
|
|
|
81
81
|
|
|
82
82
|
### Setup
|
|
83
83
|
|
|
84
|
-
- Install [Node.js](https://nodejs.org) version
|
|
84
|
+
- Install [Node.js](https://nodejs.org) version 14 or greater
|
|
85
85
|
- If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you.
|
|
86
86
|
- Install [Yarn v3](https://yarnpkg.com/getting-started/install)
|
|
87
87
|
- Run `yarn install` to install dependencies and run any required post-install scripts
|
|
88
88
|
|
|
89
|
+
-- This package implicitly relies on Buffer to be present (meaning that if someone wants to use this in a browser context, they need to supply a polyfill for Buffer or use the `buffer` package)
|
|
90
|
+
|
|
89
91
|
### Testing and Linting
|
|
90
92
|
|
|
91
93
|
Run `yarn test` to run the tests once. To run tests on file changes, run `yarn test:watch`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './simple-keyring';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var simple_keyring_1 = require("./simple-keyring");
|
|
8
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(simple_keyring_1).default; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,mDAA2C;AAAlC,0HAAA,OAAO,OAAA","sourcesContent":["export { default } from './simple-keyring';\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TypedTransaction } from '@ethereumjs/tx';
|
|
2
|
+
import { SignTypedDataVersion } from '@metamask/eth-sig-util';
|
|
3
|
+
import { Eip1024EncryptedData, Hex, Keyring } from '@metamask/utils';
|
|
4
|
+
declare type KeyringOpt = {
|
|
5
|
+
withAppKeyOrigin?: string;
|
|
6
|
+
version?: SignTypedDataVersion | string;
|
|
7
|
+
};
|
|
8
|
+
export default class SimpleKeyring implements Keyring<string[]> {
|
|
9
|
+
#private;
|
|
10
|
+
readonly type: string;
|
|
11
|
+
static type: string;
|
|
12
|
+
constructor(privateKeys?: string[]);
|
|
13
|
+
serialize(): Promise<string[]>;
|
|
14
|
+
deserialize(privateKeys?: string[]): Promise<void>;
|
|
15
|
+
addAccounts(numAccounts?: number): Promise<`0x${string}`[]>;
|
|
16
|
+
getAccounts(): Promise<`0x${string}`[]>;
|
|
17
|
+
signTransaction(address: Hex, transaction: TypedTransaction, opts?: KeyringOpt): Promise<TypedTransaction>;
|
|
18
|
+
signMessage(address: Hex, data: string, opts?: {
|
|
19
|
+
withAppKeyOrigin: string;
|
|
20
|
+
validateMessage: boolean;
|
|
21
|
+
}): Promise<string>;
|
|
22
|
+
signPersonalMessage(address: Hex, msgHex: Hex, opts?: {
|
|
23
|
+
withAppKeyOrigin: string;
|
|
24
|
+
}): Promise<string>;
|
|
25
|
+
decryptMessage(withAccount: Hex, encryptedData: Eip1024EncryptedData): Promise<string>;
|
|
26
|
+
signTypedData(address: Hex, typedData: any, opts?: KeyringOpt): Promise<string>;
|
|
27
|
+
getEncryptionPublicKey(withAccount: Hex, opts?: KeyringOpt): Promise<string>;
|
|
28
|
+
getAppKeyAddress(address: Hex, origin: string): Promise<`0x${string}`>;
|
|
29
|
+
exportAccount(address: Hex, opts?: {
|
|
30
|
+
withAppKeyOrigin: string;
|
|
31
|
+
}): Promise<string>;
|
|
32
|
+
removeAccount(address: string): void;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
var _SimpleKeyring_instances, _SimpleKeyring_wallets, _SimpleKeyring_getPrivateKeyFor, _SimpleKeyring_getWalletForAccount;
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const util_1 = require("@ethereumjs/util");
|
|
19
|
+
const eth_sig_util_1 = require("@metamask/eth-sig-util");
|
|
20
|
+
const utils_1 = require("@metamask/utils");
|
|
21
|
+
const keccak_1 = require("ethereum-cryptography/keccak");
|
|
22
|
+
const randombytes_1 = __importDefault(require("randombytes"));
|
|
23
|
+
const TYPE = 'Simple Key Pair';
|
|
24
|
+
class SimpleKeyring {
|
|
25
|
+
constructor(privateKeys = []) {
|
|
26
|
+
_SimpleKeyring_instances.add(this);
|
|
27
|
+
_SimpleKeyring_wallets.set(this, void 0);
|
|
28
|
+
this.type = TYPE;
|
|
29
|
+
__classPrivateFieldSet(this, _SimpleKeyring_wallets, [], "f");
|
|
30
|
+
/* istanbul ignore next: It's not possible to write a unit test for this, because a constructor isn't allowed
|
|
31
|
+
* to be async. Jest can't await the constructor, and when the error gets thrown, Jest can't catch it. */
|
|
32
|
+
this.deserialize(privateKeys).catch((error) => {
|
|
33
|
+
throw new Error(`Problem deserializing SimpleKeyring ${error.message}`);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async serialize() {
|
|
37
|
+
return __classPrivateFieldGet(this, _SimpleKeyring_wallets, "f").map((a) => a.privateKey.toString('hex'));
|
|
38
|
+
}
|
|
39
|
+
async deserialize(privateKeys = []) {
|
|
40
|
+
__classPrivateFieldSet(this, _SimpleKeyring_wallets, privateKeys.map((hexPrivateKey) => {
|
|
41
|
+
const strippedHexPrivateKey = (0, util_1.stripHexPrefix)(hexPrivateKey);
|
|
42
|
+
const privateKey = Buffer.from(strippedHexPrivateKey, 'hex');
|
|
43
|
+
const publicKey = (0, util_1.privateToPublic)(privateKey);
|
|
44
|
+
return { privateKey, publicKey };
|
|
45
|
+
}), "f");
|
|
46
|
+
}
|
|
47
|
+
async addAccounts(numAccounts = 1) {
|
|
48
|
+
const newWallets = [];
|
|
49
|
+
for (let i = 0; i < numAccounts; i++) {
|
|
50
|
+
const privateKey = generateKey();
|
|
51
|
+
const publicKey = (0, util_1.privateToPublic)(privateKey);
|
|
52
|
+
newWallets.push({ privateKey, publicKey });
|
|
53
|
+
}
|
|
54
|
+
__classPrivateFieldSet(this, _SimpleKeyring_wallets, __classPrivateFieldGet(this, _SimpleKeyring_wallets, "f").concat(newWallets), "f");
|
|
55
|
+
const hexWallets = newWallets.map(({ publicKey }) => (0, utils_1.add0x)((0, util_1.bufferToHex)((0, util_1.publicToAddress)(publicKey))));
|
|
56
|
+
return hexWallets;
|
|
57
|
+
}
|
|
58
|
+
async getAccounts() {
|
|
59
|
+
return __classPrivateFieldGet(this, _SimpleKeyring_wallets, "f").map(({ publicKey }) => (0, utils_1.add0x)((0, util_1.bufferToHex)((0, util_1.publicToAddress)(publicKey))));
|
|
60
|
+
}
|
|
61
|
+
async signTransaction(address, transaction, opts = {}) {
|
|
62
|
+
const privKey = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getPrivateKeyFor).call(this, address, opts);
|
|
63
|
+
const signedTx = transaction.sign(privKey);
|
|
64
|
+
// Newer versions of Ethereumjs-tx are immutable and return a new tx object
|
|
65
|
+
return signedTx === undefined ? transaction : signedTx;
|
|
66
|
+
}
|
|
67
|
+
// For eth_sign, we need to sign arbitrary data:
|
|
68
|
+
async signMessage(address, data, opts = { withAppKeyOrigin: '', validateMessage: true }) {
|
|
69
|
+
const message = (0, util_1.stripHexPrefix)(data);
|
|
70
|
+
if (opts.validateMessage &&
|
|
71
|
+
(message.length === 0 || !message.match(/^[a-fA-F0-9]*$/u))) {
|
|
72
|
+
throw new Error('Cannot sign invalid message');
|
|
73
|
+
}
|
|
74
|
+
const privKey = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getPrivateKeyFor).call(this, address, opts);
|
|
75
|
+
const msgSig = (0, util_1.ecsign)(Buffer.from(message, 'hex'), privKey);
|
|
76
|
+
const rawMsgSig = (0, eth_sig_util_1.concatSig)((0, util_1.toBuffer)(msgSig.v), msgSig.r, msgSig.s);
|
|
77
|
+
return rawMsgSig;
|
|
78
|
+
}
|
|
79
|
+
// For personal_sign, we need to prefix the message:
|
|
80
|
+
async signPersonalMessage(address, msgHex, opts = { withAppKeyOrigin: '' }) {
|
|
81
|
+
const privKey = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getPrivateKeyFor).call(this, address, opts);
|
|
82
|
+
return (0, eth_sig_util_1.personalSign)({ privateKey: privKey, data: msgHex });
|
|
83
|
+
}
|
|
84
|
+
// For eth_decryptMessage:
|
|
85
|
+
async decryptMessage(withAccount, encryptedData) {
|
|
86
|
+
const wallet = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getWalletForAccount).call(this, withAccount);
|
|
87
|
+
const privateKey = wallet.privateKey.toString('hex');
|
|
88
|
+
return (0, eth_sig_util_1.decrypt)({ privateKey, encryptedData });
|
|
89
|
+
}
|
|
90
|
+
// personal_signTypedData, signs data along with the schema
|
|
91
|
+
async signTypedData(address, typedData, opts = { version: eth_sig_util_1.SignTypedDataVersion.V1 }) {
|
|
92
|
+
// Treat invalid versions as "V1"
|
|
93
|
+
let version = eth_sig_util_1.SignTypedDataVersion.V1;
|
|
94
|
+
if (opts.version && isSignTypedDataVersion(opts.version)) {
|
|
95
|
+
version = eth_sig_util_1.SignTypedDataVersion[opts.version];
|
|
96
|
+
}
|
|
97
|
+
const privateKey = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getPrivateKeyFor).call(this, address, opts);
|
|
98
|
+
return (0, eth_sig_util_1.signTypedData)({ privateKey, data: typedData, version });
|
|
99
|
+
}
|
|
100
|
+
// get public key for nacl
|
|
101
|
+
async getEncryptionPublicKey(withAccount, opts) {
|
|
102
|
+
const privKey = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getPrivateKeyFor).call(this, withAccount, opts);
|
|
103
|
+
const publicKey = (0, eth_sig_util_1.getEncryptionPublicKey)(privKey.toString('hex'));
|
|
104
|
+
return publicKey;
|
|
105
|
+
}
|
|
106
|
+
// returns an address specific to an app
|
|
107
|
+
async getAppKeyAddress(address, origin) {
|
|
108
|
+
if (!origin || typeof origin !== 'string') {
|
|
109
|
+
throw new Error(`'origin' must be a non-empty string`);
|
|
110
|
+
}
|
|
111
|
+
const wallet = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getWalletForAccount).call(this, address, {
|
|
112
|
+
withAppKeyOrigin: origin,
|
|
113
|
+
});
|
|
114
|
+
const appKeyAddress = (0, utils_1.add0x)((0, util_1.bufferToHex)((0, util_1.publicToAddress)(wallet.publicKey)));
|
|
115
|
+
return appKeyAddress;
|
|
116
|
+
}
|
|
117
|
+
// exportAccount should return a hex-encoded private key:
|
|
118
|
+
async exportAccount(address, opts = { withAppKeyOrigin: '' }) {
|
|
119
|
+
const wallet = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getWalletForAccount).call(this, address, opts);
|
|
120
|
+
return wallet.privateKey.toString('hex');
|
|
121
|
+
}
|
|
122
|
+
removeAccount(address) {
|
|
123
|
+
if (!__classPrivateFieldGet(this, _SimpleKeyring_wallets, "f")
|
|
124
|
+
.map(({ publicKey }) => (0, util_1.bufferToHex)((0, util_1.publicToAddress)(publicKey)).toLowerCase())
|
|
125
|
+
.includes(address.toLowerCase())) {
|
|
126
|
+
throw new Error(`Address ${address} not found in this keyring`);
|
|
127
|
+
}
|
|
128
|
+
__classPrivateFieldSet(this, _SimpleKeyring_wallets, __classPrivateFieldGet(this, _SimpleKeyring_wallets, "f").filter(({ publicKey }) => (0, util_1.bufferToHex)((0, util_1.publicToAddress)(publicKey)).toLowerCase() !==
|
|
129
|
+
address.toLowerCase()), "f");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.default = SimpleKeyring;
|
|
133
|
+
_SimpleKeyring_wallets = new WeakMap(), _SimpleKeyring_instances = new WeakSet(), _SimpleKeyring_getPrivateKeyFor = function _SimpleKeyring_getPrivateKeyFor(address, opts = { withAppKeyOrigin: '' }) {
|
|
134
|
+
if (!address) {
|
|
135
|
+
throw new Error('Must specify address.');
|
|
136
|
+
}
|
|
137
|
+
const wallet = __classPrivateFieldGet(this, _SimpleKeyring_instances, "m", _SimpleKeyring_getWalletForAccount).call(this, address, opts);
|
|
138
|
+
return wallet.privateKey;
|
|
139
|
+
}, _SimpleKeyring_getWalletForAccount = function _SimpleKeyring_getWalletForAccount(account, opts = {}) {
|
|
140
|
+
const address = (0, eth_sig_util_1.normalize)(account);
|
|
141
|
+
let wallet = __classPrivateFieldGet(this, _SimpleKeyring_wallets, "f").find(({ publicKey }) => (0, util_1.bufferToHex)((0, util_1.publicToAddress)(publicKey)) === address);
|
|
142
|
+
if (!wallet) {
|
|
143
|
+
throw new Error('Simple Keyring - Unable to find matching address.');
|
|
144
|
+
}
|
|
145
|
+
if (opts.withAppKeyOrigin) {
|
|
146
|
+
const { privateKey } = wallet;
|
|
147
|
+
const appKeyOriginBuffer = Buffer.from(opts.withAppKeyOrigin, 'utf8');
|
|
148
|
+
const appKeyBuffer = Buffer.concat([privateKey, appKeyOriginBuffer]);
|
|
149
|
+
const appKeyPrivateKey = (0, util_1.arrToBufArr)((0, keccak_1.keccak256)(appKeyBuffer));
|
|
150
|
+
const appKeyPublicKey = (0, util_1.privateToPublic)(appKeyPrivateKey);
|
|
151
|
+
wallet = { privateKey: appKeyPrivateKey, publicKey: appKeyPublicKey };
|
|
152
|
+
}
|
|
153
|
+
return wallet;
|
|
154
|
+
};
|
|
155
|
+
SimpleKeyring.type = TYPE;
|
|
156
|
+
/**
|
|
157
|
+
* Generate and validate a new random key of 32 bytes.
|
|
158
|
+
*
|
|
159
|
+
* @returns Buffer The generated key.
|
|
160
|
+
*/
|
|
161
|
+
function generateKey() {
|
|
162
|
+
const privateKey = (0, randombytes_1.default)(32);
|
|
163
|
+
if (!(0, util_1.isValidPrivate)(privateKey)) {
|
|
164
|
+
throw new Error('Private key does not satisfy the curve requirements (ie. it is invalid)');
|
|
165
|
+
}
|
|
166
|
+
return privateKey;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Type predicate type guard to check if a string is in the enum SignTypedDataVersion.
|
|
170
|
+
*
|
|
171
|
+
* @param version - The string to check.
|
|
172
|
+
* @returns Whether it's in the enum.
|
|
173
|
+
*/
|
|
174
|
+
// TODO: Put this in @metamask/eth-sig-util
|
|
175
|
+
function isSignTypedDataVersion(version) {
|
|
176
|
+
return version in eth_sig_util_1.SignTypedDataVersion;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=simple-keyring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simple-keyring.js","sourceRoot":"","sources":["../src/simple-keyring.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AACA,2CAS0B;AAC1B,yDAQgC;AAChC,2CAA4E;AAC5E,yDAAyD;AACzD,8DAAsC;AAOtC,MAAM,IAAI,GAAG,iBAAiB,CAAC;AAE/B,MAAqB,aAAa;IAOhC,YAAY,cAAwB,EAAE;;QANtC,yCAAsD;QAE7C,SAAI,GAAW,IAAI,CAAC;QAK3B,uBAAA,IAAI,0BAAY,EAAE,MAAA,CAAC;QAEnB;iHACyG;QACzG,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;YACnD,MAAM,IAAI,KAAK,CAAC,uCAAuC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,uBAAA,IAAI,8BAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,cAAwB,EAAE;QAC1C,uBAAA,IAAI,0BAAY,WAAW,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE;YAChD,MAAM,qBAAqB,GAAG,IAAA,qBAAc,EAAC,aAAa,CAAC,CAAC;YAC5D,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;YAC7D,MAAM,SAAS,GAAG,IAAA,sBAAe,EAAC,UAAU,CAAC,CAAC;YAC9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;QACnC,CAAC,CAAC,MAAA,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,WAAW,GAAG,CAAC;QAC/B,MAAM,UAAU,GAAG,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE;YACpC,MAAM,UAAU,GAAG,WAAW,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,IAAA,sBAAe,EAAC,UAAU,CAAC,CAAC;YAC9C,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;SAC5C;QACD,uBAAA,IAAI,0BAAY,uBAAA,IAAI,8BAAS,CAAC,MAAM,CAAC,UAAU,CAAC,MAAA,CAAC;QACjD,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAClD,IAAA,aAAK,EAAC,IAAA,kBAAW,EAAC,IAAA,sBAAe,EAAC,SAAS,CAAC,CAAC,CAAC,CAC/C,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,uBAAA,IAAI,8BAAS,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CACzC,IAAA,aAAK,EAAC,IAAA,kBAAW,EAAC,IAAA,sBAAe,EAAC,SAAS,CAAC,CAAC,CAAC,CAC/C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAAY,EACZ,WAA6B,EAC7B,OAAmB,EAAE;QAErB,MAAM,OAAO,GAAG,uBAAA,IAAI,iEAAkB,MAAtB,IAAI,EAAmB,OAAO,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,2EAA2E;QAC3E,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;IACzD,CAAC;IAED,gDAAgD;IAChD,KAAK,CAAC,WAAW,CACf,OAAY,EACZ,IAAY,EACZ,IAAI,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;QAEtD,MAAM,OAAO,GAAG,IAAA,qBAAc,EAAC,IAAI,CAAC,CAAC;QACrC,IACE,IAAI,CAAC,eAAe;YACpB,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,EAC3D;YACA,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;SAChD;QACD,MAAM,OAAO,GAAG,uBAAA,IAAI,iEAAkB,MAAtB,IAAI,EAAmB,OAAO,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAA,aAAM,EAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,IAAA,wBAAS,EAAC,IAAA,eAAQ,EAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QACpE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,oDAAoD;IACpD,KAAK,CAAC,mBAAmB,CACvB,OAAY,EACZ,MAAW,EACX,IAAI,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAAE;QAE/B,MAAM,OAAO,GAAG,uBAAA,IAAI,iEAAkB,MAAtB,IAAI,EAAmB,OAAO,EAAE,IAAI,CAAC,CAAC;QACtD,OAAO,IAAA,2BAAY,EAAC,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,0BAA0B;IAC1B,KAAK,CAAC,cAAc,CAAC,WAAgB,EAAE,aAAmC;QACxE,MAAM,MAAM,GAAG,uBAAA,IAAI,oEAAqB,MAAzB,IAAI,EAAsB,WAAW,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrD,OAAO,IAAA,sBAAO,EAAC,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,aAAa,CACjB,OAAY,EACZ,SAAc,EACd,OAAmB,EAAE,OAAO,EAAE,mCAAoB,CAAC,EAAE,EAAE;QAEvD,iCAAiC;QACjC,IAAI,OAAO,GAAG,mCAAoB,CAAC,EAAE,CAAC;QAEtC,IAAI,IAAI,CAAC,OAAO,IAAI,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YACxD,OAAO,GAAG,mCAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SAC9C;QAED,MAAM,UAAU,GAAG,uBAAA,IAAI,iEAAkB,MAAtB,IAAI,EAAmB,OAAO,EAAE,IAAI,CAAC,CAAC;QACzD,OAAO,IAAA,4BAAa,EAAC,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,0BAA0B;IAC1B,KAAK,CAAC,sBAAsB,CAAC,WAAgB,EAAE,IAAiB;QAC9D,MAAM,OAAO,GAAG,uBAAA,IAAI,iEAAkB,MAAtB,IAAI,EAAmB,WAAW,EAAE,IAAI,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAA,qCAAsB,EAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAClE,OAAO,SAAS,CAAC;IACnB,CAAC;IAUD,wCAAwC;IACxC,KAAK,CAAC,gBAAgB,CAAC,OAAY,EAAE,MAAc;QACjD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YACzC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;SACxD;QACD,MAAM,MAAM,GAAG,uBAAA,IAAI,oEAAqB,MAAzB,IAAI,EAAsB,OAAO,EAAE;YAChD,gBAAgB,EAAE,MAAM;SACzB,CAAC,CAAC;QACH,MAAM,aAAa,GAAG,IAAA,aAAK,EAAC,IAAA,kBAAW,EAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC5E,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,yDAAyD;IACzD,KAAK,CAAC,aAAa,CAAC,OAAY,EAAE,IAAI,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,uBAAA,IAAI,oEAAqB,MAAzB,IAAI,EAAsB,OAAO,EAAE,IAAI,CAAC,CAAC;QACxD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,aAAa,CAAC,OAAe;QAC3B,IACE,CAAC,uBAAA,IAAI,8BAAS;aACX,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CACrB,IAAA,kBAAW,EAAC,IAAA,sBAAe,EAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,CACtD;aACA,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAClC;YACA,MAAM,IAAI,KAAK,CAAC,WAAW,OAAO,4BAA4B,CAAC,CAAC;SACjE;QAED,uBAAA,IAAI,0BAAY,uBAAA,IAAI,8BAAS,CAAC,MAAM,CAClC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAChB,IAAA,kBAAW,EAAC,IAAA,sBAAe,EAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE;YACrD,OAAO,CAAC,WAAW,EAAE,CACxB,MAAA,CAAC;IACJ,CAAC;;AAnKH,gCAyLC;6JAhEmB,OAAY,EAAE,OAAmB,EAAE,gBAAgB,EAAE,EAAE,EAAE;IACzE,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;KAC1C;IACD,MAAM,MAAM,GAAG,uBAAA,IAAI,oEAAqB,MAAzB,IAAI,EAAsB,OAAO,EAAE,IAAI,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,UAAU,CAAC;AAC3B,CAAC,mFAsCoB,OAAwB,EAAE,OAAmB,EAAE;IAClE,MAAM,OAAO,GAAG,IAAA,wBAAS,EAAC,OAAO,CAAC,CAAC;IACnC,IAAI,MAAM,GAAG,uBAAA,IAAI,8BAAS,CAAC,IAAI,CAC7B,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,IAAA,kBAAW,EAAC,IAAA,sBAAe,EAAC,SAAS,CAAC,CAAC,KAAK,OAAO,CACvE,CAAC;IACF,IAAI,CAAC,MAAM,EAAE;QACX,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;KACtE;IAED,IAAI,IAAI,CAAC,gBAAgB,EAAE;QACzB,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QAC9B,MAAM,kBAAkB,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;QACtE,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC;QACrE,MAAM,gBAAgB,GAAG,IAAA,kBAAW,EAAC,IAAA,kBAAS,EAAC,YAAY,CAAC,CAAC,CAAC;QAC9D,MAAM,eAAe,GAAG,IAAA,sBAAe,EAAC,gBAAgB,CAAC,CAAC;QAC1D,MAAM,GAAG,EAAE,UAAU,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;KACvE;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAnLM,kBAAI,GAAW,IAAI,CAAC;AAsL7B;;;;GAIG;AACH,SAAS,WAAW;IAClB,MAAM,UAAU,GAAG,IAAA,qBAAW,EAAC,EAAE,CAAC,CAAC;IAEnC,IAAI,CAAC,IAAA,qBAAc,EAAC,UAAU,CAAC,EAAE;QAC/B,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAC;KACH;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,2CAA2C;AAC3C,SAAS,sBAAsB,CAC7B,OAAsC;IAEtC,OAAO,OAAO,IAAI,mCAAoB,CAAC;AACzC,CAAC","sourcesContent":["import { TypedTransaction } from '@ethereumjs/tx';\nimport {\n arrToBufArr,\n bufferToHex,\n ecsign,\n isValidPrivate,\n privateToPublic,\n publicToAddress,\n stripHexPrefix,\n toBuffer,\n} from '@ethereumjs/util';\nimport {\n concatSig,\n decrypt,\n getEncryptionPublicKey,\n normalize,\n personalSign,\n signTypedData,\n SignTypedDataVersion,\n} from '@metamask/eth-sig-util';\nimport { add0x, Eip1024EncryptedData, Hex, Keyring } from '@metamask/utils';\nimport { keccak256 } from 'ethereum-cryptography/keccak';\nimport randombytes from 'randombytes';\n\ntype KeyringOpt = {\n withAppKeyOrigin?: string;\n version?: SignTypedDataVersion | string;\n};\n\nconst TYPE = 'Simple Key Pair';\n\nexport default class SimpleKeyring implements Keyring<string[]> {\n #wallets: { privateKey: Buffer; publicKey: Buffer }[];\n\n readonly type: string = TYPE;\n\n static type: string = TYPE;\n\n constructor(privateKeys: string[] = []) {\n this.#wallets = [];\n\n /* istanbul ignore next: It's not possible to write a unit test for this, because a constructor isn't allowed\n * to be async. Jest can't await the constructor, and when the error gets thrown, Jest can't catch it. */\n this.deserialize(privateKeys).catch((error: Error) => {\n throw new Error(`Problem deserializing SimpleKeyring ${error.message}`);\n });\n }\n\n async serialize() {\n return this.#wallets.map((a) => a.privateKey.toString('hex'));\n }\n\n async deserialize(privateKeys: string[] = []) {\n this.#wallets = privateKeys.map((hexPrivateKey) => {\n const strippedHexPrivateKey = stripHexPrefix(hexPrivateKey);\n const privateKey = Buffer.from(strippedHexPrivateKey, 'hex');\n const publicKey = privateToPublic(privateKey);\n return { privateKey, publicKey };\n });\n }\n\n async addAccounts(numAccounts = 1) {\n const newWallets = [];\n for (let i = 0; i < numAccounts; i++) {\n const privateKey = generateKey();\n const publicKey = privateToPublic(privateKey);\n newWallets.push({ privateKey, publicKey });\n }\n this.#wallets = this.#wallets.concat(newWallets);\n const hexWallets = newWallets.map(({ publicKey }) =>\n add0x(bufferToHex(publicToAddress(publicKey))),\n );\n return hexWallets;\n }\n\n async getAccounts() {\n return this.#wallets.map(({ publicKey }) =>\n add0x(bufferToHex(publicToAddress(publicKey))),\n );\n }\n\n async signTransaction(\n address: Hex,\n transaction: TypedTransaction,\n opts: KeyringOpt = {},\n ): Promise<TypedTransaction> {\n const privKey = this.#getPrivateKeyFor(address, opts);\n const signedTx = transaction.sign(privKey);\n // Newer versions of Ethereumjs-tx are immutable and return a new tx object\n return signedTx === undefined ? transaction : signedTx;\n }\n\n // For eth_sign, we need to sign arbitrary data:\n async signMessage(\n address: Hex,\n data: string,\n opts = { withAppKeyOrigin: '', validateMessage: true },\n ) {\n const message = stripHexPrefix(data);\n if (\n opts.validateMessage &&\n (message.length === 0 || !message.match(/^[a-fA-F0-9]*$/u))\n ) {\n throw new Error('Cannot sign invalid message');\n }\n const privKey = this.#getPrivateKeyFor(address, opts);\n const msgSig = ecsign(Buffer.from(message, 'hex'), privKey);\n const rawMsgSig = concatSig(toBuffer(msgSig.v), msgSig.r, msgSig.s);\n return rawMsgSig;\n }\n\n // For personal_sign, we need to prefix the message:\n async signPersonalMessage(\n address: Hex,\n msgHex: Hex,\n opts = { withAppKeyOrigin: '' },\n ) {\n const privKey = this.#getPrivateKeyFor(address, opts);\n return personalSign({ privateKey: privKey, data: msgHex });\n }\n\n // For eth_decryptMessage:\n async decryptMessage(withAccount: Hex, encryptedData: Eip1024EncryptedData) {\n const wallet = this.#getWalletForAccount(withAccount);\n const privateKey = wallet.privateKey.toString('hex');\n return decrypt({ privateKey, encryptedData });\n }\n\n // personal_signTypedData, signs data along with the schema\n async signTypedData(\n address: Hex,\n typedData: any,\n opts: KeyringOpt = { version: SignTypedDataVersion.V1 },\n ) {\n // Treat invalid versions as \"V1\"\n let version = SignTypedDataVersion.V1;\n\n if (opts.version && isSignTypedDataVersion(opts.version)) {\n version = SignTypedDataVersion[opts.version];\n }\n\n const privateKey = this.#getPrivateKeyFor(address, opts);\n return signTypedData({ privateKey, data: typedData, version });\n }\n\n // get public key for nacl\n async getEncryptionPublicKey(withAccount: Hex, opts?: KeyringOpt) {\n const privKey = this.#getPrivateKeyFor(withAccount, opts);\n const publicKey = getEncryptionPublicKey(privKey.toString('hex'));\n return publicKey;\n }\n\n #getPrivateKeyFor(address: Hex, opts: KeyringOpt = { withAppKeyOrigin: '' }) {\n if (!address) {\n throw new Error('Must specify address.');\n }\n const wallet = this.#getWalletForAccount(address, opts);\n return wallet.privateKey;\n }\n\n // returns an address specific to an app\n async getAppKeyAddress(address: Hex, origin: string) {\n if (!origin || typeof origin !== 'string') {\n throw new Error(`'origin' must be a non-empty string`);\n }\n const wallet = this.#getWalletForAccount(address, {\n withAppKeyOrigin: origin,\n });\n const appKeyAddress = add0x(bufferToHex(publicToAddress(wallet.publicKey)));\n return appKeyAddress;\n }\n\n // exportAccount should return a hex-encoded private key:\n async exportAccount(address: Hex, opts = { withAppKeyOrigin: '' }) {\n const wallet = this.#getWalletForAccount(address, opts);\n return wallet.privateKey.toString('hex');\n }\n\n removeAccount(address: string) {\n if (\n !this.#wallets\n .map(({ publicKey }) =>\n bufferToHex(publicToAddress(publicKey)).toLowerCase(),\n )\n .includes(address.toLowerCase())\n ) {\n throw new Error(`Address ${address} not found in this keyring`);\n }\n\n this.#wallets = this.#wallets.filter(\n ({ publicKey }) =>\n bufferToHex(publicToAddress(publicKey)).toLowerCase() !==\n address.toLowerCase(),\n );\n }\n\n #getWalletForAccount(account: string | number, opts: KeyringOpt = {}) {\n const address = normalize(account);\n let wallet = this.#wallets.find(\n ({ publicKey }) => bufferToHex(publicToAddress(publicKey)) === address,\n );\n if (!wallet) {\n throw new Error('Simple Keyring - Unable to find matching address.');\n }\n\n if (opts.withAppKeyOrigin) {\n const { privateKey } = wallet;\n const appKeyOriginBuffer = Buffer.from(opts.withAppKeyOrigin, 'utf8');\n const appKeyBuffer = Buffer.concat([privateKey, appKeyOriginBuffer]);\n const appKeyPrivateKey = arrToBufArr(keccak256(appKeyBuffer));\n const appKeyPublicKey = privateToPublic(appKeyPrivateKey);\n wallet = { privateKey: appKeyPrivateKey, publicKey: appKeyPublicKey };\n }\n\n return wallet;\n }\n}\n\n/**\n * Generate and validate a new random key of 32 bytes.\n *\n * @returns Buffer The generated key.\n */\nfunction generateKey(): Buffer {\n const privateKey = randombytes(32);\n\n if (!isValidPrivate(privateKey)) {\n throw new Error(\n 'Private key does not satisfy the curve requirements (ie. it is invalid)',\n );\n }\n return privateKey;\n}\n\n/**\n * Type predicate type guard to check if a string is in the enum SignTypedDataVersion.\n *\n * @param version - The string to check.\n * @returns Whether it's in the enum.\n */\n// TODO: Put this in @metamask/eth-sig-util\nfunction isSignTypedDataVersion(\n version: SignTypedDataVersion | string,\n): version is SignTypedDataVersion {\n return version in SignTypedDataVersion;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask/eth-simple-keyring",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"description": "A simple standard interface for a series of Ethereum private keys.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ethereum",
|
|
@@ -14,44 +14,63 @@
|
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "https://github.com/MetaMask/eth-simple-keyring.git"
|
|
16
16
|
},
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"main": "index.js",
|
|
17
|
+
"main": "dist/index.js",
|
|
18
|
+
"types": "dist/index.d.ts",
|
|
20
19
|
"files": [
|
|
21
|
-
"
|
|
20
|
+
"dist/"
|
|
22
21
|
],
|
|
23
22
|
"scripts": {
|
|
24
|
-
"
|
|
25
|
-
"
|
|
23
|
+
"build": "tsc --project tsconfig.build.json",
|
|
24
|
+
"build:clean": "rimraf dist && yarn build",
|
|
25
|
+
"build:docs": "typedoc",
|
|
26
|
+
"lint": "yarn lint:eslint && yarn lint:misc --check && yarn lint:dependencies",
|
|
27
|
+
"lint:dependencies": "depcheck",
|
|
26
28
|
"lint:eslint": "eslint . --cache --ext js,ts",
|
|
29
|
+
"lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write",
|
|
27
30
|
"lint:misc": "prettier '**/*.json' '**/*.md' '!CHANGELOG.md' '**/*.yml' '!.yarnrc.yml' --ignore-path .gitignore --no-error-on-unmatched-pattern",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
31
|
+
"prepack": "./scripts/prepack.sh",
|
|
32
|
+
"sample": "ts-node src/sample.ts",
|
|
33
|
+
"test": "jest",
|
|
34
|
+
"test:watch": "jest --watch"
|
|
30
35
|
},
|
|
31
36
|
"dependencies": {
|
|
32
|
-
"@ethereumjs/util": "^8.0.
|
|
33
|
-
"@metamask/eth-sig-util": "^
|
|
34
|
-
"
|
|
37
|
+
"@ethereumjs/util": "^8.0.5",
|
|
38
|
+
"@metamask/eth-sig-util": "^6.0.1",
|
|
39
|
+
"@metamask/utils": "^5.0.2",
|
|
40
|
+
"ethereum-cryptography": "^1.2.0",
|
|
35
41
|
"randombytes": "^2.1.0"
|
|
36
42
|
},
|
|
37
43
|
"devDependencies": {
|
|
38
|
-
"@ethereumjs/tx": "^4.
|
|
39
|
-
"@lavamoat/allow-scripts": "^2.
|
|
40
|
-
"@metamask/auto-changelog": "^3.
|
|
41
|
-
"@metamask/eslint-config": "^
|
|
42
|
-
"@metamask/eslint-config-jest": "^11.
|
|
43
|
-
"@metamask/eslint-config-nodejs": "^11.0
|
|
44
|
-
"@
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
44
|
+
"@ethereumjs/tx": "^4.1.1",
|
|
45
|
+
"@lavamoat/allow-scripts": "^2.3.0",
|
|
46
|
+
"@metamask/auto-changelog": "^3.1.0",
|
|
47
|
+
"@metamask/eslint-config": "^11.1.0",
|
|
48
|
+
"@metamask/eslint-config-jest": "^11.1.0",
|
|
49
|
+
"@metamask/eslint-config-nodejs": "^11.1.0",
|
|
50
|
+
"@metamask/eslint-config-typescript": "^11.1.0",
|
|
51
|
+
"@types/ethereumjs-tx": "^1.0.1",
|
|
52
|
+
"@types/jest": "^29.5.0",
|
|
53
|
+
"@types/node": "^18.15.10",
|
|
54
|
+
"@types/randombytes": "^2.0.0",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
|
56
|
+
"@typescript-eslint/parser": "^5.57.0",
|
|
57
|
+
"depcheck": "^1.4.3",
|
|
58
|
+
"eslint": "^8.36.0",
|
|
59
|
+
"eslint-config-prettier": "^8.8.0",
|
|
60
|
+
"eslint-plugin-import": "^2.27.5",
|
|
61
|
+
"eslint-plugin-jest": "^27.2.1",
|
|
62
|
+
"eslint-plugin-jsdoc": "^39.6.2",
|
|
49
63
|
"eslint-plugin-node": "^11.1.0",
|
|
50
|
-
"eslint-plugin-prettier": "^
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"prettier
|
|
64
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
65
|
+
"ethereumjs-tx": "^1.3.7",
|
|
66
|
+
"jest": "^29.5.0",
|
|
67
|
+
"prettier": "^2.8.7",
|
|
68
|
+
"ts-jest": "^29.0.5",
|
|
69
|
+
"ts-node": "^10.9.1",
|
|
70
|
+
"typedoc": "^0.25.1",
|
|
71
|
+
"typescript": "~4.8.4"
|
|
54
72
|
},
|
|
73
|
+
"packageManager": "yarn@3.3.0",
|
|
55
74
|
"engines": {
|
|
56
75
|
"node": ">=14.0.0"
|
|
57
76
|
},
|
|
@@ -63,8 +82,9 @@
|
|
|
63
82
|
"allowScripts": {
|
|
64
83
|
"keccak": true,
|
|
65
84
|
"secp256k1": true,
|
|
66
|
-
"@lavamoat/preinstall-always-fail": false
|
|
85
|
+
"@lavamoat/preinstall-always-fail": false,
|
|
86
|
+
"ethereumjs-tx>ethereumjs-util>ethereum-cryptography>keccak": false,
|
|
87
|
+
"ethereumjs-tx>ethereumjs-util>ethereum-cryptography>secp256k1": false
|
|
67
88
|
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
}
|
|
89
|
+
}
|
|
90
|
+
}
|
package/index.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
const { EventEmitter } = require('events');
|
|
2
|
-
const {
|
|
3
|
-
isValidPrivate,
|
|
4
|
-
stripHexPrefix,
|
|
5
|
-
privateToPublic,
|
|
6
|
-
bufferToHex,
|
|
7
|
-
publicToAddress,
|
|
8
|
-
ecsign,
|
|
9
|
-
arrToBufArr,
|
|
10
|
-
} = require('@ethereumjs/util');
|
|
11
|
-
const randomBytes = require('randombytes');
|
|
12
|
-
const { keccak256 } = require('ethereum-cryptography/keccak');
|
|
13
|
-
|
|
14
|
-
const type = 'Simple Key Pair';
|
|
15
|
-
const {
|
|
16
|
-
concatSig,
|
|
17
|
-
decrypt,
|
|
18
|
-
getEncryptionPublicKey,
|
|
19
|
-
normalize,
|
|
20
|
-
personalSign,
|
|
21
|
-
signTypedData,
|
|
22
|
-
SignTypedDataVersion,
|
|
23
|
-
} = require('@metamask/eth-sig-util');
|
|
24
|
-
|
|
25
|
-
function generateKey() {
|
|
26
|
-
const privateKey = randomBytes(32);
|
|
27
|
-
// I don't think this is possible, but this validation was here previously,
|
|
28
|
-
// so it has been preserved just in case.
|
|
29
|
-
// istanbul ignore next
|
|
30
|
-
if (!isValidPrivate(privateKey)) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
'Private key does not satisfy the curve requirements (ie. it is invalid)',
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
return privateKey;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
class SimpleKeyring extends EventEmitter {
|
|
39
|
-
constructor(opts) {
|
|
40
|
-
super();
|
|
41
|
-
this.type = type;
|
|
42
|
-
this._wallets = [];
|
|
43
|
-
this.deserialize(opts);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async serialize() {
|
|
47
|
-
return this._wallets.map(({ privateKey }) => privateKey.toString('hex'));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async deserialize(privateKeys = []) {
|
|
51
|
-
this._wallets = privateKeys.map((hexPrivateKey) => {
|
|
52
|
-
const strippedHexPrivateKey = stripHexPrefix(hexPrivateKey);
|
|
53
|
-
const privateKey = Buffer.from(strippedHexPrivateKey, 'hex');
|
|
54
|
-
const publicKey = privateToPublic(privateKey);
|
|
55
|
-
return { privateKey, publicKey };
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async addAccounts(n = 1) {
|
|
60
|
-
const newWallets = [];
|
|
61
|
-
for (let i = 0; i < n; i++) {
|
|
62
|
-
const privateKey = generateKey();
|
|
63
|
-
const publicKey = privateToPublic(privateKey);
|
|
64
|
-
newWallets.push({ privateKey, publicKey });
|
|
65
|
-
}
|
|
66
|
-
this._wallets = this._wallets.concat(newWallets);
|
|
67
|
-
const hexWallets = newWallets.map(({ publicKey }) =>
|
|
68
|
-
bufferToHex(publicToAddress(publicKey)),
|
|
69
|
-
);
|
|
70
|
-
return hexWallets;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async getAccounts() {
|
|
74
|
-
return this._wallets.map(({ publicKey }) =>
|
|
75
|
-
bufferToHex(publicToAddress(publicKey)),
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// tx is an instance of the ethereumjs-transaction class.
|
|
80
|
-
async signTransaction(address, tx, opts = {}) {
|
|
81
|
-
const privKey = this._getPrivateKeyFor(address, opts);
|
|
82
|
-
const signedTx = tx.sign(privKey);
|
|
83
|
-
// Newer versions of Ethereumjs-tx are immutable and return a new tx object
|
|
84
|
-
return signedTx === undefined ? tx : signedTx;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// For eth_sign, we need to sign arbitrary data:
|
|
88
|
-
async signMessage(address, data, opts = {}) {
|
|
89
|
-
const message = stripHexPrefix(data);
|
|
90
|
-
const privKey = this._getPrivateKeyFor(address, opts);
|
|
91
|
-
const msgSig = ecsign(Buffer.from(message, 'hex'), privKey);
|
|
92
|
-
const rawMsgSig = concatSig(msgSig.v, msgSig.r, msgSig.s);
|
|
93
|
-
return rawMsgSig;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// For personal_sign, we need to prefix the message:
|
|
97
|
-
async signPersonalMessage(address, msgHex, opts = {}) {
|
|
98
|
-
const privKey = this._getPrivateKeyFor(address, opts);
|
|
99
|
-
const privateKey = Buffer.from(privKey, 'hex');
|
|
100
|
-
const sig = personalSign({ privateKey, data: msgHex });
|
|
101
|
-
return sig;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// For eth_decryptMessage:
|
|
105
|
-
async decryptMessage(withAccount, encryptedData) {
|
|
106
|
-
const wallet = this._getWalletForAccount(withAccount);
|
|
107
|
-
const { privateKey } = wallet;
|
|
108
|
-
const sig = decrypt({ privateKey, encryptedData });
|
|
109
|
-
return sig;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// personal_signTypedData, signs data along with the schema
|
|
113
|
-
async signTypedData(
|
|
114
|
-
withAccount,
|
|
115
|
-
typedData,
|
|
116
|
-
opts = { version: SignTypedDataVersion.V1 },
|
|
117
|
-
) {
|
|
118
|
-
// Treat invalid versions as "V1"
|
|
119
|
-
const version = Object.keys(SignTypedDataVersion).includes(opts.version)
|
|
120
|
-
? opts.version
|
|
121
|
-
: SignTypedDataVersion.V1;
|
|
122
|
-
|
|
123
|
-
const privateKey = this._getPrivateKeyFor(withAccount, opts);
|
|
124
|
-
return signTypedData({ privateKey, data: typedData, version });
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// get public key for nacl
|
|
128
|
-
async getEncryptionPublicKey(withAccount, opts = {}) {
|
|
129
|
-
const privKey = this._getPrivateKeyFor(withAccount, opts);
|
|
130
|
-
const publicKey = getEncryptionPublicKey(privKey);
|
|
131
|
-
return publicKey;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
_getPrivateKeyFor(address, opts = {}) {
|
|
135
|
-
if (!address) {
|
|
136
|
-
throw new Error('Must specify address.');
|
|
137
|
-
}
|
|
138
|
-
const wallet = this._getWalletForAccount(address, opts);
|
|
139
|
-
return wallet.privateKey;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// returns an address specific to an app
|
|
143
|
-
async getAppKeyAddress(address, origin) {
|
|
144
|
-
if (!origin || typeof origin !== 'string') {
|
|
145
|
-
throw new Error(`'origin' must be a non-empty string`);
|
|
146
|
-
}
|
|
147
|
-
const wallet = this._getWalletForAccount(address, {
|
|
148
|
-
withAppKeyOrigin: origin,
|
|
149
|
-
});
|
|
150
|
-
const appKeyAddress = normalize(
|
|
151
|
-
publicToAddress(wallet.publicKey).toString('hex'),
|
|
152
|
-
);
|
|
153
|
-
return appKeyAddress;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// exportAccount should return a hex-encoded private key:
|
|
157
|
-
async exportAccount(address, opts = {}) {
|
|
158
|
-
const wallet = this._getWalletForAccount(address, opts);
|
|
159
|
-
return wallet.privateKey.toString('hex');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
removeAccount(address) {
|
|
163
|
-
if (
|
|
164
|
-
!this._wallets
|
|
165
|
-
.map(({ publicKey }) =>
|
|
166
|
-
bufferToHex(publicToAddress(publicKey)).toLowerCase(),
|
|
167
|
-
)
|
|
168
|
-
.includes(address.toLowerCase())
|
|
169
|
-
) {
|
|
170
|
-
throw new Error(`Address ${address} not found in this keyring`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
this._wallets = this._wallets.filter(
|
|
174
|
-
({ publicKey }) =>
|
|
175
|
-
bufferToHex(publicToAddress(publicKey)).toLowerCase() !==
|
|
176
|
-
address.toLowerCase(),
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* @private
|
|
182
|
-
*/
|
|
183
|
-
_getWalletForAccount(account, opts = {}) {
|
|
184
|
-
const address = normalize(account);
|
|
185
|
-
let wallet = this._wallets.find(
|
|
186
|
-
({ publicKey }) => bufferToHex(publicToAddress(publicKey)) === address,
|
|
187
|
-
);
|
|
188
|
-
if (!wallet) {
|
|
189
|
-
throw new Error('Simple Keyring - Unable to find matching address.');
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (opts.withAppKeyOrigin) {
|
|
193
|
-
const { privateKey } = wallet;
|
|
194
|
-
const appKeyOriginBuffer = Buffer.from(opts.withAppKeyOrigin, 'utf8');
|
|
195
|
-
const appKeyBuffer = Buffer.concat([privateKey, appKeyOriginBuffer]);
|
|
196
|
-
const appKeyPrivateKey = arrToBufArr(keccak256(appKeyBuffer, 256));
|
|
197
|
-
const appKeyPublicKey = privateToPublic(appKeyPrivateKey);
|
|
198
|
-
wallet = { privateKey: appKeyPrivateKey, publicKey: appKeyPublicKey };
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return wallet;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
SimpleKeyring.type = type;
|
|
206
|
-
module.exports = SimpleKeyring;
|