@metamask/accounts-controller 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +14 -0
- package/LICENSE +20 -0
- package/README.md +15 -0
- package/dist/AccountsController.d.ts +132 -0
- package/dist/AccountsController.d.ts.map +1 -0
- package/dist/AccountsController.js +368 -0
- package/dist/AccountsController.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
|
9
|
+
## [1.0.0]
|
10
|
+
### Added
|
11
|
+
- Initial release ([#1637](https://github.com/MetaMask/core/pull/1637))
|
12
|
+
|
13
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/accounts-controller@1.0.0...HEAD
|
14
|
+
[1.0.0]: https://github.com/MetaMask/core/releases/tag/@metamask/accounts-controller@1.0.0
|
package/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 MetaMask
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
package/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# `@metamask/accounts-controller`
|
2
|
+
|
3
|
+
Manages internal accounts used in place of regular ethereum addresses.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
`yarn add @metamask/accounts-controller`
|
8
|
+
|
9
|
+
or
|
10
|
+
|
11
|
+
`npm install @metamask/accounts-controller`
|
12
|
+
|
13
|
+
## Contributing
|
14
|
+
|
15
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import type { RestrictedControllerMessenger } from '@metamask/base-controller';
|
2
|
+
import { BaseControllerV2 } from '@metamask/base-controller';
|
3
|
+
import type { InternalAccount } from '@metamask/keyring-api';
|
4
|
+
import type { KeyringControllerEvents, KeyringControllerGetKeyringForAccountAction, KeyringControllerGetKeyringsByTypeAction, KeyringControllerGetAccountsAction } from '@metamask/keyring-controller';
|
5
|
+
import type { SnapControllerEvents } from '@metamask/snaps-controllers';
|
6
|
+
import type { Patch } from 'immer';
|
7
|
+
declare const controllerName = "AccountsController";
|
8
|
+
export declare type AccountsControllerState = {
|
9
|
+
internalAccounts: {
|
10
|
+
accounts: Record<string, InternalAccount>;
|
11
|
+
selectedAccount: string;
|
12
|
+
};
|
13
|
+
};
|
14
|
+
export declare type AccountsControllerGetStateAction = {
|
15
|
+
type: `${typeof controllerName}:getState`;
|
16
|
+
handler: () => AccountsControllerState;
|
17
|
+
};
|
18
|
+
export declare type AccountsControllerSetSelectedAccount = {
|
19
|
+
type: `${typeof controllerName}:setSelectedAccount`;
|
20
|
+
handler: AccountsController['setSelectedAccount'];
|
21
|
+
};
|
22
|
+
export declare type AccountsControllerSetAccountName = {
|
23
|
+
type: `${typeof controllerName}:setAccountName`;
|
24
|
+
handler: AccountsController['setAccountName'];
|
25
|
+
};
|
26
|
+
export declare type AccountsControllerListAccounts = {
|
27
|
+
type: `${typeof controllerName}:listAccounts`;
|
28
|
+
handler: AccountsController['listAccounts'];
|
29
|
+
};
|
30
|
+
export declare type AccountsControllerUpdateAccounts = {
|
31
|
+
type: `${typeof controllerName}:updateAccounts`;
|
32
|
+
handler: AccountsController['updateAccounts'];
|
33
|
+
};
|
34
|
+
export declare type AccountsControllerActions = AccountsControllerGetStateAction | AccountsControllerSetSelectedAccount | AccountsControllerListAccounts | AccountsControllerSetAccountName | AccountsControllerUpdateAccounts | KeyringControllerGetKeyringForAccountAction | KeyringControllerGetKeyringsByTypeAction | KeyringControllerGetAccountsAction;
|
35
|
+
export declare type AccountsControllerChangeEvent = {
|
36
|
+
type: `${typeof controllerName}:stateChange`;
|
37
|
+
payload: [AccountsControllerState, Patch[]];
|
38
|
+
};
|
39
|
+
export declare type AccountsControllerSelectedAccountChangeEvent = {
|
40
|
+
type: `${typeof controllerName}:selectedAccountChange`;
|
41
|
+
payload: [InternalAccount];
|
42
|
+
};
|
43
|
+
export declare type AccountsControllerEvents = AccountsControllerChangeEvent | AccountsControllerSelectedAccountChangeEvent | SnapControllerEvents | KeyringControllerEvents;
|
44
|
+
export declare type AccountsControllerMessenger = RestrictedControllerMessenger<typeof controllerName, AccountsControllerActions, AccountsControllerEvents, string, string>;
|
45
|
+
/**
|
46
|
+
* Controller that manages internal accounts.
|
47
|
+
* The accounts controller is responsible for creating and managing internal accounts.
|
48
|
+
* It also provides convenience methods for accessing and updating the internal accounts.
|
49
|
+
* The accounts controller also listens for keyring state changes and updates the internal accounts accordingly.
|
50
|
+
* The accounts controller also listens for snap state changes and updates the internal accounts accordingly.
|
51
|
+
*
|
52
|
+
*/
|
53
|
+
export declare class AccountsController extends BaseControllerV2<typeof controllerName, AccountsControllerState, AccountsControllerMessenger> {
|
54
|
+
#private;
|
55
|
+
keyringApiEnabled: boolean;
|
56
|
+
/**
|
57
|
+
* Constructor for AccountsController.
|
58
|
+
*
|
59
|
+
* @param options - The controller options.
|
60
|
+
* @param options.messenger - The messenger object.
|
61
|
+
* @param options.state - Initial state to set on this controller
|
62
|
+
* @param [options.keyringApiEnabled] - The keyring API enabled flag.
|
63
|
+
*/
|
64
|
+
constructor({ messenger, state, keyringApiEnabled, }: {
|
65
|
+
messenger: AccountsControllerMessenger;
|
66
|
+
state: AccountsControllerState;
|
67
|
+
keyringApiEnabled?: boolean;
|
68
|
+
});
|
69
|
+
/**
|
70
|
+
* Returns the internal account object for the given account ID, if it exists.
|
71
|
+
*
|
72
|
+
* @param accountId - The ID of the account to retrieve.
|
73
|
+
* @returns The internal account object, or undefined if the account does not exist.
|
74
|
+
*/
|
75
|
+
getAccount(accountId: string): InternalAccount | undefined;
|
76
|
+
/**
|
77
|
+
* Returns an array of all internal accounts.
|
78
|
+
*
|
79
|
+
* @returns An array of InternalAccount objects.
|
80
|
+
*/
|
81
|
+
listAccounts(): InternalAccount[];
|
82
|
+
/**
|
83
|
+
* Returns the internal account object for the given account ID.
|
84
|
+
*
|
85
|
+
* @param accountId - The ID of the account to retrieve.
|
86
|
+
* @returns The internal account object.
|
87
|
+
* @throws An error if the account ID is not found.
|
88
|
+
*/
|
89
|
+
getAccountExpect(accountId: string): InternalAccount;
|
90
|
+
/**
|
91
|
+
* Returns the selected internal account.
|
92
|
+
*
|
93
|
+
* @returns The selected internal account.
|
94
|
+
*/
|
95
|
+
getSelectedAccount(): InternalAccount;
|
96
|
+
/**
|
97
|
+
* Sets the selected account by its ID.
|
98
|
+
*
|
99
|
+
* @param accountId - The ID of the account to be selected.
|
100
|
+
*/
|
101
|
+
setSelectedAccount(accountId: string): void;
|
102
|
+
/**
|
103
|
+
* Sets the name of the account with the given ID.
|
104
|
+
*
|
105
|
+
* @param accountId - The ID of the account to set the name for.
|
106
|
+
* @param accountName - The new name for the account.
|
107
|
+
* @throws An error if an account with the same name already exists.
|
108
|
+
*/
|
109
|
+
setAccountName(accountId: string, accountName: string): void;
|
110
|
+
/**
|
111
|
+
* Updates the internal accounts list by retrieving normal and snap accounts,
|
112
|
+
* removing duplicates, and updating the metadata of each account.
|
113
|
+
*
|
114
|
+
* @returns A Promise that resolves when the accounts have been updated.
|
115
|
+
*/
|
116
|
+
updateAccounts(): Promise<void>;
|
117
|
+
/**
|
118
|
+
* Loads the backup state of the accounts controller.
|
119
|
+
*
|
120
|
+
* @param backup - The backup state to load.
|
121
|
+
*/
|
122
|
+
loadBackup(backup: AccountsControllerState): void;
|
123
|
+
}
|
124
|
+
/**
|
125
|
+
* Returns the name of the keyring type.
|
126
|
+
*
|
127
|
+
* @param keyringType - The type of the keyring.
|
128
|
+
* @returns The name of the keyring type.
|
129
|
+
*/
|
130
|
+
export declare function keyringTypeToName(keyringType: string): string;
|
131
|
+
export {};
|
132
|
+
//# sourceMappingURL=AccountsController.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"AccountsController.d.ts","sourceRoot":"","sources":["../src/AccountsController.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,368 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
12
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
13
|
+
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");
|
14
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
15
|
+
};
|
16
|
+
var _AccountsController_instances, _AccountsController_listSnapAccounts, _AccountsController_listNormalAccounts, _AccountsController_handleSelectedAccountRemoved, _AccountsController_handleOnKeyringStateChange, _AccountsController_handleOnSnapStateChange, _AccountsController_handleNewAccountAdded, _AccountsController_registerMessageHandlers;
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
18
|
+
exports.keyringTypeToName = exports.AccountsController = void 0;
|
19
|
+
const base_controller_1 = require("@metamask/base-controller");
|
20
|
+
const eth_snap_keyring_1 = require("@metamask/eth-snap-keyring");
|
21
|
+
const keyring_api_1 = require("@metamask/keyring-api");
|
22
|
+
const ethereumjs_util_1 = require("ethereumjs-util");
|
23
|
+
const uuid_1 = require("uuid");
|
24
|
+
const controllerName = 'AccountsController';
|
25
|
+
const accountsControllerMetadata = {
|
26
|
+
internalAccounts: {
|
27
|
+
persist: true,
|
28
|
+
anonymous: false,
|
29
|
+
},
|
30
|
+
selectedAccount: {
|
31
|
+
persist: true,
|
32
|
+
anonymous: false,
|
33
|
+
},
|
34
|
+
};
|
35
|
+
const defaultState = {
|
36
|
+
internalAccounts: {
|
37
|
+
accounts: {},
|
38
|
+
selectedAccount: '',
|
39
|
+
},
|
40
|
+
};
|
41
|
+
/**
|
42
|
+
* Controller that manages internal accounts.
|
43
|
+
* The accounts controller is responsible for creating and managing internal accounts.
|
44
|
+
* It also provides convenience methods for accessing and updating the internal accounts.
|
45
|
+
* The accounts controller also listens for keyring state changes and updates the internal accounts accordingly.
|
46
|
+
* The accounts controller also listens for snap state changes and updates the internal accounts accordingly.
|
47
|
+
*
|
48
|
+
*/
|
49
|
+
class AccountsController extends base_controller_1.BaseControllerV2 {
|
50
|
+
/**
|
51
|
+
* Constructor for AccountsController.
|
52
|
+
*
|
53
|
+
* @param options - The controller options.
|
54
|
+
* @param options.messenger - The messenger object.
|
55
|
+
* @param options.state - Initial state to set on this controller
|
56
|
+
* @param [options.keyringApiEnabled] - The keyring API enabled flag.
|
57
|
+
*/
|
58
|
+
constructor({ messenger, state, keyringApiEnabled, }) {
|
59
|
+
super({
|
60
|
+
messenger,
|
61
|
+
name: controllerName,
|
62
|
+
metadata: accountsControllerMetadata,
|
63
|
+
state: Object.assign(Object.assign({}, defaultState), state),
|
64
|
+
});
|
65
|
+
_AccountsController_instances.add(this);
|
66
|
+
this.keyringApiEnabled = Boolean(keyringApiEnabled);
|
67
|
+
if (this.keyringApiEnabled) {
|
68
|
+
this.messagingSystem.subscribe('SnapController:stateChange', (snapStateState) => __awaiter(this, void 0, void 0, function* () { return yield __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleOnSnapStateChange).call(this, snapStateState); }));
|
69
|
+
}
|
70
|
+
this.messagingSystem.subscribe('KeyringController:stateChange', (keyringState) => __awaiter(this, void 0, void 0, function* () { return yield __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleOnKeyringStateChange).call(this, keyringState); }));
|
71
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_registerMessageHandlers).call(this);
|
72
|
+
// if somehow the selected account becomes lost then select the first account
|
73
|
+
if (this.state.internalAccounts.selectedAccount !== '' &&
|
74
|
+
!this.getAccount(this.state.internalAccounts.selectedAccount) &&
|
75
|
+
this.listAccounts().length > 0) {
|
76
|
+
this.setSelectedAccount(this.listAccounts()[0].id);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* Returns the internal account object for the given account ID, if it exists.
|
81
|
+
*
|
82
|
+
* @param accountId - The ID of the account to retrieve.
|
83
|
+
* @returns The internal account object, or undefined if the account does not exist.
|
84
|
+
*/
|
85
|
+
getAccount(accountId) {
|
86
|
+
return this.state.internalAccounts.accounts[accountId];
|
87
|
+
}
|
88
|
+
/**
|
89
|
+
* Returns an array of all internal accounts.
|
90
|
+
*
|
91
|
+
* @returns An array of InternalAccount objects.
|
92
|
+
*/
|
93
|
+
listAccounts() {
|
94
|
+
return Object.values(this.state.internalAccounts.accounts);
|
95
|
+
}
|
96
|
+
/**
|
97
|
+
* Returns the internal account object for the given account ID.
|
98
|
+
*
|
99
|
+
* @param accountId - The ID of the account to retrieve.
|
100
|
+
* @returns The internal account object.
|
101
|
+
* @throws An error if the account ID is not found.
|
102
|
+
*/
|
103
|
+
getAccountExpect(accountId) {
|
104
|
+
// Edge case where the extension is setup but the srp is not yet created
|
105
|
+
// certain ui elements will query the selected address before any accounts are created.
|
106
|
+
if (!accountId) {
|
107
|
+
return {
|
108
|
+
id: '',
|
109
|
+
address: '',
|
110
|
+
options: {},
|
111
|
+
methods: [],
|
112
|
+
type: keyring_api_1.EthAccountType.Eoa,
|
113
|
+
metadata: {
|
114
|
+
name: '',
|
115
|
+
keyring: {
|
116
|
+
type: '',
|
117
|
+
},
|
118
|
+
},
|
119
|
+
};
|
120
|
+
}
|
121
|
+
const account = this.getAccount(accountId);
|
122
|
+
if (account === undefined) {
|
123
|
+
throw new Error(`Account Id ${accountId} not found`);
|
124
|
+
}
|
125
|
+
return account;
|
126
|
+
}
|
127
|
+
/**
|
128
|
+
* Returns the selected internal account.
|
129
|
+
*
|
130
|
+
* @returns The selected internal account.
|
131
|
+
*/
|
132
|
+
getSelectedAccount() {
|
133
|
+
return this.getAccountExpect(this.state.internalAccounts.selectedAccount);
|
134
|
+
}
|
135
|
+
/**
|
136
|
+
* Sets the selected account by its ID.
|
137
|
+
*
|
138
|
+
* @param accountId - The ID of the account to be selected.
|
139
|
+
*/
|
140
|
+
setSelectedAccount(accountId) {
|
141
|
+
const account = this.getAccountExpect(accountId);
|
142
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
143
|
+
// @ts-ignore Type instantiation is excessively deep and possibly infinite.
|
144
|
+
this.update((currentState) => {
|
145
|
+
currentState.internalAccounts.accounts[account.id].metadata.lastSelected =
|
146
|
+
Date.now();
|
147
|
+
currentState.internalAccounts.selectedAccount = account.id;
|
148
|
+
});
|
149
|
+
this.messagingSystem.publish(`${this.name}:selectedAccountChange`, account);
|
150
|
+
}
|
151
|
+
/**
|
152
|
+
* Sets the name of the account with the given ID.
|
153
|
+
*
|
154
|
+
* @param accountId - The ID of the account to set the name for.
|
155
|
+
* @param accountName - The new name for the account.
|
156
|
+
* @throws An error if an account with the same name already exists.
|
157
|
+
*/
|
158
|
+
setAccountName(accountId, accountName) {
|
159
|
+
const account = this.getAccountExpect(accountId);
|
160
|
+
if (this.listAccounts().find((internalAccount) => internalAccount.metadata.name === accountName &&
|
161
|
+
internalAccount.id !== accountId)) {
|
162
|
+
throw new Error('Account name already exists');
|
163
|
+
}
|
164
|
+
this.update((currentState) => {
|
165
|
+
currentState.internalAccounts.accounts[accountId] = Object.assign(Object.assign({}, account), { metadata: Object.assign(Object.assign({}, account.metadata), { name: accountName }) });
|
166
|
+
});
|
167
|
+
}
|
168
|
+
/**
|
169
|
+
* Updates the internal accounts list by retrieving normal and snap accounts,
|
170
|
+
* removing duplicates, and updating the metadata of each account.
|
171
|
+
*
|
172
|
+
* @returns A Promise that resolves when the accounts have been updated.
|
173
|
+
*/
|
174
|
+
updateAccounts() {
|
175
|
+
return __awaiter(this, void 0, void 0, function* () {
|
176
|
+
let normalAccounts = yield __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_listNormalAccounts).call(this);
|
177
|
+
let snapAccounts = [];
|
178
|
+
if (this.keyringApiEnabled) {
|
179
|
+
snapAccounts = yield __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_listSnapAccounts).call(this);
|
180
|
+
// remove duplicate accounts that are retrieved from the snap keyring.
|
181
|
+
normalAccounts = normalAccounts.filter((account) => !snapAccounts.find((snapAccount) => snapAccount.address === account.address));
|
182
|
+
}
|
183
|
+
// keyring type map.
|
184
|
+
const keyringTypes = new Map();
|
185
|
+
const previousAccounts = this.state.internalAccounts.accounts;
|
186
|
+
const accounts = [
|
187
|
+
...normalAccounts,
|
188
|
+
...snapAccounts,
|
189
|
+
].reduce((internalAccountMap, internalAccount) => {
|
190
|
+
var _a, _b;
|
191
|
+
const keyringTypeName = keyringTypeToName(internalAccount.metadata.keyring.type);
|
192
|
+
const keyringAccountIndex = (_a = keyringTypes.get(keyringTypeName)) !== null && _a !== void 0 ? _a : 0;
|
193
|
+
if (keyringAccountIndex) {
|
194
|
+
keyringTypes.set(keyringTypeName, keyringAccountIndex + 1);
|
195
|
+
}
|
196
|
+
else {
|
197
|
+
keyringTypes.set(keyringTypeName, 1);
|
198
|
+
}
|
199
|
+
const existingAccount = previousAccounts[internalAccount.id];
|
200
|
+
internalAccountMap[internalAccount.id] = Object.assign(Object.assign({}, internalAccount), { metadata: Object.assign(Object.assign({}, internalAccount.metadata), { name: existingAccount && existingAccount.metadata.name !== ''
|
201
|
+
? existingAccount.metadata.name
|
202
|
+
: `${keyringTypeName} ${keyringAccountIndex + 1}`, lastSelected: (_b = existingAccount === null || existingAccount === void 0 ? void 0 : existingAccount.metadata) === null || _b === void 0 ? void 0 : _b.lastSelected }) });
|
203
|
+
return internalAccountMap;
|
204
|
+
}, {});
|
205
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
206
|
+
// @ts-ignore Type instantiation is excessively deep and possibly infinite.
|
207
|
+
this.update((currentState) => {
|
208
|
+
currentState.internalAccounts.accounts = accounts;
|
209
|
+
});
|
210
|
+
});
|
211
|
+
}
|
212
|
+
/**
|
213
|
+
* Loads the backup state of the accounts controller.
|
214
|
+
*
|
215
|
+
* @param backup - The backup state to load.
|
216
|
+
*/
|
217
|
+
loadBackup(backup) {
|
218
|
+
if (backup.internalAccounts) {
|
219
|
+
this.update((currentState) => {
|
220
|
+
currentState.internalAccounts = backup.internalAccounts;
|
221
|
+
});
|
222
|
+
}
|
223
|
+
}
|
224
|
+
}
|
225
|
+
exports.AccountsController = AccountsController;
|
226
|
+
_AccountsController_instances = new WeakSet(), _AccountsController_listSnapAccounts = function _AccountsController_listSnapAccounts() {
|
227
|
+
return __awaiter(this, void 0, void 0, function* () {
|
228
|
+
const [snapKeyring] = yield this.messagingSystem.call('KeyringController:getKeyringsByType', eth_snap_keyring_1.SnapKeyring.type);
|
229
|
+
// snap keyring is not available until the first account is created in the keyring controller
|
230
|
+
if (!snapKeyring) {
|
231
|
+
return [];
|
232
|
+
}
|
233
|
+
const snapAccounts = yield snapKeyring.listAccounts();
|
234
|
+
return snapAccounts;
|
235
|
+
});
|
236
|
+
}, _AccountsController_listNormalAccounts = function _AccountsController_listNormalAccounts() {
|
237
|
+
return __awaiter(this, void 0, void 0, function* () {
|
238
|
+
const addresses = yield this.messagingSystem.call('KeyringController:getAccounts');
|
239
|
+
const internalAccounts = [];
|
240
|
+
for (const address of addresses) {
|
241
|
+
const keyring = yield this.messagingSystem.call('KeyringController:getKeyringForAccount', address);
|
242
|
+
const v4options = {
|
243
|
+
random: (0, ethereumjs_util_1.sha256FromString)(address).slice(0, 16),
|
244
|
+
};
|
245
|
+
internalAccounts.push({
|
246
|
+
id: (0, uuid_1.v4)(v4options),
|
247
|
+
address,
|
248
|
+
options: {},
|
249
|
+
methods: [
|
250
|
+
'personal_sign',
|
251
|
+
'eth_sign',
|
252
|
+
'eth_signTransaction',
|
253
|
+
'eth_signTypedData_v1',
|
254
|
+
'eth_signTypedData_v3',
|
255
|
+
'eth_signTypedData_v4',
|
256
|
+
],
|
257
|
+
type: keyring_api_1.EthAccountType.Eoa,
|
258
|
+
metadata: {
|
259
|
+
name: '',
|
260
|
+
keyring: {
|
261
|
+
type: keyring.type,
|
262
|
+
},
|
263
|
+
},
|
264
|
+
});
|
265
|
+
}
|
266
|
+
return internalAccounts.filter((account) => account.metadata.keyring.type !== 'Snap Keyring');
|
267
|
+
});
|
268
|
+
}, _AccountsController_handleSelectedAccountRemoved = function _AccountsController_handleSelectedAccountRemoved() {
|
269
|
+
const previousAccount = this.listAccounts()
|
270
|
+
.filter((account) => account.id !== this.state.internalAccounts.selectedAccount)
|
271
|
+
.sort((accountA, accountB) => {
|
272
|
+
var _a, _b;
|
273
|
+
// sort by lastSelected descending
|
274
|
+
return (((_a = accountB.metadata.lastSelected) !== null && _a !== void 0 ? _a : 0) -
|
275
|
+
((_b = accountA.metadata.lastSelected) !== null && _b !== void 0 ? _b : 0));
|
276
|
+
})[0];
|
277
|
+
this.setSelectedAccount(previousAccount.id);
|
278
|
+
}, _AccountsController_handleOnKeyringStateChange = function _AccountsController_handleOnKeyringStateChange(keyringState) {
|
279
|
+
return __awaiter(this, void 0, void 0, function* () {
|
280
|
+
// check if there are any new accounts added
|
281
|
+
// TODO: change when accountAdded event is added to the keyring controller
|
282
|
+
if (keyringState.isUnlocked) {
|
283
|
+
// TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id
|
284
|
+
const updatedKeyringAddresses = keyringState.keyrings.flatMap((keyring) => keyring.accounts);
|
285
|
+
const previousAccounts = this.listAccounts();
|
286
|
+
// if there are no overlaps between the addresses in the keyring and previous accounts,
|
287
|
+
// it means the keyring is being reinitialized because the vault is being restored with the same SRP
|
288
|
+
const overlaps = updatedKeyringAddresses.filter((address) => previousAccounts.find((account) => account.address.toLowerCase() === address.toLowerCase()));
|
289
|
+
yield this.updateAccounts();
|
290
|
+
if (updatedKeyringAddresses.length > previousAccounts.length) {
|
291
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleNewAccountAdded).call(this, updatedKeyringAddresses, previousAccounts);
|
292
|
+
}
|
293
|
+
else if (updatedKeyringAddresses.length > 0 && overlaps.length === 0) {
|
294
|
+
// if the keyring is being reinitialized, the selected account will be reset to the first account
|
295
|
+
this.setSelectedAccount(this.listAccounts()[0].id);
|
296
|
+
}
|
297
|
+
else if (updatedKeyringAddresses.length < previousAccounts.length &&
|
298
|
+
overlaps.length > 0 &&
|
299
|
+
!this.getAccount(this.state.internalAccounts.selectedAccount)) {
|
300
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleSelectedAccountRemoved).call(this);
|
301
|
+
}
|
302
|
+
}
|
303
|
+
});
|
304
|
+
}, _AccountsController_handleOnSnapStateChange = function _AccountsController_handleOnSnapStateChange(snapState) {
|
305
|
+
return __awaiter(this, void 0, void 0, function* () {
|
306
|
+
// only check if snaps changed in status
|
307
|
+
const { snaps } = snapState;
|
308
|
+
const accounts = this.listAccounts().filter((account) => account.metadata.snap);
|
309
|
+
this.update((currentState) => {
|
310
|
+
accounts.forEach((account) => {
|
311
|
+
const currentAccount = currentState.internalAccounts.accounts[account.id];
|
312
|
+
if (currentAccount.metadata.snap) {
|
313
|
+
currentAccount.metadata.snap.enabled =
|
314
|
+
snaps[currentAccount.metadata.snap.id].enabled &&
|
315
|
+
!snaps[currentAccount.metadata.snap.id].blocked;
|
316
|
+
}
|
317
|
+
});
|
318
|
+
});
|
319
|
+
});
|
320
|
+
}, _AccountsController_handleNewAccountAdded = function _AccountsController_handleNewAccountAdded(updatedKeyringAddresses, previousAccounts) {
|
321
|
+
const [newAddress] = updatedKeyringAddresses.filter((address) => !previousAccounts.find((account) => account.address.toLowerCase() === address.toLowerCase()));
|
322
|
+
const [newAccount] = this.listAccounts().filter((account) => account.address.toLowerCase() === newAddress.toLowerCase());
|
323
|
+
this.setSelectedAccount(newAccount.id);
|
324
|
+
}, _AccountsController_registerMessageHandlers = function _AccountsController_registerMessageHandlers() {
|
325
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:setSelectedAccount`, this.setSelectedAccount.bind(this));
|
326
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:listAccounts`, this.listAccounts.bind(this));
|
327
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:setAccountName`, this.setAccountName.bind(this));
|
328
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:updateAccounts`, this.updateAccounts.bind(this));
|
329
|
+
};
|
330
|
+
/**
|
331
|
+
* Returns the name of the keyring type.
|
332
|
+
*
|
333
|
+
* @param keyringType - The type of the keyring.
|
334
|
+
* @returns The name of the keyring type.
|
335
|
+
*/
|
336
|
+
function keyringTypeToName(keyringType) {
|
337
|
+
switch (keyringType) {
|
338
|
+
case 'Simple Key Pair': {
|
339
|
+
return 'Account';
|
340
|
+
}
|
341
|
+
case 'HD Key Tree': {
|
342
|
+
return 'Account';
|
343
|
+
}
|
344
|
+
case 'Trezor Hardware': {
|
345
|
+
return 'Trezor';
|
346
|
+
}
|
347
|
+
case 'Ledger Hardware': {
|
348
|
+
return 'Ledger';
|
349
|
+
}
|
350
|
+
case 'Lattice Hardware': {
|
351
|
+
return 'Lattice';
|
352
|
+
}
|
353
|
+
case 'QR Hardware Wallet Device': {
|
354
|
+
return 'QR';
|
355
|
+
}
|
356
|
+
case 'Snap Keyring': {
|
357
|
+
return 'Snap Account';
|
358
|
+
}
|
359
|
+
case 'Custody': {
|
360
|
+
return 'Custody';
|
361
|
+
}
|
362
|
+
default: {
|
363
|
+
throw new Error(`Unknown keyring ${keyringType}`);
|
364
|
+
}
|
365
|
+
}
|
366
|
+
}
|
367
|
+
exports.keyringTypeToName = keyringTypeToName;
|
368
|
+
//# sourceMappingURL=AccountsController.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"AccountsController.js","sourceRoot":"","sources":["../src/AccountsController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AACA,+DAA6D;AAC7D,iEAAyD;AAEzD,uDAAuD;AAavD,qDAAmD;AAEnD,+BAAkC;AAElC,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAoE5C,MAAM,0BAA0B,GAAG;IACjC,gBAAgB,EAAE;QAChB,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,KAAK;KACjB;IACD,eAAe,EAAE;QACf,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,KAAK;KACjB;CACF,CAAC;AAEF,MAAM,YAAY,GAA4B;IAC5C,gBAAgB,EAAE;QAChB,QAAQ,EAAE,EAAE;QACZ,eAAe,EAAE,EAAE;KACpB;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,MAAa,kBAAmB,SAAQ,kCAIvC;IAGC;;;;;;;OAOG;IACH,YAAY,EACV,SAAS,EACT,KAAK,EACL,iBAAiB,GAKlB;QACC,KAAK,CAAC;YACJ,SAAS;YACT,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,0BAA0B;YACpC,KAAK,kCACA,YAAY,GACZ,KAAK,CACT;SACF,CAAC,CAAC;;QAEH,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAEpD,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,4BAA4B,EAC5B,CAAO,cAAc,EAAE,EAAE,gDACvB,OAAA,MAAM,uBAAA,IAAI,kFAAyB,MAA7B,IAAI,EAA0B,cAAc,CAAC,CAAA,GAAA,CACtD,CAAC;SACH;QAED,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,+BAA+B,EAC/B,CAAO,YAAY,EAAE,EAAE,gDACrB,OAAA,MAAM,uBAAA,IAAI,qFAA4B,MAAhC,IAAI,EAA6B,YAAY,CAAC,CAAA,GAAA,CACvD,CAAC;QAEF,uBAAA,IAAI,kFAAyB,MAA7B,IAAI,CAA2B,CAAC;QAEhC,6EAA6E;QAC7E,IACE,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,eAAe,KAAK,EAAE;YAClD,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,eAAe,CAAC;YAC7D,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM,GAAG,CAAC,EAC9B;YACA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACpD;IACH,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;IAED;;;;OAIG;IACH,YAAY;QACV,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;;OAMG;IACH,gBAAgB,CAAC,SAAiB;QAChC,wEAAwE;QACxE,uFAAuF;QACvF,IAAI,CAAC,SAAS,EAAE;YACd,OAAO;gBACL,EAAE,EAAE,EAAE;gBACN,OAAO,EAAE,EAAE;gBACX,OAAO,EAAE,EAAE;gBACX,OAAO,EAAE,EAAE;gBACX,IAAI,EAAE,4BAAc,CAAC,GAAG;gBACxB,QAAQ,EAAE;oBACR,IAAI,EAAE,EAAE;oBACR,OAAO,EAAE;wBACP,IAAI,EAAE,EAAE;qBACT;iBACF;aACF,CAAC;SACH;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,MAAM,IAAI,KAAK,CAAC,cAAc,SAAS,YAAY,CAAC,CAAC;SACtD;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;IAC5E,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAAC,SAAiB;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAEjD,6DAA6D;QAC7D,2EAA2E;QAC3E,IAAI,CAAC,MAAM,CAAC,CAAC,YAAqC,EAAE,EAAE;YACpD,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,YAAY;gBACtE,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,YAAY,CAAC,gBAAgB,CAAC,eAAe,GAAG,OAAO,CAAC,EAAE,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,wBAAwB,EAAE,OAAO,CAAC,CAAC;IAC9E,CAAC;IAED;;;;;;OAMG;IACH,cAAc,CAAC,SAAiB,EAAE,WAAmB;QACnD,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAEjD,IACE,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CACtB,CAAC,eAAe,EAAE,EAAE,CAClB,eAAe,CAAC,QAAQ,CAAC,IAAI,KAAK,WAAW;YAC7C,eAAe,CAAC,EAAE,KAAK,SAAS,CACnC,EACD;YACA,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;SAChD;QAED,IAAI,CAAC,MAAM,CAAC,CAAC,YAAqC,EAAE,EAAE;YACpD,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,SAAS,CAAC,mCAC5C,OAAO,KACV,QAAQ,kCACH,OAAO,CAAC,QAAQ,KACnB,IAAI,EAAE,WAAW,MAEpB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACG,cAAc;;YAClB,IAAI,cAAc,GAAG,MAAM,uBAAA,IAAI,6EAAoB,MAAxB,IAAI,CAAsB,CAAC;YACtD,IAAI,YAAY,GAAsB,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,iBAAiB,EAAE;gBAC1B,YAAY,GAAG,MAAM,uBAAA,IAAI,2EAAkB,MAAtB,IAAI,CAAoB,CAAC;gBAC9C,sEAAsE;gBACtE,cAAc,GAAG,cAAc,CAAC,MAAM,CACpC,CAAC,OAAO,EAAE,EAAE,CACV,CAAC,YAAY,CAAC,IAAI,CAChB,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CACzD,CACJ,CAAC;aACH;YAED,oBAAoB;YACpB,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;YAC/C,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC;YAE9D,MAAM,QAAQ,GAAoC;gBAChD,GAAG,cAAc;gBACjB,GAAG,YAAY;aAChB,CAAC,MAAM,CAAC,CAAC,kBAAkB,EAAE,eAAe,EAAE,EAAE;;gBAC/C,MAAM,eAAe,GAAG,iBAAiB,CACvC,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CACtC,CAAC;gBACF,MAAM,mBAAmB,GAAG,MAAA,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,mCAAI,CAAC,CAAC;gBACnE,IAAI,mBAAmB,EAAE;oBACvB,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,mBAAmB,GAAG,CAAC,CAAC,CAAC;iBAC5D;qBAAM;oBACL,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;iBACtC;gBAED,MAAM,eAAe,GAAG,gBAAgB,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;gBAE7D,kBAAkB,CAAC,eAAe,CAAC,EAAE,CAAC,mCACjC,eAAe,KAElB,QAAQ,kCACH,eAAe,CAAC,QAAQ,KAC3B,IAAI,EACF,eAAe,IAAI,eAAe,CAAC,QAAQ,CAAC,IAAI,KAAK,EAAE;4BACrD,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI;4BAC/B,CAAC,CAAC,GAAG,eAAe,IAAI,mBAAmB,GAAG,CAAC,EAAE,EACrD,YAAY,EAAE,MAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,QAAQ,0CAAE,YAAY,MAExD,CAAC;gBAEF,OAAO,kBAAkB,CAAC;YAC5B,CAAC,EAAE,EAAqC,CAAC,CAAC;YAE1C,6DAA6D;YAC7D,2EAA2E;YAC3E,IAAI,CAAC,MAAM,CAAC,CAAC,YAAqC,EAAE,EAAE;gBACpD,YAAY,CAAC,gBAAgB,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACpD,CAAC,CAAC,CAAC;QACL,CAAC;KAAA;IAED;;;;OAIG;IACH,UAAU,CAAC,MAA+B;QACxC,IAAI,MAAM,CAAC,gBAAgB,EAAE;YAC3B,IAAI,CAAC,MAAM,CAAC,CAAC,YAAqC,EAAE,EAAE;gBACpD,YAAY,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;YAC1D,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;CA8MF;AArcD,gDAqcC;;;QAtMG,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CACnD,qCAAqC,EACrC,8BAAW,CAAC,IAAI,CACjB,CAAC;QACF,6FAA6F;QAC7F,IAAI,CAAC,WAAW,EAAE;YAChB,OAAO,EAAE,CAAC;SACX;QAED,MAAM,YAAY,GAAG,MAAO,WAA2B,CAAC,YAAY,EAAE,CAAC;QAEvE,OAAO,YAAY,CAAC;IACtB,CAAC;;;QAUC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAC/C,+BAA+B,CAChC,CAAC;QACF,MAAM,gBAAgB,GAAsB,EAAE,CAAC;QAC/C,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE;YAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAC7C,wCAAwC,EACxC,OAAO,CACR,CAAC;YACF,MAAM,SAAS,GAAG;gBAChB,MAAM,EAAE,IAAA,kCAAgB,EAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;aAC/C,CAAC;YAEF,gBAAgB,CAAC,IAAI,CAAC;gBACpB,EAAE,EAAE,IAAA,SAAI,EAAC,SAAS,CAAC;gBACnB,OAAO;gBACP,OAAO,EAAE,EAAE;gBACX,OAAO,EAAE;oBACP,eAAe;oBACf,UAAU;oBACV,qBAAqB;oBACrB,sBAAsB;oBACtB,sBAAsB;oBACtB,sBAAsB;iBACvB;gBACD,IAAI,EAAE,4BAAc,CAAC,GAAG;gBACxB,QAAQ,EAAE;oBACR,IAAI,EAAE,EAAE;oBACR,OAAO,EAAE;wBACP,IAAI,EAAG,OAAyB,CAAC,IAAI;qBACtC;iBACF;aACF,CAAC,CAAC;SACJ;QAED,OAAO,gBAAgB,CAAC,MAAM,CAC5B,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,cAAc,CAC9D,CAAC;IACJ,CAAC;;IAMC,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE;SACxC,MAAM,CACL,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,eAAe,CACxE;SACA,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE;;QAC3B,kCAAkC;QAClC,OAAO,CACL,CAAC,MAAA,QAAQ,CAAC,QAAQ,CAAC,YAAY,mCAAI,CAAC,CAAC;YACrC,CAAC,MAAA,QAAQ,CAAC,QAAQ,CAAC,YAAY,mCAAI,CAAC,CAAC,CACtC,CAAC;IACJ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAER,IAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;AAC9C,CAAC,2GASC,YAAoC;;QAEpC,4CAA4C;QAC5C,0EAA0E;QAE1E,IAAI,YAAY,CAAC,UAAU,EAAE;YAC3B,oIAAoI;YACpI,MAAM,uBAAuB,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,CAC3D,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAC9B,CAAC;YACF,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAE7C,uFAAuF;YACvF,oGAAoG;YACpG,MAAM,QAAQ,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1D,gBAAgB,CAAC,IAAI,CACnB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACrE,CACF,CAAC;YAEF,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YAE5B,IAAI,uBAAuB,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE;gBAC5D,uBAAA,IAAI,gFAAuB,MAA3B,IAAI,EAAwB,uBAAuB,EAAE,gBAAgB,CAAC,CAAC;aACxE;iBAAM,IAAI,uBAAuB,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;gBACtE,iGAAiG;gBACjG,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACpD;iBAAM,IACL,uBAAuB,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM;gBACxD,QAAQ,CAAC,MAAM,GAAG,CAAC;gBACnB,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,eAAe,CAAC,EAC7D;gBACA,uBAAA,IAAI,uFAA8B,MAAlC,IAAI,CAAgC,CAAC;aACtC;SACF;IACH,CAAC;sGASC,SAA8B;;QAE9B,wCAAwC;QACxC,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM,CACzC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CACnC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,CAAC,YAAqC,EAAE,EAAE;YACpD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC3B,MAAM,cAAc,GAClB,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBACrD,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,EAAE;oBAChC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO;wBAClC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO;4BAC9C,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;iBACnD;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;kGASC,uBAAiC,EACjC,gBAAmC;IAEnC,MAAM,CAAC,UAAU,CAAC,GAAG,uBAAuB,CAAC,MAAM,CACjD,CAAC,OAAO,EAAE,EAAE,CACV,CAAC,gBAAgB,CAAC,IAAI,CACpB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CACrE,CACJ,CAAC;IAEF,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM,CAC7C,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,WAAW,EAAE,CACxE,CAAC;IAEF,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;AACzC,CAAC;IAGC,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,qBAAqB,EACtC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CACnC,CAAC;IAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,eAAe,EAChC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAC7B,CAAC;IAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,iBAAiB,EAClC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAC/B,CAAC;IAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,iBAAiB,EAClC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAC/B,CAAC;AACJ,CAAC;AAGH;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,WAAmB;IACnD,QAAQ,WAAW,EAAE;QACnB,KAAK,iBAAiB,CAAC,CAAC;YACtB,OAAO,SAAS,CAAC;SAClB;QACD,KAAK,aAAa,CAAC,CAAC;YAClB,OAAO,SAAS,CAAC;SAClB;QACD,KAAK,iBAAiB,CAAC,CAAC;YACtB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,iBAAiB,CAAC,CAAC;YACtB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,kBAAkB,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;SAClB;QACD,KAAK,2BAA2B,CAAC,CAAC;YAChC,OAAO,IAAI,CAAC;SACb;QACD,KAAK,cAAc,CAAC,CAAC;YACnB,OAAO,cAAc,CAAC;SACvB;QACD,KAAK,SAAS,CAAC,CAAC;YACd,OAAO,SAAS,CAAC;SAClB;QACD,OAAO,CAAC,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;SACnD;KACF;AACH,CAAC;AA9BD,8CA8BC","sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport { BaseControllerV2 } from '@metamask/base-controller';\nimport { SnapKeyring } from '@metamask/eth-snap-keyring';\nimport type { InternalAccount } from '@metamask/keyring-api';\nimport { EthAccountType } from '@metamask/keyring-api';\nimport type {\n KeyringControllerState,\n KeyringControllerEvents,\n KeyringControllerGetKeyringForAccountAction,\n KeyringControllerGetKeyringsByTypeAction,\n KeyringControllerGetAccountsAction,\n} from '@metamask/keyring-controller';\nimport type {\n SnapControllerEvents,\n SnapControllerState,\n} from '@metamask/snaps-controllers';\nimport type { Keyring, Json } from '@metamask/utils';\nimport { sha256FromString } from 'ethereumjs-util';\nimport type { Patch } from 'immer';\nimport { v4 as uuid } from 'uuid';\n\nconst controllerName = 'AccountsController';\n\nexport type AccountsControllerState = {\n internalAccounts: {\n accounts: Record<string, InternalAccount>;\n selectedAccount: string; // id of the selected account\n };\n};\n\nexport type AccountsControllerGetStateAction = {\n type: `${typeof controllerName}:getState`;\n handler: () => AccountsControllerState;\n};\n\nexport type AccountsControllerSetSelectedAccount = {\n type: `${typeof controllerName}:setSelectedAccount`;\n handler: AccountsController['setSelectedAccount'];\n};\n\nexport type AccountsControllerSetAccountName = {\n type: `${typeof controllerName}:setAccountName`;\n handler: AccountsController['setAccountName'];\n};\n\nexport type AccountsControllerListAccounts = {\n type: `${typeof controllerName}:listAccounts`;\n handler: AccountsController['listAccounts'];\n};\n\nexport type AccountsControllerUpdateAccounts = {\n type: `${typeof controllerName}:updateAccounts`;\n handler: AccountsController['updateAccounts'];\n};\n\nexport type AccountsControllerActions =\n | AccountsControllerGetStateAction\n | AccountsControllerSetSelectedAccount\n | AccountsControllerListAccounts\n | AccountsControllerSetAccountName\n | AccountsControllerUpdateAccounts\n | KeyringControllerGetKeyringForAccountAction\n | KeyringControllerGetKeyringsByTypeAction\n | KeyringControllerGetAccountsAction;\n\nexport type AccountsControllerChangeEvent = {\n type: `${typeof controllerName}:stateChange`;\n payload: [AccountsControllerState, Patch[]];\n};\n\nexport type AccountsControllerSelectedAccountChangeEvent = {\n type: `${typeof controllerName}:selectedAccountChange`;\n payload: [InternalAccount];\n};\n\nexport type AccountsControllerEvents =\n | AccountsControllerChangeEvent\n | AccountsControllerSelectedAccountChangeEvent\n | SnapControllerEvents\n | KeyringControllerEvents;\n\nexport type AccountsControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n AccountsControllerActions,\n AccountsControllerEvents,\n string,\n string\n>;\n\nconst accountsControllerMetadata = {\n internalAccounts: {\n persist: true,\n anonymous: false,\n },\n selectedAccount: {\n persist: true,\n anonymous: false,\n },\n};\n\nconst defaultState: AccountsControllerState = {\n internalAccounts: {\n accounts: {},\n selectedAccount: '',\n },\n};\n\n/**\n * Controller that manages internal accounts.\n * The accounts controller is responsible for creating and managing internal accounts.\n * It also provides convenience methods for accessing and updating the internal accounts.\n * The accounts controller also listens for keyring state changes and updates the internal accounts accordingly.\n * The accounts controller also listens for snap state changes and updates the internal accounts accordingly.\n *\n */\nexport class AccountsController extends BaseControllerV2<\n typeof controllerName,\n AccountsControllerState,\n AccountsControllerMessenger\n> {\n keyringApiEnabled: boolean;\n\n /**\n * Constructor for AccountsController.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger object.\n * @param options.state - Initial state to set on this controller\n * @param [options.keyringApiEnabled] - The keyring API enabled flag.\n */\n constructor({\n messenger,\n state,\n keyringApiEnabled,\n }: {\n messenger: AccountsControllerMessenger;\n state: AccountsControllerState;\n keyringApiEnabled?: boolean;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: accountsControllerMetadata,\n state: {\n ...defaultState,\n ...state,\n },\n });\n\n this.keyringApiEnabled = Boolean(keyringApiEnabled);\n\n if (this.keyringApiEnabled) {\n this.messagingSystem.subscribe(\n 'SnapController:stateChange',\n async (snapStateState) =>\n await this.#handleOnSnapStateChange(snapStateState),\n );\n }\n\n this.messagingSystem.subscribe(\n 'KeyringController:stateChange',\n async (keyringState) =>\n await this.#handleOnKeyringStateChange(keyringState),\n );\n\n this.#registerMessageHandlers();\n\n // if somehow the selected account becomes lost then select the first account\n if (\n this.state.internalAccounts.selectedAccount !== '' &&\n !this.getAccount(this.state.internalAccounts.selectedAccount) &&\n this.listAccounts().length > 0\n ) {\n this.setSelectedAccount(this.listAccounts()[0].id);\n }\n }\n\n /**\n * Returns the internal account object for the given account ID, if it exists.\n *\n * @param accountId - The ID of the account to retrieve.\n * @returns The internal account object, or undefined if the account does not exist.\n */\n getAccount(accountId: string): InternalAccount | undefined {\n return this.state.internalAccounts.accounts[accountId];\n }\n\n /**\n * Returns an array of all internal accounts.\n *\n * @returns An array of InternalAccount objects.\n */\n listAccounts(): InternalAccount[] {\n return Object.values(this.state.internalAccounts.accounts);\n }\n\n /**\n * Returns the internal account object for the given account ID.\n *\n * @param accountId - The ID of the account to retrieve.\n * @returns The internal account object.\n * @throws An error if the account ID is not found.\n */\n getAccountExpect(accountId: string): InternalAccount {\n // Edge case where the extension is setup but the srp is not yet created\n // certain ui elements will query the selected address before any accounts are created.\n if (!accountId) {\n return {\n id: '',\n address: '',\n options: {},\n methods: [],\n type: EthAccountType.Eoa,\n metadata: {\n name: '',\n keyring: {\n type: '',\n },\n },\n };\n }\n\n const account = this.getAccount(accountId);\n if (account === undefined) {\n throw new Error(`Account Id ${accountId} not found`);\n }\n return account;\n }\n\n /**\n * Returns the selected internal account.\n *\n * @returns The selected internal account.\n */\n getSelectedAccount(): InternalAccount {\n return this.getAccountExpect(this.state.internalAccounts.selectedAccount);\n }\n\n /**\n * Sets the selected account by its ID.\n *\n * @param accountId - The ID of the account to be selected.\n */\n setSelectedAccount(accountId: string): void {\n const account = this.getAccountExpect(accountId);\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore Type instantiation is excessively deep and possibly infinite.\n this.update((currentState: AccountsControllerState) => {\n currentState.internalAccounts.accounts[account.id].metadata.lastSelected =\n Date.now();\n currentState.internalAccounts.selectedAccount = account.id;\n });\n\n this.messagingSystem.publish(`${this.name}:selectedAccountChange`, account);\n }\n\n /**\n * Sets the name of the account with the given ID.\n *\n * @param accountId - The ID of the account to set the name for.\n * @param accountName - The new name for the account.\n * @throws An error if an account with the same name already exists.\n */\n setAccountName(accountId: string, accountName: string): void {\n const account = this.getAccountExpect(accountId);\n\n if (\n this.listAccounts().find(\n (internalAccount) =>\n internalAccount.metadata.name === accountName &&\n internalAccount.id !== accountId,\n )\n ) {\n throw new Error('Account name already exists');\n }\n\n this.update((currentState: AccountsControllerState) => {\n currentState.internalAccounts.accounts[accountId] = {\n ...account,\n metadata: {\n ...account.metadata,\n name: accountName,\n },\n };\n });\n }\n\n /**\n * Updates the internal accounts list by retrieving normal and snap accounts,\n * removing duplicates, and updating the metadata of each account.\n *\n * @returns A Promise that resolves when the accounts have been updated.\n */\n async updateAccounts(): Promise<void> {\n let normalAccounts = await this.#listNormalAccounts();\n let snapAccounts: InternalAccount[] = [];\n if (this.keyringApiEnabled) {\n snapAccounts = await this.#listSnapAccounts();\n // remove duplicate accounts that are retrieved from the snap keyring.\n normalAccounts = normalAccounts.filter(\n (account) =>\n !snapAccounts.find(\n (snapAccount) => snapAccount.address === account.address,\n ),\n );\n }\n\n // keyring type map.\n const keyringTypes = new Map<string, number>();\n const previousAccounts = this.state.internalAccounts.accounts;\n\n const accounts: Record<string, InternalAccount> = [\n ...normalAccounts,\n ...snapAccounts,\n ].reduce((internalAccountMap, internalAccount) => {\n const keyringTypeName = keyringTypeToName(\n internalAccount.metadata.keyring.type,\n );\n const keyringAccountIndex = keyringTypes.get(keyringTypeName) ?? 0;\n if (keyringAccountIndex) {\n keyringTypes.set(keyringTypeName, keyringAccountIndex + 1);\n } else {\n keyringTypes.set(keyringTypeName, 1);\n }\n\n const existingAccount = previousAccounts[internalAccount.id];\n\n internalAccountMap[internalAccount.id] = {\n ...internalAccount,\n\n metadata: {\n ...internalAccount.metadata,\n name:\n existingAccount && existingAccount.metadata.name !== ''\n ? existingAccount.metadata.name\n : `${keyringTypeName} ${keyringAccountIndex + 1}`,\n lastSelected: existingAccount?.metadata?.lastSelected,\n },\n };\n\n return internalAccountMap;\n }, {} as Record<string, InternalAccount>);\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore Type instantiation is excessively deep and possibly infinite.\n this.update((currentState: AccountsControllerState) => {\n currentState.internalAccounts.accounts = accounts;\n });\n }\n\n /**\n * Loads the backup state of the accounts controller.\n *\n * @param backup - The backup state to load.\n */\n loadBackup(backup: AccountsControllerState): void {\n if (backup.internalAccounts) {\n this.update((currentState: AccountsControllerState) => {\n currentState.internalAccounts = backup.internalAccounts;\n });\n }\n }\n\n /**\n * Returns a list of internal accounts created using the SnapKeyring.\n *\n * @returns A promise that resolves to an array of InternalAccount objects.\n */\n async #listSnapAccounts(): Promise<InternalAccount[]> {\n const [snapKeyring] = await this.messagingSystem.call(\n 'KeyringController:getKeyringsByType',\n SnapKeyring.type,\n );\n // snap keyring is not available until the first account is created in the keyring controller\n if (!snapKeyring) {\n return [];\n }\n\n const snapAccounts = await (snapKeyring as SnapKeyring).listAccounts();\n\n return snapAccounts;\n }\n\n /**\n * Returns a list of normal accounts.\n * Note: listNormalAccounts is a temporary method until the keyrings all implement the InternalAccount interface.\n * Once all keyrings implement the InternalAccount interface, this method can be removed and getAccounts can be used instead.\n *\n * @returns A Promise that resolves to an array of InternalAccount objects.\n */\n async #listNormalAccounts(): Promise<InternalAccount[]> {\n const addresses = await this.messagingSystem.call(\n 'KeyringController:getAccounts',\n );\n const internalAccounts: InternalAccount[] = [];\n for (const address of addresses) {\n const keyring = await this.messagingSystem.call(\n 'KeyringController:getKeyringForAccount',\n address,\n );\n const v4options = {\n random: sha256FromString(address).slice(0, 16),\n };\n\n internalAccounts.push({\n id: uuid(v4options),\n address,\n options: {},\n methods: [\n 'personal_sign',\n 'eth_sign',\n 'eth_signTransaction',\n 'eth_signTypedData_v1',\n 'eth_signTypedData_v3',\n 'eth_signTypedData_v4',\n ],\n type: EthAccountType.Eoa,\n metadata: {\n name: '',\n keyring: {\n type: (keyring as Keyring<Json>).type,\n },\n },\n });\n }\n\n return internalAccounts.filter(\n (account) => account.metadata.keyring.type !== 'Snap Keyring',\n );\n }\n\n /**\n * Handles the removal of the currently selected account by selecting the previous account in the list.\n */\n #handleSelectedAccountRemoved() {\n const previousAccount = this.listAccounts()\n .filter(\n (account) => account.id !== this.state.internalAccounts.selectedAccount,\n )\n .sort((accountA, accountB) => {\n // sort by lastSelected descending\n return (\n (accountB.metadata.lastSelected ?? 0) -\n (accountA.metadata.lastSelected ?? 0)\n );\n })[0];\n\n this.setSelectedAccount(previousAccount.id);\n }\n\n /**\n * Handles changes in the keyring state, specifically when new accounts are added or removed.\n *\n * @param keyringState - The new state of the keyring controller.\n * @returns A Promise that resolves when the function has finished executing.\n */\n async #handleOnKeyringStateChange(\n keyringState: KeyringControllerState,\n ): Promise<void> {\n // check if there are any new accounts added\n // TODO: change when accountAdded event is added to the keyring controller\n\n if (keyringState.isUnlocked) {\n // TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id\n const updatedKeyringAddresses = keyringState.keyrings.flatMap(\n (keyring) => keyring.accounts,\n );\n const previousAccounts = this.listAccounts();\n\n // if there are no overlaps between the addresses in the keyring and previous accounts,\n // it means the keyring is being reinitialized because the vault is being restored with the same SRP\n const overlaps = updatedKeyringAddresses.filter((address) =>\n previousAccounts.find(\n (account) => account.address.toLowerCase() === address.toLowerCase(),\n ),\n );\n\n await this.updateAccounts();\n\n if (updatedKeyringAddresses.length > previousAccounts.length) {\n this.#handleNewAccountAdded(updatedKeyringAddresses, previousAccounts);\n } else if (updatedKeyringAddresses.length > 0 && overlaps.length === 0) {\n // if the keyring is being reinitialized, the selected account will be reset to the first account\n this.setSelectedAccount(this.listAccounts()[0].id);\n } else if (\n updatedKeyringAddresses.length < previousAccounts.length &&\n overlaps.length > 0 &&\n !this.getAccount(this.state.internalAccounts.selectedAccount)\n ) {\n this.#handleSelectedAccountRemoved();\n }\n }\n }\n\n /**\n * Handles the change in SnapControllerState by updating the metadata of accounts that have a snap enabled.\n *\n * @param snapState - The new SnapControllerState.\n * @returns A Promise that resolves when the update is complete.\n */\n async #handleOnSnapStateChange(\n snapState: SnapControllerState,\n ): Promise<void> {\n // only check if snaps changed in status\n const { snaps } = snapState;\n const accounts = this.listAccounts().filter(\n (account) => account.metadata.snap,\n );\n\n this.update((currentState: AccountsControllerState) => {\n accounts.forEach((account) => {\n const currentAccount =\n currentState.internalAccounts.accounts[account.id];\n if (currentAccount.metadata.snap) {\n currentAccount.metadata.snap.enabled =\n snaps[currentAccount.metadata.snap.id].enabled &&\n !snaps[currentAccount.metadata.snap.id].blocked;\n }\n });\n });\n }\n\n /**\n * Handles the event when a new account is added to the keyring.\n *\n * @param updatedKeyringAddresses - An array of updated keyring addresses.\n * @param previousAccounts - An array of previous internal accounts.\n */\n #handleNewAccountAdded(\n updatedKeyringAddresses: string[],\n previousAccounts: InternalAccount[],\n ) {\n const [newAddress] = updatedKeyringAddresses.filter(\n (address) =>\n !previousAccounts.find(\n (account) => account.address.toLowerCase() === address.toLowerCase(),\n ),\n );\n\n const [newAccount] = this.listAccounts().filter(\n (account) => account.address.toLowerCase() === newAddress.toLowerCase(),\n );\n\n this.setSelectedAccount(newAccount.id);\n }\n\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:setSelectedAccount`,\n this.setSelectedAccount.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:listAccounts`,\n this.listAccounts.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:setAccountName`,\n this.setAccountName.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateAccounts`,\n this.updateAccounts.bind(this),\n );\n }\n}\n\n/**\n * Returns the name of the keyring type.\n *\n * @param keyringType - The type of the keyring.\n * @returns The name of the keyring type.\n */\nexport function keyringTypeToName(keyringType: string): string {\n switch (keyringType) {\n case 'Simple Key Pair': {\n return 'Account';\n }\n case 'HD Key Tree': {\n return 'Account';\n }\n case 'Trezor Hardware': {\n return 'Trezor';\n }\n case 'Ledger Hardware': {\n return 'Ledger';\n }\n case 'Lattice Hardware': {\n return 'Lattice';\n }\n case 'QR Hardware Wallet Device': {\n return 'QR';\n }\n case 'Snap Keyring': {\n return 'Snap Account';\n }\n case 'Custody': {\n return 'Custody';\n }\n default: {\n throw new Error(`Unknown keyring ${keyringType}`);\n }\n }\n}\n"]}
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./AccountsController"), exports);
|
18
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC","sourcesContent":["export * from './AccountsController';\n"]}
|
package/package.json
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
{
|
2
|
+
"name": "@metamask/accounts-controller",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "Manages internal accounts",
|
5
|
+
"keywords": [
|
6
|
+
"MetaMask",
|
7
|
+
"Ethereum"
|
8
|
+
],
|
9
|
+
"homepage": "https://github.com/MetaMask/core/tree/main/packages/accounts-controller#readme",
|
10
|
+
"bugs": {
|
11
|
+
"url": "https://github.com/MetaMask/core/issues"
|
12
|
+
},
|
13
|
+
"repository": {
|
14
|
+
"type": "git",
|
15
|
+
"url": "https://github.com/MetaMask/core.git"
|
16
|
+
},
|
17
|
+
"license": "MIT",
|
18
|
+
"main": "./dist/index.js",
|
19
|
+
"types": "./dist/index.d.ts",
|
20
|
+
"files": [
|
21
|
+
"dist/"
|
22
|
+
],
|
23
|
+
"scripts": {
|
24
|
+
"build:docs": "typedoc",
|
25
|
+
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/accounts-controller",
|
26
|
+
"publish:preview": "yarn npm publish --tag preview",
|
27
|
+
"test": "jest",
|
28
|
+
"test:watch": "jest --watch"
|
29
|
+
},
|
30
|
+
"dependencies": {
|
31
|
+
"@metamask/base-controller": "^3.2.1",
|
32
|
+
"@metamask/eth-snap-keyring": "^0.2.2",
|
33
|
+
"@metamask/keyring-api": "^0.2.5",
|
34
|
+
"@metamask/snaps-utils": "^1.0.1",
|
35
|
+
"@metamask/utils": "^6.2.0",
|
36
|
+
"deepmerge": "^4.2.2",
|
37
|
+
"eth-rpc-errors": "^4.0.2",
|
38
|
+
"ethereumjs-util": "^7.0.10",
|
39
|
+
"immer": "^9.0.6",
|
40
|
+
"nanoid": "^3.1.31",
|
41
|
+
"uuid": "^8.3.2"
|
42
|
+
},
|
43
|
+
"devDependencies": {
|
44
|
+
"@metamask/auto-changelog": "^3.1.0",
|
45
|
+
"@metamask/keyring-controller": "^7.5.0",
|
46
|
+
"@metamask/snaps-controllers": "^1.0.1",
|
47
|
+
"@types/jest": "^27.4.1",
|
48
|
+
"@types/readable-stream": "^2.3.0",
|
49
|
+
"jest": "^27.5.1",
|
50
|
+
"ts-jest": "^27.1.4",
|
51
|
+
"typedoc": "^0.22.15",
|
52
|
+
"typedoc-plugin-missing-exports": "^0.22.6",
|
53
|
+
"typescript": "~4.6.3"
|
54
|
+
},
|
55
|
+
"peerDependencies": {
|
56
|
+
"@metamask/keyring-controller": "^7.5.0"
|
57
|
+
},
|
58
|
+
"engines": {
|
59
|
+
"node": ">=16.0.0"
|
60
|
+
},
|
61
|
+
"publishConfig": {
|
62
|
+
"access": "public",
|
63
|
+
"registry": "https://registry.npmjs.org/"
|
64
|
+
}
|
65
|
+
}
|