Skip to content

Commit 64b22ec

Browse files
committed
feat: add createAccounts
1 parent 204cc79 commit 64b22ec

File tree

7 files changed

+93
-0
lines changed

7 files changed

+93
-0
lines changed

packages/keyring-api/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- Add `Keyring.createAccounts` optional method ([#448](https://github.com/MetaMask/accounts/pull/448))
13+
- This method is part of the keyring v2 specification and set as optional for backwards compatibility.
14+
- This method can be used to create one or more accounts using the new keyring v2 account creation typed options.
1215
- Add support for account derivations using range of indices in `KeyringV2` ([#451](https://github.com/MetaMask/accounts/pull/451))
1316
- Add `bip44:derive-index-range` capability to `KeyringCapabilities`.
1417
- Add `AccountCreationType.Bip44DeriveIndexRange` and `CreateAccountBip44DeriveIndexRangeOptions`.

packages/keyring-api/src/api/keyring.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { Paginated, Pagination } from './pagination';
1313
import type { KeyringRequest } from './request';
1414
import type { KeyringResponse } from './response';
1515
import type { Transaction } from './transaction';
16+
import type { CreateAccountOptions } from './v2';
1617

1718
/**
1819
* Keyring interface.
@@ -56,6 +57,19 @@ export type Keyring = {
5657
options?: Record<string, Json> & MetaMaskOptions,
5758
): Promise<KeyringAccount>;
5859

60+
/**
61+
* Creates one or more new accounts according to the provided options.
62+
*
63+
* Deterministic account creation MUST be idempotent, meaning that for
64+
* deterministic algorithms, like BIP-44, calling this method with the same
65+
* options should always return the same accounts, even if the accounts
66+
* already exist in the keyring.
67+
*
68+
* @param options - Options describing how to create the account(s).
69+
* @returns A promise that resolves to an array of the created account objects.
70+
*/
71+
createAccounts?(options: CreateAccountOptions): Promise<KeyringAccount[]>;
72+
5973
/**
6074
* Lists the assets of an account (fungibles and non-fungibles) represented
6175
* by their respective CAIP-19:

packages/keyring-api/src/rpc.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
export enum KeyringRpcMethod {
3737
// Account management
3838
CreateAccount = 'keyring_createAccount',
39+
CreateAccounts = 'keyring_createAccounts',
3940
DeleteAccount = 'keyring_deleteAccount',
4041
DiscoverAccounts = 'keyring_discoverAccounts',
4142
ExportAccount = 'keyring_exportAccount',
@@ -126,6 +127,23 @@ export const CreateAccountResponseStruct = KeyringAccountStruct;
126127

127128
export type CreateAccountResponse = Infer<typeof CreateAccountResponseStruct>;
128129

130+
// ----------------------------------------------------------------------------
131+
// Create accounts
132+
133+
export const CreateAccountsRequestStruct = object({
134+
...CommonHeader,
135+
method: literal('keyring_createAccounts'),
136+
params: object({
137+
options: record(string(), JsonStruct),
138+
}),
139+
});
140+
141+
export type CreateAccountsRequest = Infer<typeof CreateAccountsRequestStruct>;
142+
143+
export const CreateAccountsResponseStruct = array(KeyringAccountStruct);
144+
145+
export type CreateAccountsResponse = Infer<typeof CreateAccountsResponseStruct>;
146+
129147
// ----------------------------------------------------------------------------
130148
// Set selected accounts
131149

packages/keyring-snap-bridge/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add `SnapKeyring.createAccounts` method ([#448](https://github.com/MetaMask/accounts/pull/448))
13+
- This method can be used to create one or more accounts using the new keyring v2 account creation typed options.
14+
1015
### Changed
1116

1217
- Bump `@metamask/snaps-controllers` from `^14.0.1` to `^17.2.0` ([#422](https://github.com/MetaMask/accounts/pull/422))

packages/keyring-snap-bridge/src/SnapKeyring.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {
1414
CaipChainId,
1515
MetaMaskOptions,
1616
KeyringResponse,
17+
CreateAccountOptions,
1718
} from '@metamask/keyring-api';
1819
import {
1920
EthBytesStruct,
@@ -891,6 +892,39 @@ export class SnapKeyring {
891892
});
892893
}
893894

895+
/**
896+
* Create one or more accounts according to the provided options.
897+
*
898+
* This method supports batch account creation for BIP-44 derivation paths,
899+
* allowing the creation of multiple accounts up to a specified maximum index.
900+
*
901+
* @param snapId - Snap ID to create the accounts for.
902+
* @param options - Account creation options.
903+
* @returns A promise that resolves to an array of the created account objects.
904+
*/
905+
async createAccounts(
906+
snapId: SnapId,
907+
options: CreateAccountOptions,
908+
): Promise<KeyringAccount[]> {
909+
const client = new KeyringInternalSnapClient({
910+
messenger: this.#messenger,
911+
snapId,
912+
});
913+
914+
// Add each returned account to the internal accounts map.
915+
// NOTE: This method DOES NOT rely on the `AccountCreated` event to add
916+
// accounts to the keyring, since those accounts are created in batch.
917+
const accounts = await client.createAccounts(options);
918+
for (const account of accounts) {
919+
this.#accounts.set(account.id, { account, snapId });
920+
}
921+
922+
// Save the state after adding all accounts.
923+
await this.#callbacks.saveState();
924+
925+
return accounts;
926+
}
927+
894928
/**
895929
* Checks if a Snap ID is known from the keyring.
896930
*

packages/keyring-snap-client/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add `KeyringClient.createAccounts` method ([#448](https://github.com/MetaMask/accounts/pull/448))
13+
- This method can be used to create one or more accounts using the new keyring v2 account creation typed options.
14+
1015
## [8.1.1]
1116

1217
### Changed

packages/keyring-snap-client/src/KeyringClient.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
ApproveRequestResponseStruct,
33
CreateAccountResponseStruct,
4+
CreateAccountsResponseStruct,
45
DeleteAccountResponseStruct,
56
ExportAccountResponseStruct,
67
FilterAccountChainsResponseStruct,
@@ -34,6 +35,7 @@ import type {
3435
CaipAssetTypeOrId,
3536
EntropySourceId,
3637
DiscoveredAccount,
38+
CreateAccountOptions,
3739
} from '@metamask/keyring-api';
3840
import type { AccountId, JsonRpcRequest } from '@metamask/keyring-utils';
3941
import { strictMask } from '@metamask/keyring-utils';
@@ -117,6 +119,18 @@ export class KeyringClient implements Keyring {
117119
);
118120
}
119121

122+
async createAccounts(
123+
options: CreateAccountOptions,
124+
): Promise<KeyringAccount[]> {
125+
return strictMask(
126+
await this.send({
127+
method: KeyringRpcMethod.CreateAccounts,
128+
params: options,
129+
}),
130+
CreateAccountsResponseStruct,
131+
);
132+
}
133+
120134
async discoverAccounts(
121135
scopes: CaipChainId[],
122136
entropySource: EntropySourceId,

0 commit comments

Comments
 (0)