@metamask-previews/eth-simple-keyring 11.0.0-855692d → 11.0.0-ca02a28

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 CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add `SimpleKeyringV2` class implementing `KeyringV2` interface ([#409](https://github.com/MetaMask/accounts/pull/409)), ([#410](https://github.com/MetaMask/accounts/pull/410)), ([#413](https://github.com/MetaMask/accounts/pull/413))
13
+ - Wraps legacy `SimpleKeyring` to expose accounts via the unified `KeyringV2` API and the `KeyringAccount` type.
14
+ - Extends `EthKeyringWrapper` for common Ethereum logic.
15
+
10
16
  ## [11.0.0]
11
17
 
12
18
  ### Changed
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ 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");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var _SimpleKeyringV2_instances, _SimpleKeyringV2_createKeyringAccount, _SimpleKeyringV2_getPrivateKeys, _SimpleKeyringV2_setPrivateKeys, _SimpleKeyringV2_withRollback, _SimpleKeyringV2_importPrivateKeyOrRollback;
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.SimpleKeyringV2 = void 0;
10
+ const keyring_api_1 = require("@metamask/keyring-api");
11
+ const utils_1 = require("@metamask/utils");
12
+ /**
13
+ * Methods supported by SimpleKeyring EOA accounts.
14
+ * SimpleKeyring supports all standard signing methods plus encryption and app keys.
15
+ */
16
+ const SIMPLE_KEYRING_METHODS = [
17
+ keyring_api_1.EthMethod.SignTransaction,
18
+ keyring_api_1.EthMethod.Sign,
19
+ keyring_api_1.EthMethod.PersonalSign,
20
+ keyring_api_1.EthMethod.SignTypedDataV1,
21
+ keyring_api_1.EthMethod.SignTypedDataV3,
22
+ keyring_api_1.EthMethod.SignTypedDataV4,
23
+ keyring_api_1.EthKeyringMethod.Decrypt,
24
+ keyring_api_1.EthKeyringMethod.GetEncryptionPublicKey,
25
+ keyring_api_1.EthKeyringMethod.GetAppKeyAddress,
26
+ keyring_api_1.EthKeyringMethod.SignEip7702Authorization,
27
+ ];
28
+ const simpleKeyringV2Capabilities = {
29
+ scopes: [keyring_api_1.EthScope.Eoa],
30
+ privateKey: {
31
+ importFormats: [
32
+ { encoding: keyring_api_1.PrivateKeyEncoding.Hexadecimal, type: keyring_api_1.EthAccountType.Eoa },
33
+ ],
34
+ exportFormats: [{ encoding: keyring_api_1.PrivateKeyEncoding.Hexadecimal }],
35
+ },
36
+ };
37
+ class SimpleKeyringV2 extends keyring_api_1.EthKeyringWrapper {
38
+ constructor(options) {
39
+ super({
40
+ type: keyring_api_1.KeyringType.PrivateKey,
41
+ inner: options.legacyKeyring,
42
+ capabilities: simpleKeyringV2Capabilities,
43
+ });
44
+ _SimpleKeyringV2_instances.add(this);
45
+ }
46
+ async getAccounts() {
47
+ const addresses = await this.inner.getAccounts();
48
+ return addresses.map((address) => {
49
+ // Check if we already have this account in the registry
50
+ const existingId = this.registry.getAccountId(address);
51
+ if (existingId) {
52
+ const cached = this.registry.get(existingId);
53
+ if (cached) {
54
+ return cached;
55
+ }
56
+ }
57
+ // Create and register the account if not already cached
58
+ return __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_createKeyringAccount).call(this, address);
59
+ });
60
+ }
61
+ async createAccounts(options) {
62
+ return this.withLock(async () => {
63
+ // For SimpleKeyring, we only support private key import
64
+ if (options.type !== 'private-key:import') {
65
+ throw new Error(`Unsupported account creation type for SimpleKeyring: ${options.type}`);
66
+ }
67
+ // Validate account type
68
+ if (options.accountType !== keyring_api_1.EthAccountType.Eoa) {
69
+ throw new Error(`Unsupported account type for SimpleKeyring: ${options.accountType}. Only '${keyring_api_1.EthAccountType.Eoa}' is supported.`);
70
+ }
71
+ const { encoding, privateKey } = options;
72
+ // Validate encoding
73
+ if (encoding !== keyring_api_1.PrivateKeyEncoding.Hexadecimal) {
74
+ throw new Error(`Unsupported encoding for SimpleKeyring: ${encoding}. Only '${keyring_api_1.PrivateKeyEncoding.Hexadecimal}' is supported.`);
75
+ }
76
+ // Import the private key (with automatic rollback on failure)
77
+ const newAddress = await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_importPrivateKeyOrRollback).call(this, privateKey);
78
+ // Create and return the new KeyringAccount
79
+ const newAccount = __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_createKeyringAccount).call(this, newAddress);
80
+ return [newAccount];
81
+ });
82
+ }
83
+ /**
84
+ * Delete an account from the keyring.
85
+ *
86
+ * @param accountId - The account ID to delete.
87
+ */
88
+ async deleteAccount(accountId) {
89
+ await this.withLock(async () => {
90
+ const account = await this.getAccount(accountId);
91
+ // Remove from the legacy keyring
92
+ this.inner.removeAccount(account.address);
93
+ // Remove from the registry
94
+ this.registry.delete(accountId);
95
+ });
96
+ }
97
+ /**
98
+ * Export the private key for an account in hexadecimal format.
99
+ *
100
+ * @param accountId - The ID of the account to export.
101
+ * @param options - Export options (only hexadecimal encoding is supported).
102
+ * @returns The exported account with private key.
103
+ */
104
+ async exportAccount(accountId, options) {
105
+ const account = await this.getAccount(accountId);
106
+ const requestedEncoding = options?.encoding ?? keyring_api_1.PrivateKeyEncoding.Hexadecimal;
107
+ if (requestedEncoding !== keyring_api_1.PrivateKeyEncoding.Hexadecimal) {
108
+ throw new Error(`Unsupported encoding for SimpleKeyring: ${requestedEncoding}. Only '${keyring_api_1.PrivateKeyEncoding.Hexadecimal}' is supported.`);
109
+ }
110
+ const privateKeyHex = await this.inner.exportAccount(this.toHexAddress(account.address));
111
+ // Sanitize private key format
112
+ const privateKey = (0, utils_1.add0x)(privateKeyHex);
113
+ const exported = {
114
+ type: 'private-key',
115
+ privateKey,
116
+ encoding: keyring_api_1.PrivateKeyEncoding.Hexadecimal,
117
+ };
118
+ return exported;
119
+ }
120
+ }
121
+ exports.SimpleKeyringV2 = SimpleKeyringV2;
122
+ _SimpleKeyringV2_instances = new WeakSet(), _SimpleKeyringV2_createKeyringAccount = function _SimpleKeyringV2_createKeyringAccount(address) {
123
+ const id = this.registry.register(address);
124
+ const account = {
125
+ id,
126
+ type: keyring_api_1.EthAccountType.Eoa,
127
+ address,
128
+ scopes: [...this.capabilities.scopes],
129
+ methods: [...SIMPLE_KEYRING_METHODS],
130
+ options: {
131
+ entropy: {
132
+ type: keyring_api_1.KeyringAccountEntropyTypeOption.PrivateKey,
133
+ },
134
+ exportable: true,
135
+ },
136
+ };
137
+ // Add the account to the registry
138
+ this.registry.set(account);
139
+ return account;
140
+ }, _SimpleKeyringV2_getPrivateKeys =
141
+ /**
142
+ * Get all private keys from the inner SimpleKeyring.
143
+ *
144
+ * @returns An array of private keys in hexadecimal format.
145
+ */
146
+ async function _SimpleKeyringV2_getPrivateKeys() {
147
+ return await this.inner.serialize();
148
+ }, _SimpleKeyringV2_setPrivateKeys =
149
+ /**
150
+ * Set private keys in the inner SimpleKeyring.
151
+ *
152
+ * @param privateKeys - An array of private keys in hexadecimal format.
153
+ */
154
+ async function _SimpleKeyringV2_setPrivateKeys(privateKeys) {
155
+ await this.inner.deserialize(privateKeys);
156
+ }, _SimpleKeyringV2_withRollback =
157
+ /**
158
+ * Executes a transactional update on the inner keyring state.
159
+ * If the callback throws, the state is automatically rolled back.
160
+ *
161
+ * @param callback - A function that receives the current private keys and performs the update.
162
+ * Should return the result on success, or throw to trigger rollback.
163
+ * @returns The result of the callback.
164
+ * @throws Error if the callback throws (after rollback).
165
+ */
166
+ async function _SimpleKeyringV2_withRollback(callback) {
167
+ const originalPrivateKeys = await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_getPrivateKeys).call(this);
168
+ try {
169
+ return await callback(originalPrivateKeys);
170
+ }
171
+ catch (error) {
172
+ // Rollback on error
173
+ await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_setPrivateKeys).call(this, originalPrivateKeys);
174
+ throw error;
175
+ }
176
+ }, _SimpleKeyringV2_importPrivateKeyOrRollback =
177
+ /**
178
+ * Import a private key and return the new address.
179
+ * If the import fails (no new address added), rolls back to the original state.
180
+ *
181
+ * @param privateKey - The private key to import in hexadecimal format.
182
+ * @returns The address of the newly imported account.
183
+ * @throws Error if the import fails or no new address is added.
184
+ */
185
+ async function _SimpleKeyringV2_importPrivateKeyOrRollback(privateKey) {
186
+ return __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_withRollback).call(this, async (currentPrivateKeys) => {
187
+ // Get current addresses before import
188
+ const addressesBefore = new Set(await this.inner.getAccounts());
189
+ // Import the new private key
190
+ await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_setPrivateKeys).call(this, [...currentPrivateKeys, privateKey]);
191
+ // Get addresses after import and find the newly added one
192
+ const addressesAfter = await this.inner.getAccounts();
193
+ // Find the new address by diffing the two sets
194
+ const newAddresses = addressesAfter.filter((addr) => !addressesBefore.has(addr));
195
+ if (newAddresses.length !== 1 || !newAddresses[0]) {
196
+ throw new Error('Failed to import private key');
197
+ }
198
+ return newAddresses[0];
199
+ });
200
+ };
201
+ //# sourceMappingURL=simple-keyring-v2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-keyring-v2.cjs","sourceRoot":"","sources":["../src/simple-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type CreateAccountOptions,\n EthAccountType,\n EthKeyringMethod,\n EthKeyringWrapper,\n EthMethod,\n EthScope,\n type ExportAccountOptions,\n type ExportedAccount,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n PrivateKeyEncoding,\n} from '@metamask/keyring-api';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport { add0x, type Hex } from '@metamask/utils';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nimport type SimpleKeyring from './simple-keyring';\n\n/**\n * Methods supported by SimpleKeyring EOA accounts.\n * SimpleKeyring supports all standard signing methods plus encryption and app keys.\n */\nconst SIMPLE_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.Sign,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n EthKeyringMethod.Decrypt,\n EthKeyringMethod.GetEncryptionPublicKey,\n EthKeyringMethod.GetAppKeyAddress,\n EthKeyringMethod.SignEip7702Authorization,\n];\n\nconst simpleKeyringV2Capabilities: KeyringCapabilities = {\n scopes: [EthScope.Eoa],\n privateKey: {\n importFormats: [\n { encoding: PrivateKeyEncoding.Hexadecimal, type: EthAccountType.Eoa },\n ],\n exportFormats: [{ encoding: PrivateKeyEncoding.Hexadecimal }],\n },\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link SimpleKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * SimpleKeyring via the unified V2 interface.\n */\nexport type SimpleKeyringV2Options = {\n legacyKeyring: SimpleKeyring;\n};\n\nexport class SimpleKeyringV2\n extends EthKeyringWrapper<SimpleKeyring>\n implements KeyringV2\n{\n constructor(options: SimpleKeyringV2Options) {\n super({\n type: KeyringType.PrivateKey,\n inner: options.legacyKeyring,\n capabilities: simpleKeyringV2Capabilities,\n });\n }\n\n /**\n * Creates a KeyringAccount object for the given address and index.\n *\n * @param address - The account address.\n * @returns The created KeyringAccount.\n */\n #createKeyringAccount(address: Hex): KeyringAccount {\n const id = this.registry.register(address);\n\n const account: KeyringAccount = {\n id,\n type: EthAccountType.Eoa,\n address,\n scopes: [...this.capabilities.scopes],\n methods: [...SIMPLE_KEYRING_METHODS],\n options: {\n entropy: {\n type: KeyringAccountEntropyTypeOption.PrivateKey,\n },\n exportable: true,\n },\n };\n\n // Add the account to the registry\n this.registry.set(account);\n\n return account;\n }\n\n /**\n * Get all private keys from the inner SimpleKeyring.\n *\n * @returns An array of private keys in hexadecimal format.\n */\n async #getPrivateKeys(): Promise<string[]> {\n return await this.inner.serialize();\n }\n\n /**\n * Set private keys in the inner SimpleKeyring.\n *\n * @param privateKeys - An array of private keys in hexadecimal format.\n */\n async #setPrivateKeys(privateKeys: string[]): Promise<void> {\n await this.inner.deserialize(privateKeys);\n }\n\n /**\n * Executes a transactional update on the inner keyring state.\n * If the callback throws, the state is automatically rolled back.\n *\n * @param callback - A function that receives the current private keys and performs the update.\n * Should return the result on success, or throw to trigger rollback.\n * @returns The result of the callback.\n * @throws Error if the callback throws (after rollback).\n */\n async #withRollback<Result>(\n callback: (currentPrivateKeys: string[]) => Promise<Result>,\n ): Promise<Result> {\n const originalPrivateKeys = await this.#getPrivateKeys();\n\n try {\n return await callback(originalPrivateKeys);\n } catch (error) {\n // Rollback on error\n await this.#setPrivateKeys(originalPrivateKeys);\n throw error;\n }\n }\n\n /**\n * Import a private key and return the new address.\n * If the import fails (no new address added), rolls back to the original state.\n *\n * @param privateKey - The private key to import in hexadecimal format.\n * @returns The address of the newly imported account.\n * @throws Error if the import fails or no new address is added.\n */\n async #importPrivateKeyOrRollback(privateKey: string): Promise<Hex> {\n return this.#withRollback(async (currentPrivateKeys) => {\n // Get current addresses before import\n const addressesBefore = new Set(await this.inner.getAccounts());\n\n // Import the new private key\n await this.#setPrivateKeys([...currentPrivateKeys, privateKey]);\n\n // Get addresses after import and find the newly added one\n const addressesAfter = await this.inner.getAccounts();\n\n // Find the new address by diffing the two sets\n const newAddresses = addressesAfter.filter(\n (addr) => !addressesBefore.has(addr),\n );\n\n if (newAddresses.length !== 1 || !newAddresses[0]) {\n throw new Error('Failed to import private key');\n }\n\n return newAddresses[0];\n });\n }\n\n async getAccounts(): Promise<KeyringAccount[]> {\n const addresses = await this.inner.getAccounts();\n\n return addresses.map((address) => {\n // Check if we already have this account in the registry\n const existingId = this.registry.getAccountId(address);\n if (existingId) {\n const cached = this.registry.get(existingId);\n if (cached) {\n return cached;\n }\n }\n\n // Create and register the account if not already cached\n return this.#createKeyringAccount(address);\n });\n }\n\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<KeyringAccount[]> {\n return this.withLock(async () => {\n // For SimpleKeyring, we only support private key import\n if (options.type !== 'private-key:import') {\n throw new Error(\n `Unsupported account creation type for SimpleKeyring: ${options.type}`,\n );\n }\n\n // Validate account type\n if (options.accountType !== EthAccountType.Eoa) {\n throw new Error(\n `Unsupported account type for SimpleKeyring: ${options.accountType}. Only '${EthAccountType.Eoa}' is supported.`,\n );\n }\n\n const { encoding, privateKey } = options;\n\n // Validate encoding\n if (encoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for SimpleKeyring: ${encoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n // Import the private key (with automatic rollback on failure)\n const newAddress = await this.#importPrivateKeyOrRollback(privateKey);\n\n // Create and return the new KeyringAccount\n const newAccount = this.#createKeyringAccount(newAddress);\n return [newAccount];\n });\n }\n\n /**\n * Delete an account from the keyring.\n *\n * @param accountId - The account ID to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n await this.withLock(async () => {\n const account = await this.getAccount(accountId);\n\n // Remove from the legacy keyring\n this.inner.removeAccount(account.address);\n\n // Remove from the registry\n this.registry.delete(accountId);\n });\n }\n\n /**\n * Export the private key for an account in hexadecimal format.\n *\n * @param accountId - The ID of the account to export.\n * @param options - Export options (only hexadecimal encoding is supported).\n * @returns The exported account with private key.\n */\n async exportAccount(\n accountId: AccountId,\n options?: ExportAccountOptions,\n ): Promise<ExportedAccount> {\n const account = await this.getAccount(accountId);\n\n const requestedEncoding =\n options?.encoding ?? PrivateKeyEncoding.Hexadecimal;\n\n if (requestedEncoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for SimpleKeyring: ${requestedEncoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n const privateKeyHex = await this.inner.exportAccount(\n this.toHexAddress(account.address),\n );\n // Sanitize private key format\n const privateKey = add0x(privateKeyHex);\n\n const exported: ExportedAccount = {\n type: 'private-key',\n privateKey,\n encoding: PrivateKeyEncoding.Hexadecimal,\n };\n\n return exported;\n }\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import { type CreateAccountOptions, EthKeyringWrapper, type ExportAccountOptions, type ExportedAccount, type KeyringAccount, type KeyringV2 } from "@metamask/keyring-api";
2
+ import type { AccountId } from "@metamask/keyring-utils";
3
+ import type SimpleKeyring from "./simple-keyring.cjs";
4
+ /**
5
+ * Concrete {@link KeyringV2} adapter for {@link SimpleKeyring}.
6
+ *
7
+ * This wrapper exposes the accounts and signing capabilities of the legacy
8
+ * SimpleKeyring via the unified V2 interface.
9
+ */
10
+ export type SimpleKeyringV2Options = {
11
+ legacyKeyring: SimpleKeyring;
12
+ };
13
+ export declare class SimpleKeyringV2 extends EthKeyringWrapper<SimpleKeyring> implements KeyringV2 {
14
+ #private;
15
+ constructor(options: SimpleKeyringV2Options);
16
+ getAccounts(): Promise<KeyringAccount[]>;
17
+ createAccounts(options: CreateAccountOptions): Promise<KeyringAccount[]>;
18
+ /**
19
+ * Delete an account from the keyring.
20
+ *
21
+ * @param accountId - The account ID to delete.
22
+ */
23
+ deleteAccount(accountId: AccountId): Promise<void>;
24
+ /**
25
+ * Export the private key for an account in hexadecimal format.
26
+ *
27
+ * @param accountId - The ID of the account to export.
28
+ * @param options - Export options (only hexadecimal encoding is supported).
29
+ * @returns The exported account with private key.
30
+ */
31
+ exportAccount(accountId: AccountId, options?: ExportAccountOptions): Promise<ExportedAccount>;
32
+ }
33
+ //# sourceMappingURL=simple-keyring-v2.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-keyring-v2.d.cts","sourceRoot":"","sources":["../src/simple-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EAGzB,iBAAiB,EAGjB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAGf,8BAA8B;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,gCAAgC;AAIzD,OAAO,KAAK,aAAa,6BAAyB;AA6BlD;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF,qBAAa,eACX,SAAQ,iBAAiB,CAAC,aAAa,CACvC,YAAW,SAAS;;gBAER,OAAO,EAAE,sBAAsB;IA8GrC,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAkBxC,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,cAAc,EAAE,CAAC;IAkC5B;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxD;;;;;;OAMG;IACG,aAAa,CACjB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,eAAe,CAAC;CA0B5B"}
@@ -0,0 +1,33 @@
1
+ import { type CreateAccountOptions, EthKeyringWrapper, type ExportAccountOptions, type ExportedAccount, type KeyringAccount, type KeyringV2 } from "@metamask/keyring-api";
2
+ import type { AccountId } from "@metamask/keyring-utils";
3
+ import type SimpleKeyring from "./simple-keyring.mjs";
4
+ /**
5
+ * Concrete {@link KeyringV2} adapter for {@link SimpleKeyring}.
6
+ *
7
+ * This wrapper exposes the accounts and signing capabilities of the legacy
8
+ * SimpleKeyring via the unified V2 interface.
9
+ */
10
+ export type SimpleKeyringV2Options = {
11
+ legacyKeyring: SimpleKeyring;
12
+ };
13
+ export declare class SimpleKeyringV2 extends EthKeyringWrapper<SimpleKeyring> implements KeyringV2 {
14
+ #private;
15
+ constructor(options: SimpleKeyringV2Options);
16
+ getAccounts(): Promise<KeyringAccount[]>;
17
+ createAccounts(options: CreateAccountOptions): Promise<KeyringAccount[]>;
18
+ /**
19
+ * Delete an account from the keyring.
20
+ *
21
+ * @param accountId - The account ID to delete.
22
+ */
23
+ deleteAccount(accountId: AccountId): Promise<void>;
24
+ /**
25
+ * Export the private key for an account in hexadecimal format.
26
+ *
27
+ * @param accountId - The ID of the account to export.
28
+ * @param options - Export options (only hexadecimal encoding is supported).
29
+ * @returns The exported account with private key.
30
+ */
31
+ exportAccount(accountId: AccountId, options?: ExportAccountOptions): Promise<ExportedAccount>;
32
+ }
33
+ //# sourceMappingURL=simple-keyring-v2.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-keyring-v2.d.mts","sourceRoot":"","sources":["../src/simple-keyring-v2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EAGzB,iBAAiB,EAGjB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,cAAc,EAGnB,KAAK,SAAS,EAGf,8BAA8B;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,gCAAgC;AAIzD,OAAO,KAAK,aAAa,6BAAyB;AA6BlD;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF,qBAAa,eACX,SAAQ,iBAAiB,CAAC,aAAa,CACvC,YAAW,SAAS;;gBAER,OAAO,EAAE,sBAAsB;IA8GrC,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAkBxC,cAAc,CAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,cAAc,EAAE,CAAC;IAkC5B;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxD;;;;;;OAMG;IACG,aAAa,CACjB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,eAAe,CAAC;CA0B5B"}
@@ -0,0 +1,197 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ 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");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _SimpleKeyringV2_instances, _SimpleKeyringV2_createKeyringAccount, _SimpleKeyringV2_getPrivateKeys, _SimpleKeyringV2_setPrivateKeys, _SimpleKeyringV2_withRollback, _SimpleKeyringV2_importPrivateKeyOrRollback;
7
+ import { EthAccountType, EthKeyringMethod, EthKeyringWrapper, EthMethod, EthScope, KeyringAccountEntropyTypeOption, KeyringType, PrivateKeyEncoding } from "@metamask/keyring-api";
8
+ import { add0x } from "@metamask/utils";
9
+ /**
10
+ * Methods supported by SimpleKeyring EOA accounts.
11
+ * SimpleKeyring supports all standard signing methods plus encryption and app keys.
12
+ */
13
+ const SIMPLE_KEYRING_METHODS = [
14
+ EthMethod.SignTransaction,
15
+ EthMethod.Sign,
16
+ EthMethod.PersonalSign,
17
+ EthMethod.SignTypedDataV1,
18
+ EthMethod.SignTypedDataV3,
19
+ EthMethod.SignTypedDataV4,
20
+ EthKeyringMethod.Decrypt,
21
+ EthKeyringMethod.GetEncryptionPublicKey,
22
+ EthKeyringMethod.GetAppKeyAddress,
23
+ EthKeyringMethod.SignEip7702Authorization,
24
+ ];
25
+ const simpleKeyringV2Capabilities = {
26
+ scopes: [EthScope.Eoa],
27
+ privateKey: {
28
+ importFormats: [
29
+ { encoding: PrivateKeyEncoding.Hexadecimal, type: EthAccountType.Eoa },
30
+ ],
31
+ exportFormats: [{ encoding: PrivateKeyEncoding.Hexadecimal }],
32
+ },
33
+ };
34
+ export class SimpleKeyringV2 extends EthKeyringWrapper {
35
+ constructor(options) {
36
+ super({
37
+ type: KeyringType.PrivateKey,
38
+ inner: options.legacyKeyring,
39
+ capabilities: simpleKeyringV2Capabilities,
40
+ });
41
+ _SimpleKeyringV2_instances.add(this);
42
+ }
43
+ async getAccounts() {
44
+ const addresses = await this.inner.getAccounts();
45
+ return addresses.map((address) => {
46
+ // Check if we already have this account in the registry
47
+ const existingId = this.registry.getAccountId(address);
48
+ if (existingId) {
49
+ const cached = this.registry.get(existingId);
50
+ if (cached) {
51
+ return cached;
52
+ }
53
+ }
54
+ // Create and register the account if not already cached
55
+ return __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_createKeyringAccount).call(this, address);
56
+ });
57
+ }
58
+ async createAccounts(options) {
59
+ return this.withLock(async () => {
60
+ // For SimpleKeyring, we only support private key import
61
+ if (options.type !== 'private-key:import') {
62
+ throw new Error(`Unsupported account creation type for SimpleKeyring: ${options.type}`);
63
+ }
64
+ // Validate account type
65
+ if (options.accountType !== EthAccountType.Eoa) {
66
+ throw new Error(`Unsupported account type for SimpleKeyring: ${options.accountType}. Only '${EthAccountType.Eoa}' is supported.`);
67
+ }
68
+ const { encoding, privateKey } = options;
69
+ // Validate encoding
70
+ if (encoding !== PrivateKeyEncoding.Hexadecimal) {
71
+ throw new Error(`Unsupported encoding for SimpleKeyring: ${encoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`);
72
+ }
73
+ // Import the private key (with automatic rollback on failure)
74
+ const newAddress = await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_importPrivateKeyOrRollback).call(this, privateKey);
75
+ // Create and return the new KeyringAccount
76
+ const newAccount = __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_createKeyringAccount).call(this, newAddress);
77
+ return [newAccount];
78
+ });
79
+ }
80
+ /**
81
+ * Delete an account from the keyring.
82
+ *
83
+ * @param accountId - The account ID to delete.
84
+ */
85
+ async deleteAccount(accountId) {
86
+ await this.withLock(async () => {
87
+ const account = await this.getAccount(accountId);
88
+ // Remove from the legacy keyring
89
+ this.inner.removeAccount(account.address);
90
+ // Remove from the registry
91
+ this.registry.delete(accountId);
92
+ });
93
+ }
94
+ /**
95
+ * Export the private key for an account in hexadecimal format.
96
+ *
97
+ * @param accountId - The ID of the account to export.
98
+ * @param options - Export options (only hexadecimal encoding is supported).
99
+ * @returns The exported account with private key.
100
+ */
101
+ async exportAccount(accountId, options) {
102
+ const account = await this.getAccount(accountId);
103
+ const requestedEncoding = options?.encoding ?? PrivateKeyEncoding.Hexadecimal;
104
+ if (requestedEncoding !== PrivateKeyEncoding.Hexadecimal) {
105
+ throw new Error(`Unsupported encoding for SimpleKeyring: ${requestedEncoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`);
106
+ }
107
+ const privateKeyHex = await this.inner.exportAccount(this.toHexAddress(account.address));
108
+ // Sanitize private key format
109
+ const privateKey = add0x(privateKeyHex);
110
+ const exported = {
111
+ type: 'private-key',
112
+ privateKey,
113
+ encoding: PrivateKeyEncoding.Hexadecimal,
114
+ };
115
+ return exported;
116
+ }
117
+ }
118
+ _SimpleKeyringV2_instances = new WeakSet(), _SimpleKeyringV2_createKeyringAccount = function _SimpleKeyringV2_createKeyringAccount(address) {
119
+ const id = this.registry.register(address);
120
+ const account = {
121
+ id,
122
+ type: EthAccountType.Eoa,
123
+ address,
124
+ scopes: [...this.capabilities.scopes],
125
+ methods: [...SIMPLE_KEYRING_METHODS],
126
+ options: {
127
+ entropy: {
128
+ type: KeyringAccountEntropyTypeOption.PrivateKey,
129
+ },
130
+ exportable: true,
131
+ },
132
+ };
133
+ // Add the account to the registry
134
+ this.registry.set(account);
135
+ return account;
136
+ }, _SimpleKeyringV2_getPrivateKeys =
137
+ /**
138
+ * Get all private keys from the inner SimpleKeyring.
139
+ *
140
+ * @returns An array of private keys in hexadecimal format.
141
+ */
142
+ async function _SimpleKeyringV2_getPrivateKeys() {
143
+ return await this.inner.serialize();
144
+ }, _SimpleKeyringV2_setPrivateKeys =
145
+ /**
146
+ * Set private keys in the inner SimpleKeyring.
147
+ *
148
+ * @param privateKeys - An array of private keys in hexadecimal format.
149
+ */
150
+ async function _SimpleKeyringV2_setPrivateKeys(privateKeys) {
151
+ await this.inner.deserialize(privateKeys);
152
+ }, _SimpleKeyringV2_withRollback =
153
+ /**
154
+ * Executes a transactional update on the inner keyring state.
155
+ * If the callback throws, the state is automatically rolled back.
156
+ *
157
+ * @param callback - A function that receives the current private keys and performs the update.
158
+ * Should return the result on success, or throw to trigger rollback.
159
+ * @returns The result of the callback.
160
+ * @throws Error if the callback throws (after rollback).
161
+ */
162
+ async function _SimpleKeyringV2_withRollback(callback) {
163
+ const originalPrivateKeys = await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_getPrivateKeys).call(this);
164
+ try {
165
+ return await callback(originalPrivateKeys);
166
+ }
167
+ catch (error) {
168
+ // Rollback on error
169
+ await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_setPrivateKeys).call(this, originalPrivateKeys);
170
+ throw error;
171
+ }
172
+ }, _SimpleKeyringV2_importPrivateKeyOrRollback =
173
+ /**
174
+ * Import a private key and return the new address.
175
+ * If the import fails (no new address added), rolls back to the original state.
176
+ *
177
+ * @param privateKey - The private key to import in hexadecimal format.
178
+ * @returns The address of the newly imported account.
179
+ * @throws Error if the import fails or no new address is added.
180
+ */
181
+ async function _SimpleKeyringV2_importPrivateKeyOrRollback(privateKey) {
182
+ return __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_withRollback).call(this, async (currentPrivateKeys) => {
183
+ // Get current addresses before import
184
+ const addressesBefore = new Set(await this.inner.getAccounts());
185
+ // Import the new private key
186
+ await __classPrivateFieldGet(this, _SimpleKeyringV2_instances, "m", _SimpleKeyringV2_setPrivateKeys).call(this, [...currentPrivateKeys, privateKey]);
187
+ // Get addresses after import and find the newly added one
188
+ const addressesAfter = await this.inner.getAccounts();
189
+ // Find the new address by diffing the two sets
190
+ const newAddresses = addressesAfter.filter((addr) => !addressesBefore.has(addr));
191
+ if (newAddresses.length !== 1 || !newAddresses[0]) {
192
+ throw new Error('Failed to import private key');
193
+ }
194
+ return newAddresses[0];
195
+ });
196
+ };
197
+ //# sourceMappingURL=simple-keyring-v2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-keyring-v2.mjs","sourceRoot":"","sources":["../src/simple-keyring-v2.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type CreateAccountOptions,\n EthAccountType,\n EthKeyringMethod,\n EthKeyringWrapper,\n EthMethod,\n EthScope,\n type ExportAccountOptions,\n type ExportedAccount,\n type KeyringAccount,\n KeyringAccountEntropyTypeOption,\n type KeyringCapabilities,\n type KeyringV2,\n KeyringType,\n PrivateKeyEncoding,\n} from '@metamask/keyring-api';\nimport type { AccountId } from '@metamask/keyring-utils';\nimport { add0x, type Hex } from '@metamask/utils';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nimport type SimpleKeyring from './simple-keyring';\n\n/**\n * Methods supported by SimpleKeyring EOA accounts.\n * SimpleKeyring supports all standard signing methods plus encryption and app keys.\n */\nconst SIMPLE_KEYRING_METHODS = [\n EthMethod.SignTransaction,\n EthMethod.Sign,\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n EthKeyringMethod.Decrypt,\n EthKeyringMethod.GetEncryptionPublicKey,\n EthKeyringMethod.GetAppKeyAddress,\n EthKeyringMethod.SignEip7702Authorization,\n];\n\nconst simpleKeyringV2Capabilities: KeyringCapabilities = {\n scopes: [EthScope.Eoa],\n privateKey: {\n importFormats: [\n { encoding: PrivateKeyEncoding.Hexadecimal, type: EthAccountType.Eoa },\n ],\n exportFormats: [{ encoding: PrivateKeyEncoding.Hexadecimal }],\n },\n};\n\n/**\n * Concrete {@link KeyringV2} adapter for {@link SimpleKeyring}.\n *\n * This wrapper exposes the accounts and signing capabilities of the legacy\n * SimpleKeyring via the unified V2 interface.\n */\nexport type SimpleKeyringV2Options = {\n legacyKeyring: SimpleKeyring;\n};\n\nexport class SimpleKeyringV2\n extends EthKeyringWrapper<SimpleKeyring>\n implements KeyringV2\n{\n constructor(options: SimpleKeyringV2Options) {\n super({\n type: KeyringType.PrivateKey,\n inner: options.legacyKeyring,\n capabilities: simpleKeyringV2Capabilities,\n });\n }\n\n /**\n * Creates a KeyringAccount object for the given address and index.\n *\n * @param address - The account address.\n * @returns The created KeyringAccount.\n */\n #createKeyringAccount(address: Hex): KeyringAccount {\n const id = this.registry.register(address);\n\n const account: KeyringAccount = {\n id,\n type: EthAccountType.Eoa,\n address,\n scopes: [...this.capabilities.scopes],\n methods: [...SIMPLE_KEYRING_METHODS],\n options: {\n entropy: {\n type: KeyringAccountEntropyTypeOption.PrivateKey,\n },\n exportable: true,\n },\n };\n\n // Add the account to the registry\n this.registry.set(account);\n\n return account;\n }\n\n /**\n * Get all private keys from the inner SimpleKeyring.\n *\n * @returns An array of private keys in hexadecimal format.\n */\n async #getPrivateKeys(): Promise<string[]> {\n return await this.inner.serialize();\n }\n\n /**\n * Set private keys in the inner SimpleKeyring.\n *\n * @param privateKeys - An array of private keys in hexadecimal format.\n */\n async #setPrivateKeys(privateKeys: string[]): Promise<void> {\n await this.inner.deserialize(privateKeys);\n }\n\n /**\n * Executes a transactional update on the inner keyring state.\n * If the callback throws, the state is automatically rolled back.\n *\n * @param callback - A function that receives the current private keys and performs the update.\n * Should return the result on success, or throw to trigger rollback.\n * @returns The result of the callback.\n * @throws Error if the callback throws (after rollback).\n */\n async #withRollback<Result>(\n callback: (currentPrivateKeys: string[]) => Promise<Result>,\n ): Promise<Result> {\n const originalPrivateKeys = await this.#getPrivateKeys();\n\n try {\n return await callback(originalPrivateKeys);\n } catch (error) {\n // Rollback on error\n await this.#setPrivateKeys(originalPrivateKeys);\n throw error;\n }\n }\n\n /**\n * Import a private key and return the new address.\n * If the import fails (no new address added), rolls back to the original state.\n *\n * @param privateKey - The private key to import in hexadecimal format.\n * @returns The address of the newly imported account.\n * @throws Error if the import fails or no new address is added.\n */\n async #importPrivateKeyOrRollback(privateKey: string): Promise<Hex> {\n return this.#withRollback(async (currentPrivateKeys) => {\n // Get current addresses before import\n const addressesBefore = new Set(await this.inner.getAccounts());\n\n // Import the new private key\n await this.#setPrivateKeys([...currentPrivateKeys, privateKey]);\n\n // Get addresses after import and find the newly added one\n const addressesAfter = await this.inner.getAccounts();\n\n // Find the new address by diffing the two sets\n const newAddresses = addressesAfter.filter(\n (addr) => !addressesBefore.has(addr),\n );\n\n if (newAddresses.length !== 1 || !newAddresses[0]) {\n throw new Error('Failed to import private key');\n }\n\n return newAddresses[0];\n });\n }\n\n async getAccounts(): Promise<KeyringAccount[]> {\n const addresses = await this.inner.getAccounts();\n\n return addresses.map((address) => {\n // Check if we already have this account in the registry\n const existingId = this.registry.getAccountId(address);\n if (existingId) {\n const cached = this.registry.get(existingId);\n if (cached) {\n return cached;\n }\n }\n\n // Create and register the account if not already cached\n return this.#createKeyringAccount(address);\n });\n }\n\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<KeyringAccount[]> {\n return this.withLock(async () => {\n // For SimpleKeyring, we only support private key import\n if (options.type !== 'private-key:import') {\n throw new Error(\n `Unsupported account creation type for SimpleKeyring: ${options.type}`,\n );\n }\n\n // Validate account type\n if (options.accountType !== EthAccountType.Eoa) {\n throw new Error(\n `Unsupported account type for SimpleKeyring: ${options.accountType}. Only '${EthAccountType.Eoa}' is supported.`,\n );\n }\n\n const { encoding, privateKey } = options;\n\n // Validate encoding\n if (encoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for SimpleKeyring: ${encoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n // Import the private key (with automatic rollback on failure)\n const newAddress = await this.#importPrivateKeyOrRollback(privateKey);\n\n // Create and return the new KeyringAccount\n const newAccount = this.#createKeyringAccount(newAddress);\n return [newAccount];\n });\n }\n\n /**\n * Delete an account from the keyring.\n *\n * @param accountId - The account ID to delete.\n */\n async deleteAccount(accountId: AccountId): Promise<void> {\n await this.withLock(async () => {\n const account = await this.getAccount(accountId);\n\n // Remove from the legacy keyring\n this.inner.removeAccount(account.address);\n\n // Remove from the registry\n this.registry.delete(accountId);\n });\n }\n\n /**\n * Export the private key for an account in hexadecimal format.\n *\n * @param accountId - The ID of the account to export.\n * @param options - Export options (only hexadecimal encoding is supported).\n * @returns The exported account with private key.\n */\n async exportAccount(\n accountId: AccountId,\n options?: ExportAccountOptions,\n ): Promise<ExportedAccount> {\n const account = await this.getAccount(accountId);\n\n const requestedEncoding =\n options?.encoding ?? PrivateKeyEncoding.Hexadecimal;\n\n if (requestedEncoding !== PrivateKeyEncoding.Hexadecimal) {\n throw new Error(\n `Unsupported encoding for SimpleKeyring: ${requestedEncoding}. Only '${PrivateKeyEncoding.Hexadecimal}' is supported.`,\n );\n }\n\n const privateKeyHex = await this.inner.exportAccount(\n this.toHexAddress(account.address),\n );\n // Sanitize private key format\n const privateKey = add0x(privateKeyHex);\n\n const exported: ExportedAccount = {\n type: 'private-key',\n privateKey,\n encoding: PrivateKeyEncoding.Hexadecimal,\n };\n\n return exported;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/eth-simple-keyring",
3
- "version": "11.0.0-855692d",
3
+ "version": "11.0.0-ca02a28",
4
4
  "description": "A simple standard interface for a series of Ethereum private keys.",
5
5
  "keywords": [
6
6
  "ethereum",
@@ -46,6 +46,7 @@
46
46
  "dependencies": {
47
47
  "@ethereumjs/util": "^9.1.0",
48
48
  "@metamask/eth-sig-util": "^8.2.0",
49
+ "@metamask/keyring-api": "21.3.0",
49
50
  "@metamask/utils": "^11.1.0",
50
51
  "ethereum-cryptography": "^2.1.2",
51
52
  "randombytes": "^2.1.0"