@metamask-previews/money-account-controller 2.0.0-preview-7ef511c85 → 2.0.0-preview-5d0e7527f

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,11 +7,21 @@ 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 support for MPC-backed money accounts (MFA accounts) via `createMoneyAccount({ type: 'mpc' })` ([#10694](https://github.com/MetaMask/core/pull/10694))
13
+ - Add `setDefaultMoneyAccount` and a persisted `defaultMoneyAccountId` state field, so consumers know which money account is preferred ([#10694](https://github.com/MetaMask/core/pull/10694))
14
+
10
15
  ### Changed
11
16
 
17
+ - **BREAKING:** `createMoneyAccount` now takes a params object: `{ type: 'mpc' }` for the MPC-backed account (MFA), or `{ type?: 'mnemonic', entropySource }` (the default) for the `MoneyKeyring` account (SFA) for that entropy source ([#10694](https://github.com/MetaMask/core/pull/10694))
18
+ - **BREAKING:** `MoneyAccount.options.entropy` is now a union of mnemonic and MPC entropy options (`MoneyAccountEntropyOptions`) ([#10694](https://github.com/MetaMask/core/pull/10694))
19
+ - **BREAKING:** `getMoneyAccount()` with no selector now returns the default money account (`defaultMoneyAccountId`) instead of resolving the primary HD entropy source ([#10694](https://github.com/MetaMask/core/pull/10694))
20
+ - Lookup by `{ entropySource }` is still supported, and lookup by `{ id }` was added.
12
21
  - Bump `@metamask/keyring-controller` from `^28.0.0` to `^28.2.0` ([#10418](https://github.com/MetaMask/core/pull/10418), [#10851](https://github.com/MetaMask/core/pull/10851))
13
22
  - Bump `@metamask/keyring-api` from `^24.0.0` to `^24.3.0` ([#10717](https://github.com/MetaMask/core/pull/10717), [#10792](https://github.com/MetaMask/core/pull/10792), [#10844](https://github.com/MetaMask/core/pull/10844))
14
23
  - Bump `@metamask/accounts-controller` from `^40.0.0` to `^40.1.0` ([#10851](https://github.com/MetaMask/core/pull/10851))
24
+ - Bump `@metamask/base-controller` from `^10.0.0` to `^10.1.0` ([#10864](https://github.com/MetaMask/core/pull/10864))
15
25
 
16
26
  ## [2.0.0]
17
27
 
@@ -12,10 +12,17 @@ export type MoneyAccountControllerInitAction = {
12
12
  handler: MoneyAccountController['init'];
13
13
  };
14
14
  /**
15
- * Creates a money account for the given entropy source. If an account
16
- * already exists for that entropy source, it is returned as-is (idempotent).
15
+ * Creates a money account. If an account already exists for the given
16
+ * source, it is returned as-is (idempotent).
17
17
  *
18
- * @param entropySource - The entropy source ID to create the money account for.
18
+ * The parameters determine the backing keyring:
19
+ * - `{ type: 'mpc' }`: the MPC Money keyring (MFA account), which is created and
20
+ * initialized if it does not exist yet.
21
+ * - `{ type?: 'mnemonic', entropySource }` (the default): the `MoneyKeyring`
22
+ * for that entropy source (SFA account), which is created if it does not
23
+ * exist yet.
24
+ *
25
+ * @param params - The parameters for creating the money account.
19
26
  * @returns The money account.
20
27
  */
21
28
  export type MoneyAccountControllerCreateMoneyAccountAction = {
@@ -23,12 +30,21 @@ export type MoneyAccountControllerCreateMoneyAccountAction = {
23
30
  handler: MoneyAccountController['createMoneyAccount'];
24
31
  };
25
32
  /**
26
- * Gets a money account by its associated entropy source ID. If no ID is
27
- * provided, the primary entropy source will be used.
33
+ * Sets the default money account.
34
+ *
35
+ * @param id - The id of the money account to use as the default.
36
+ */
37
+ export type MoneyAccountControllerSetDefaultMoneyAccountAction = {
38
+ type: `MoneyAccountController:setDefaultMoneyAccount`;
39
+ handler: MoneyAccountController['setDefaultMoneyAccount'];
40
+ };
41
+ /**
42
+ * Gets a money account by id, by entropy source, or the default one.
28
43
  *
29
44
  * @param selector - Selector options for getting the money account.
30
- * @param selector.entropySource - The entropy source ID to get the money account for. If not provided, the primary entropy source will be used.
31
- * @returns The money account, or `undefined` if no account exists for the given entropy source.
45
+ * @param selector.id - The account id to look up. Takes precedence over `entropySource`.
46
+ * @param selector.entropySource - The entropy source ID to get the money account for.
47
+ * @returns The money account, or `undefined` if none matches.
32
48
  */
33
49
  export type MoneyAccountControllerGetMoneyAccountAction = {
34
50
  type: `MoneyAccountController:getMoneyAccount`;
@@ -48,5 +64,5 @@ export type MoneyAccountControllerClearStateAction = {
48
64
  /**
49
65
  * Union of all MoneyAccountController action types.
50
66
  */
51
- export type MoneyAccountControllerMethodActions = MoneyAccountControllerInitAction | MoneyAccountControllerCreateMoneyAccountAction | MoneyAccountControllerGetMoneyAccountAction | MoneyAccountControllerClearStateAction;
67
+ export type MoneyAccountControllerMethodActions = MoneyAccountControllerInitAction | MoneyAccountControllerCreateMoneyAccountAction | MoneyAccountControllerSetDefaultMoneyAccountAction | MoneyAccountControllerGetMoneyAccountAction | MoneyAccountControllerClearStateAction;
52
68
  //# sourceMappingURL=MoneyAccountController-method-action-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MoneyAccountController-method-action-types.d.ts","sourceRoot":"","sources":["../src/MoneyAccountController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E;;;GAGG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,6BAA6B,CAAC;IACpC,OAAO,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8CAA8C,GAAG;IAC3D,IAAI,EAAE,2CAA2C,CAAC;IAClD,OAAO,EAAE,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;CACvD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,2CAA2C,GAAG;IACxD,IAAI,EAAE,wCAAwC,CAAC;IAC/C,OAAO,EAAE,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,sBAAsB,CAAC,YAAY,CAAC,CAAC;CAC/C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,gCAAgC,GAChC,8CAA8C,GAC9C,2CAA2C,GAC3C,sCAAsC,CAAC"}
1
+ {"version":3,"file":"MoneyAccountController-method-action-types.d.ts","sourceRoot":"","sources":["../src/MoneyAccountController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E;;;GAGG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,6BAA6B,CAAC;IACpC,OAAO,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,8CAA8C,GAAG;IAC3D,IAAI,EAAE,2CAA2C,CAAC;IAClD,OAAO,EAAE,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;CACvD,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,kDAAkD,GAAG;IAC/D,IAAI,EAAE,+CAA+C,CAAC;IACtD,OAAO,EAAE,sBAAsB,CAAC,wBAAwB,CAAC,CAAC;CAC3D,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,2CAA2C,GAAG;IACxD,IAAI,EAAE,wCAAwC,CAAC;IAC/C,OAAO,EAAE,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,sBAAsB,CAAC,YAAY,CAAC,CAAC;CAC/C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,gCAAgC,GAChC,8CAA8C,GAC9C,kDAAkD,GAClD,2CAA2C,GAC3C,sCAAsC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MoneyAccountController-method-action-types.js","sourceRoot":"","sources":["../src/MoneyAccountController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { MoneyAccountController } from './MoneyAccountController.js';\n\n/**\n * Initializes the controller by creating a money account for the primary\n * entropy source if one does not already exist.\n */\nexport type MoneyAccountControllerInitAction = {\n type: `MoneyAccountController:init`;\n handler: MoneyAccountController['init'];\n};\n\n/**\n * Creates a money account for the given entropy source. If an account\n * already exists for that entropy source, it is returned as-is (idempotent).\n *\n * @param entropySource - The entropy source ID to create the money account for.\n * @returns The money account.\n */\nexport type MoneyAccountControllerCreateMoneyAccountAction = {\n type: `MoneyAccountController:createMoneyAccount`;\n handler: MoneyAccountController['createMoneyAccount'];\n};\n\n/**\n * Gets a money account by its associated entropy source ID. If no ID is\n * provided, the primary entropy source will be used.\n *\n * @param selector - Selector options for getting the money account.\n * @param selector.entropySource - The entropy source ID to get the money account for. If not provided, the primary entropy source will be used.\n * @returns The money account, or `undefined` if no account exists for the given entropy source.\n */\nexport type MoneyAccountControllerGetMoneyAccountAction = {\n type: `MoneyAccountController:getMoneyAccount`;\n handler: MoneyAccountController['getMoneyAccount'];\n};\n\n/**\n * Resets the controller state to its default, removing all money accounts.\n *\n * Intended for use during a full app reset (e.g. when the user wipes all\n * wallet data). Does not interact with the keyring — the caller is\n * responsible for ensuring the associated keyring state is also cleared.\n */\nexport type MoneyAccountControllerClearStateAction = {\n type: `MoneyAccountController:clearState`;\n handler: MoneyAccountController['clearState'];\n};\n\n/**\n * Union of all MoneyAccountController action types.\n */\nexport type MoneyAccountControllerMethodActions =\n | MoneyAccountControllerInitAction\n | MoneyAccountControllerCreateMoneyAccountAction\n | MoneyAccountControllerGetMoneyAccountAction\n | MoneyAccountControllerClearStateAction;\n"]}
1
+ {"version":3,"file":"MoneyAccountController-method-action-types.js","sourceRoot":"","sources":["../src/MoneyAccountController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { MoneyAccountController } from './MoneyAccountController.js';\n\n/**\n * Initializes the controller by creating a money account for the primary\n * entropy source if one does not already exist.\n */\nexport type MoneyAccountControllerInitAction = {\n type: `MoneyAccountController:init`;\n handler: MoneyAccountController['init'];\n};\n\n/**\n * Creates a money account. If an account already exists for the given\n * source, it is returned as-is (idempotent).\n *\n * The parameters determine the backing keyring:\n * - `{ type: 'mpc' }`: the MPC Money keyring (MFA account), which is created and\n * initialized if it does not exist yet.\n * - `{ type?: 'mnemonic', entropySource }` (the default): the `MoneyKeyring`\n * for that entropy source (SFA account), which is created if it does not\n * exist yet.\n *\n * @param params - The parameters for creating the money account.\n * @returns The money account.\n */\nexport type MoneyAccountControllerCreateMoneyAccountAction = {\n type: `MoneyAccountController:createMoneyAccount`;\n handler: MoneyAccountController['createMoneyAccount'];\n};\n\n/**\n * Sets the default money account.\n *\n * @param id - The id of the money account to use as the default.\n */\nexport type MoneyAccountControllerSetDefaultMoneyAccountAction = {\n type: `MoneyAccountController:setDefaultMoneyAccount`;\n handler: MoneyAccountController['setDefaultMoneyAccount'];\n};\n\n/**\n * Gets a money account by id, by entropy source, or the default one.\n *\n * @param selector - Selector options for getting the money account.\n * @param selector.id - The account id to look up. Takes precedence over `entropySource`.\n * @param selector.entropySource - The entropy source ID to get the money account for.\n * @returns The money account, or `undefined` if none matches.\n */\nexport type MoneyAccountControllerGetMoneyAccountAction = {\n type: `MoneyAccountController:getMoneyAccount`;\n handler: MoneyAccountController['getMoneyAccount'];\n};\n\n/**\n * Resets the controller state to its default, removing all money accounts.\n *\n * Intended for use during a full app reset (e.g. when the user wipes all\n * wallet data). Does not interact with the keyring — the caller is\n * responsible for ensuring the associated keyring state is also cleared.\n */\nexport type MoneyAccountControllerClearStateAction = {\n type: `MoneyAccountController:clearState`;\n handler: MoneyAccountController['clearState'];\n};\n\n/**\n * Union of all MoneyAccountController action types.\n */\nexport type MoneyAccountControllerMethodActions =\n | MoneyAccountControllerInitAction\n | MoneyAccountControllerCreateMoneyAccountAction\n | MoneyAccountControllerSetDefaultMoneyAccountAction\n | MoneyAccountControllerGetMoneyAccountAction\n | MoneyAccountControllerClearStateAction;\n"]}
@@ -1,20 +1,43 @@
1
1
  import type { ControllerGetStateAction, ControllerStateChangeEvent } from '@metamask/base-controller';
2
2
  import { BaseController } from '@metamask/base-controller';
3
3
  import type { EntropySourceId } from '@metamask/keyring-api';
4
- import type { KeyringControllerAddNewKeyringAction, KeyringControllerGetStateAction, KeyringControllerWithKeyringAction } from '@metamask/keyring-controller';
4
+ import type { KeyringControllerGetStateAction, KeyringControllerWithControllerAction, KeyringControllerWithKeyringAction } from '@metamask/keyring-controller';
5
5
  import type { Messenger } from '@metamask/messenger';
6
6
  import type { MoneyAccountControllerMethodActions } from './MoneyAccountController-method-action-types.js';
7
7
  import type { MoneyAccount } from './types.js';
8
8
  export declare const controllerName = "MoneyAccountController";
9
+ /**
10
+ * Parameters for creating a money account.
11
+ *
12
+ * - `{ type: 'mpc' }`: create the MFA account backed by the MPC Money keyring.
13
+ * - `{ type?: 'mnemonic', entropySource }` (the default): create the SFA
14
+ * account backed by the `MoneyKeyring` for the given entropy source.
15
+ */
16
+ export type CreateMoneyAccountParams = {
17
+ /**
18
+ * The kind of money account to create. Defaults to `'mnemonic'`.
19
+ */
20
+ type?: 'mnemonic';
21
+ /**
22
+ * The entropy source ID of the SRP backing the account.
23
+ */
24
+ entropySource: EntropySourceId;
25
+ } | {
26
+ /**
27
+ * The kind of money account to create.
28
+ */
29
+ type: 'mpc';
30
+ };
9
31
  export type MoneyAccountControllerState = {
10
32
  moneyAccounts: {
11
33
  [id: MoneyAccount['id']]: MoneyAccount;
12
34
  };
35
+ defaultMoneyAccountId: MoneyAccount['id'] | null;
13
36
  };
14
37
  export declare function getDefaultMoneyAccountControllerState(): MoneyAccountControllerState;
15
38
  export type MoneyAccountControllerGetStateAction = ControllerGetStateAction<typeof controllerName, MoneyAccountControllerState>;
16
39
  export type MoneyAccountControllerActions = MoneyAccountControllerGetStateAction | MoneyAccountControllerMethodActions;
17
- type AllowedActions = KeyringControllerGetStateAction | KeyringControllerAddNewKeyringAction | KeyringControllerWithKeyringAction;
40
+ type AllowedActions = KeyringControllerGetStateAction | KeyringControllerWithControllerAction | KeyringControllerWithKeyringAction;
18
41
  export type MoneyAccountControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, MoneyAccountControllerState>;
19
42
  export type MoneyAccountControllerEvents = MoneyAccountControllerStateChangeEvent;
20
43
  type AllowedEvents = never;
@@ -41,22 +64,36 @@ export declare class MoneyAccountController extends BaseController<typeof contro
41
64
  */
42
65
  init(): Promise<void>;
43
66
  /**
44
- * Creates a money account for the given entropy source. If an account
45
- * already exists for that entropy source, it is returned as-is (idempotent).
67
+ * Creates a money account. If an account already exists for the given
68
+ * source, it is returned as-is (idempotent).
69
+ *
70
+ * The parameters determine the backing keyring:
71
+ * - `{ type: 'mpc' }`: the MPC Money keyring (MFA account), which is created and
72
+ * initialized if it does not exist yet.
73
+ * - `{ type?: 'mnemonic', entropySource }` (the default): the `MoneyKeyring`
74
+ * for that entropy source (SFA account), which is created if it does not
75
+ * exist yet.
46
76
  *
47
- * @param entropySource - The entropy source ID to create the money account for.
77
+ * @param params - The parameters for creating the money account.
48
78
  * @returns The money account.
49
79
  */
50
- createMoneyAccount(entropySource: EntropySourceId): Promise<MoneyAccount>;
80
+ createMoneyAccount(params: CreateMoneyAccountParams): Promise<MoneyAccount>;
81
+ /**
82
+ * Sets the default money account.
83
+ *
84
+ * @param id - The id of the money account to use as the default.
85
+ */
86
+ setDefaultMoneyAccount(id: MoneyAccount['id']): void;
51
87
  /**
52
- * Gets a money account by its associated entropy source ID. If no ID is
53
- * provided, the primary entropy source will be used.
88
+ * Gets a money account by id, by entropy source, or the default one.
54
89
  *
55
90
  * @param selector - Selector options for getting the money account.
56
- * @param selector.entropySource - The entropy source ID to get the money account for. If not provided, the primary entropy source will be used.
57
- * @returns The money account, or `undefined` if no account exists for the given entropy source.
91
+ * @param selector.id - The account id to look up. Takes precedence over `entropySource`.
92
+ * @param selector.entropySource - The entropy source ID to get the money account for.
93
+ * @returns The money account, or `undefined` if none matches.
58
94
  */
59
95
  getMoneyAccount(selector?: {
96
+ id?: MoneyAccount['id'];
60
97
  entropySource?: EntropySourceId;
61
98
  }): MoneyAccount | undefined;
62
99
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"MoneyAccountController.d.ts","sourceRoot":"","sources":["../src/MoneyAccountController.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAO3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EACV,oCAAoC,EACpC,+BAA+B,EAC/B,kCAAkC,EAGnC,MAAM,8BAA8B,CAAC;AAMtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAIrD,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,iDAAiD,CAAC;AAC3G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,eAAO,MAAM,cAAc,2BAA2B,CAAC;AAEvD,MAAM,MAAM,2BAA2B,GAAG;IACxC,aAAa,EAAE;QACb,CAAC,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC;KACxC,CAAC;CACH,CAAC;AAWF,wBAAgB,qCAAqC,IAAI,2BAA2B,CAInF;AASD,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,KAAK,cAAc,GACf,+BAA+B,GAC/B,oCAAoC,GACpC,kCAAkC,CAAC;AAEvC,MAAM,MAAM,sCAAsC,GAAG,0BAA0B,CAC7E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,4BAA4B,GACtC,sCAAsC,CAAC;AAEzC,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B,MAAM,MAAM,+BAA+B,GAAG,SAAS,CACrD,OAAO,cAAc,EACrB,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,GAAG,aAAa,CAC7C,CAAC;AAEF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;IAGC;;;;;;OAMG;IACH,YAAY,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;KAC9C,EAiBA;IAED;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAiB1B;IAED;;;;;;OAMG;IACG,kBAAkB,CACtB,aAAa,EAAE,eAAe,GAC7B,OAAO,CAAC,YAAY,CAAC,CA6DvB;IAED;;;;;;;OAOG;IACH,eAAe,CACb,QAAQ,GAAE;QAAE,aAAa,CAAC,EAAE,eAAe,CAAA;KAAO,GACjD,YAAY,GAAG,SAAS,CAY1B;IAED;;;;;;OAMG;IACH,UAAU,IAAI,IAAI,CAIjB;CAiHF"}
1
+ {"version":3,"file":"MoneyAccountController.d.ts","sourceRoot":"","sources":["../src/MoneyAccountController.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EACV,+BAA+B,EAC/B,qCAAqC,EACrC,kCAAkC,EAEnC,MAAM,8BAA8B,CAAC;AAGtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAIrD,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,iDAAiD,CAAC;AAC3G,OAAO,KAAK,EAAE,YAAY,EAA8B,MAAM,YAAY,CAAC;AAO3E,eAAO,MAAM,cAAc,2BAA2B,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAChC;IACE;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB;;OAEG;IACH,aAAa,EAAE,eAAe,CAAC;CAChC,GACD;IACE;;OAEG;IACH,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEN,MAAM,MAAM,2BAA2B,GAAG;IACxC,aAAa,EAAE;QACb,CAAC,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC;KACxC,CAAC;IACF,qBAAqB,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAClD,CAAC;AAiBF,wBAAgB,qCAAqC,IAAI,2BAA2B,CAKnF;AAqBD,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,KAAK,cAAc,GACf,+BAA+B,GAC/B,qCAAqC,GACrC,kCAAkC,CAAC;AAEvC,MAAM,MAAM,sCAAsC,GAAG,0BAA0B,CAC7E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,4BAA4B,GACtC,sCAAsC,CAAC;AAEzC,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B,MAAM,MAAM,+BAA+B,GAAG,SAAS,CACrD,OAAO,cAAc,EACrB,6BAA6B,GAAG,cAAc,EAC9C,4BAA4B,GAAG,aAAa,CAC7C,CAAC;AAYF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;IACC;;;;;;OAMG;IACH,YAAY,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;KAC9C,EAeA;IAED;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB1B;IAED;;;;;;;;;;;;;OAaG;IACG,kBAAkB,CACtB,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,YAAY,CAAC,CAsBvB;IAED;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAQnD;IAED;;;;;;;OAOG;IACH,eAAe,CACb,QAAQ,GAAE;QACR,EAAE,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;QACxB,aAAa,CAAC,EAAE,eAAe,CAAC;KAC5B,GACL,YAAY,GAAG,SAAS,CAe1B;IAED;;;;;;OAMG;IACH,UAAU,IAAI,IAAI,CAKjB;CAkSF"}
@@ -2,10 +2,9 @@ import { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller
2
2
  import { BaseController } from '@metamask/base-controller';
3
3
  import { MONEY_DERIVATION_PATH } from '@metamask/eth-money-keyring';
4
4
  import { EthAccountType, EthMethod, EthScope } from '@metamask/keyring-api';
5
- import { isKeyringNotFoundError, KeyringTypes, } from '@metamask/keyring-controller';
6
- import { Mutex } from 'async-mutex';
5
+ import { KeyringTypes } from '@metamask/keyring-controller';
7
6
  import { projectLogger as log } from './logger.js';
8
- import { isMoneyKeyring } from './utils.js';
7
+ import { isMoneyKeyring, isMpcMoneyKeyring, MPC_ENTROPY_SOURCE_ID, } from './utils.js';
9
8
  export const controllerName = 'MoneyAccountController';
10
9
  const moneyAccountControllerMetadata = {
11
10
  moneyAccounts: {
@@ -14,23 +13,40 @@ const moneyAccountControllerMetadata = {
14
13
  persist: true,
15
14
  usedInUi: true,
16
15
  },
16
+ defaultMoneyAccountId: {
17
+ includeInDebugSnapshot: true,
18
+ includeInStateLogs: true,
19
+ persist: true,
20
+ usedInUi: true,
21
+ },
17
22
  };
18
23
  export function getDefaultMoneyAccountControllerState() {
19
24
  return {
20
25
  moneyAccounts: {},
26
+ defaultMoneyAccountId: null,
21
27
  };
22
28
  }
23
29
  const MESSENGER_EXPOSED_METHODS = [
24
30
  'createMoneyAccount',
25
31
  'getMoneyAccount',
32
+ 'setDefaultMoneyAccount',
26
33
  'clearState',
27
34
  'init',
28
35
  ];
36
+ /**
37
+ * The signing methods supported by money accounts.
38
+ */
39
+ const MONEY_ACCOUNT_METHODS = [
40
+ EthMethod.PersonalSign,
41
+ EthMethod.SignTypedDataV1,
42
+ EthMethod.SignTypedDataV3,
43
+ EthMethod.SignTypedDataV4,
44
+ // TODO: Update this once the `keyring-api` package supports `SignEip7702Authorization` method.
45
+ ];
29
46
  /**
30
47
  * Controller for managing money accounts.
31
48
  */
32
49
  export class MoneyAccountController extends BaseController {
33
- #lock;
34
50
  /**
35
51
  * Constructor for the MoneyAccountController.
36
52
  *
@@ -49,7 +65,6 @@ export class MoneyAccountController extends BaseController {
49
65
  },
50
66
  });
51
67
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
52
- this.#lock = new Mutex();
53
68
  }
54
69
  /**
55
70
  * Initializes the controller by creating a money account for the primary
@@ -59,7 +74,9 @@ export class MoneyAccountController extends BaseController {
59
74
  this.#assertIsUnlocked();
60
75
  const primaryEntropySource = this.#getPrimaryEntropySource();
61
76
  if (primaryEntropySource) {
62
- const { id, address } = await this.createMoneyAccount(primaryEntropySource);
77
+ const { id, address } = await this.createMoneyAccount({
78
+ entropySource: primaryEntropySource,
79
+ });
63
80
  log(`Money keyring (entropy:${primaryEntropySource} - primary) account is: ${address} (${id})`);
64
81
  }
65
82
  else {
@@ -69,20 +86,90 @@ export class MoneyAccountController extends BaseController {
69
86
  }
70
87
  }
71
88
  /**
72
- * Creates a money account for the given entropy source. If an account
73
- * already exists for that entropy source, it is returned as-is (idempotent).
89
+ * Creates a money account. If an account already exists for the given
90
+ * source, it is returned as-is (idempotent).
74
91
  *
75
- * @param entropySource - The entropy source ID to create the money account for.
92
+ * The parameters determine the backing keyring:
93
+ * - `{ type: 'mpc' }`: the MPC Money keyring (MFA account), which is created and
94
+ * initialized if it does not exist yet.
95
+ * - `{ type?: 'mnemonic', entropySource }` (the default): the `MoneyKeyring`
96
+ * for that entropy source (SFA account), which is created if it does not
97
+ * exist yet.
98
+ *
99
+ * @param params - The parameters for creating the money account.
76
100
  * @returns The money account.
77
101
  */
78
- async createMoneyAccount(entropySource) {
102
+ async createMoneyAccount(params) {
79
103
  this.#assertIsUnlocked();
80
- // Idempotent: return existing account if already in state.
81
- const existingAccount = this.getMoneyAccount({ entropySource });
104
+ // Idempotent: return existing account if already in state. The stored
105
+ // entropy source ID identifies the account for both account kinds.
106
+ const entropySourceId = params.type === 'mpc' ? MPC_ENTROPY_SOURCE_ID : params.entropySource;
107
+ const existingAccount = this.#getMoneyAccountByEntropySource(entropySourceId);
82
108
  if (existingAccount) {
83
109
  return existingAccount;
84
110
  }
85
- const address = await this.#withKeyring(entropySource, async (keyring) => {
111
+ const account = params.type === 'mpc'
112
+ ? await this.#createMpcMoneyKeyringAccount()
113
+ : await this.#createMoneyKeyringAccount(params.entropySource);
114
+ log(`Money account created: ${account.address} (${account.id}) for entropy source: ${entropySourceId}`);
115
+ return account;
116
+ }
117
+ /**
118
+ * Sets the default money account.
119
+ *
120
+ * @param id - The id of the money account to use as the default.
121
+ */
122
+ setDefaultMoneyAccount(id) {
123
+ if (this.state.moneyAccounts[id] === undefined) {
124
+ throw new Error(`Unknown money account: ${id}`);
125
+ }
126
+ this.update((state) => {
127
+ state.defaultMoneyAccountId = id;
128
+ });
129
+ }
130
+ /**
131
+ * Gets a money account by id, by entropy source, or the default one.
132
+ *
133
+ * @param selector - Selector options for getting the money account.
134
+ * @param selector.id - The account id to look up. Takes precedence over `entropySource`.
135
+ * @param selector.entropySource - The entropy source ID to get the money account for.
136
+ * @returns The money account, or `undefined` if none matches.
137
+ */
138
+ getMoneyAccount(selector = {}) {
139
+ if (selector.id !== undefined) {
140
+ return this.state.moneyAccounts[selector.id];
141
+ }
142
+ if (selector.entropySource !== undefined) {
143
+ return this.#getMoneyAccountByEntropySource(selector.entropySource);
144
+ }
145
+ const defaultMoneyAccountId = this.state.defaultMoneyAccountId ?? null;
146
+ if (defaultMoneyAccountId === null) {
147
+ return undefined;
148
+ }
149
+ return this.state.moneyAccounts[defaultMoneyAccountId];
150
+ }
151
+ /**
152
+ * Resets the controller state to its default, removing all money accounts.
153
+ *
154
+ * Intended for use during a full app reset (e.g. when the user wipes all
155
+ * wallet data). Does not interact with the keyring — the caller is
156
+ * responsible for ensuring the associated keyring state is also cleared.
157
+ */
158
+ clearState() {
159
+ this.update((state) => {
160
+ state.moneyAccounts = {};
161
+ state.defaultMoneyAccountId = null;
162
+ });
163
+ }
164
+ /**
165
+ * Creates or reuses a `MoneyKeyring` account for the given entropy source.
166
+ *
167
+ * @param entropySource - The entropy source ID to create the money account for.
168
+ * @returns The money account.
169
+ */
170
+ async #createMoneyKeyringAccount(entropySource) {
171
+ const id = await this.#ensureMoneyKeyring(entropySource);
172
+ const address = await this.#withMoneyKeyring(id, async (keyring) => {
86
173
  // We're adding this logic to be defensive against the possibility of a money keyring
87
174
  // existing without any accounts, which shouldn't normally happen but we want to be
88
175
  // sure we can handle it if it does.
@@ -92,10 +179,66 @@ export class MoneyAccountController extends BaseController {
92
179
  const [moneyAddress] = accounts;
93
180
  return moneyAddress;
94
181
  }
95
- log(`Money keyring (entropy:${entropySource}) has no accounts, creating one...`);
182
+ log(`Money keyring (id:${id}, entropy:${entropySource}) has no accounts, creating one...`);
96
183
  const [moneyAddress] = await keyring.addAccounts(1);
97
184
  return moneyAddress;
98
185
  });
186
+ return this.#createKeyringAccount({
187
+ address,
188
+ entropy: {
189
+ type: 'mnemonic',
190
+ id: entropySource,
191
+ groupIndex: 0,
192
+ derivationPath: MONEY_DERIVATION_PATH,
193
+ },
194
+ });
195
+ }
196
+ /**
197
+ * Creates or reuses an account on the MPC Money keyring.
198
+ *
199
+ * The MPC Money keyring is an atomic keyring: its initialization is cheap when
200
+ * already initialized, and long-running work is dispatched without holding
201
+ * the keyring controller mutex.
202
+ *
203
+ * @returns The money account.
204
+ */
205
+ async #createMpcMoneyKeyringAccount() {
206
+ const id = await this.#ensureMpcMoneyKeyring();
207
+ const address = await this.#withMpcMoneyKeyring(id, async (keyring) => {
208
+ // The keyring infers the setup mode (create or import) from its own
209
+ // state. This is a no-op if the keyring is already initialized.
210
+ await keyring.init();
211
+ // We're adding this logic to be defensive against the possibility of an
212
+ // MPC Money keyring existing without any accounts, which shouldn't normally
213
+ // happen but we want to be sure we can handle it if it does.
214
+ const accounts = await keyring.getAccounts();
215
+ if (accounts.length > 0) {
216
+ const [mpcAddress] = accounts;
217
+ return mpcAddress;
218
+ }
219
+ log(`MPC Money keyring (${id}) has no accounts, adding one...`);
220
+ const [mpcAddress] = await keyring.addAccounts(1);
221
+ return mpcAddress;
222
+ });
223
+ return this.#createKeyringAccount({
224
+ address,
225
+ entropy: {
226
+ type: 'mpc',
227
+ id: MPC_ENTROPY_SOURCE_ID,
228
+ },
229
+ });
230
+ }
231
+ /**
232
+ * Builds a money account for the given address and entropy options, stores
233
+ * it in state, and returns it. If no default account is set, the new account
234
+ * becomes the default.
235
+ *
236
+ * @param params - The parameters for creating the account.
237
+ * @param params.address - The account address.
238
+ * @param params.entropy - The entropy options of the backing keyring.
239
+ * @returns The money account.
240
+ */
241
+ #createKeyringAccount({ address, entropy, }) {
99
242
  const account = {
100
243
  // This is an EVM account, so let's re-use the deterministic ID generation logic of
101
244
  // EVM accounts.
@@ -104,114 +247,110 @@ export class MoneyAccountController extends BaseController {
104
247
  address,
105
248
  scopes: [EthScope.Eoa],
106
249
  options: {
107
- entropy: {
108
- type: 'mnemonic',
109
- id: entropySource,
110
- groupIndex: 0,
111
- derivationPath: MONEY_DERIVATION_PATH,
112
- },
250
+ entropy,
113
251
  exportable: false,
114
252
  },
115
- methods: [
116
- EthMethod.PersonalSign,
117
- EthMethod.SignTypedDataV1,
118
- EthMethod.SignTypedDataV3,
119
- EthMethod.SignTypedDataV4,
120
- // TODO: Update this once the `keyring-api` package supports `SignEip7702Authorization` method.
121
- ],
253
+ methods: [...MONEY_ACCOUNT_METHODS],
122
254
  };
123
- // Store the account in state.
124
255
  this.update((state) => {
125
256
  state.moneyAccounts[account.id] = account;
257
+ state.defaultMoneyAccountId ??= account.id;
126
258
  });
127
- log(`Money keyring (entropy:${account.options.entropy.id}) account created: ${account.address} (${account.id})`);
128
259
  return account;
129
260
  }
130
261
  /**
131
- * Gets a money account by its associated entropy source ID. If no ID is
132
- * provided, the primary entropy source will be used.
262
+ * Gets a money account by entropy source ID.
133
263
  *
134
- * @param selector - Selector options for getting the money account.
135
- * @param selector.entropySource - The entropy source ID to get the money account for. If not provided, the primary entropy source will be used.
136
- * @returns The money account, or `undefined` if no account exists for the given entropy source.
264
+ * @param entropySource - The entropy source ID.
265
+ * @returns The matching account, if any.
137
266
  */
138
- getMoneyAccount(selector = {}) {
139
- const entropySource = selector.entropySource ?? this.#getPrimaryEntropySource();
140
- if (entropySource === undefined) {
141
- return undefined;
142
- }
143
- // We should never have more than one money account per entropy source, but if we
144
- // do, just return the first one we find.
267
+ #getMoneyAccountByEntropySource(entropySource) {
145
268
  return Object.values(this.state.moneyAccounts).find((account) => account.options.entropy.id === entropySource);
146
269
  }
147
270
  /**
148
- * Resets the controller state to its default, removing all money accounts.
271
+ * Ensures a `MoneyKeyring` exists for the given entropy source, creating one
272
+ * atomically if it does not, and returns its keyring ID.
149
273
  *
150
- * Intended for use during a full app reset (e.g. when the user wipes all
151
- * wallet data). Does not interact with the keyring — the caller is
152
- * responsible for ensuring the associated keyring state is also cleared.
274
+ * The check-or-create is performed within a single
275
+ * `KeyringController:withController` transaction, which is mutually
276
+ * exclusive and rolls back on error.
277
+ *
278
+ * @param entropySource - The entropy source ID identifying the target keyring.
279
+ * @returns The keyring ID of the existing or newly created keyring.
153
280
  */
154
- clearState() {
155
- this.update((state) => {
156
- state.moneyAccounts = {};
157
- });
281
+ async #ensureMoneyKeyring(entropySource) {
282
+ return (await this.messenger.call('KeyringController:withController', async (restrictedController) => {
283
+ const moneyKeyrings = restrictedController.keyrings.filter((entry) => isMoneyKeyring(entry.keyring) &&
284
+ entry.keyring.entropySource === entropySource);
285
+ if (moneyKeyrings.length > 0) {
286
+ return moneyKeyrings[0].metadata.id;
287
+ }
288
+ log(`Money keyring (entropy:${entropySource}) not found, creating one...`);
289
+ const entry = await restrictedController.addNewKeyring(KeyringTypes.money, { entropySource });
290
+ return entry.metadata.id;
291
+ }));
158
292
  }
159
293
  /**
160
- * Calls `KeyringController:withKeyring` for the `MoneyKeyring` associated with the
161
- * given entropy source, creating one first if it does not yet exist.
294
+ * Ensures the MPC Money keyring exists, creating it atomically if it does not, and
295
+ * returns its keyring ID.
162
296
  *
163
- * @param entropySource - The entropy source ID identifying the target keyring.
164
- * @param operation - Callback invoked with the resolved `MoneyKeyring`.
165
- * @returns The value returned by `operation`.
297
+ * The check-or-create is performed within a single
298
+ * `KeyringController:withController` transaction, which is mutually
299
+ * exclusive and rolls back on error.
300
+ *
301
+ * @returns The keyring ID of the existing or newly created keyring.
166
302
  */
167
- async #withKeyring(entropySource, operation) {
168
- // Filter to find a specific `MoneyKeyring` for the given entropy source.
169
- const isMoneyKeyringForEntropySource = (keyring) => isMoneyKeyring(keyring) && keyring.entropySource === entropySource;
170
- // We cannot use proper generic-type inference using the messenger
171
- // here, so we have to use a type casts for `keyring` and the return type.
172
- const withKeyring = async (selector, callback) => this.messenger.call('KeyringController:withKeyring', selector, async ({ keyring }) => callback(keyring));
173
- // We have an extra lock here to avoid a race-condition where 2 calls to
174
- // `#withKeyring` for the same entropy source happen at the same time, and
175
- // both don't find an existing keyring, so they both try to create a new
176
- // one, which creates multiple keyrings for the same entropy source.
177
- // NOTE: We cannot use `createIfMissing` here either, since it's only supported
178
- // for selectors by type (and we want to deprecate this option).
179
- // TODO: Move this new pattern in the `KeyringController`.
180
- return await this.#lock.runExclusive(async () => {
181
- try {
182
- return await withKeyring({
183
- filter: isMoneyKeyringForEntropySource,
184
- }, operation);
303
+ async #ensureMpcMoneyKeyring() {
304
+ return (await this.messenger.call('KeyringController:withController', async (restrictedController) => {
305
+ const mpcKeyrings = restrictedController.keyrings.filter((entry) => isMpcMoneyKeyring(entry.keyring));
306
+ if (mpcKeyrings.length > 1) {
307
+ throw new Error('Multiple MPC Money keyrings found');
185
308
  }
186
- catch (error) {
187
- // Forward any unexpected errors, but if the error is that
188
- // the keyring wasn't found, we'll create it below.
189
- if (!isKeyringNotFoundError(error)) {
190
- throw error;
191
- }
192
- // Create the keyring so we can use `withKeyring` to operate on it in the
193
- // retry below.
194
- log(`Money keyring (entropy:${entropySource}) not found, creating one...`);
195
- const { id } = await this.#createMoneyKeyring(entropySource);
196
- // Use the ID directly on the retry (we just created this keyring so we
197
- // know exactly which one to target).
198
- return await withKeyring({ id }, operation);
309
+ if (mpcKeyrings.length === 1) {
310
+ return mpcKeyrings[0].metadata.id;
199
311
  }
200
- });
312
+ log('MPC Money keyring not found, creating one...');
313
+ const entry = await restrictedController.addNewKeyring(KeyringTypes.mpcMoney);
314
+ return entry.metadata.id;
315
+ }));
316
+ }
317
+ /**
318
+ * Calls `KeyringController:withKeyring` for the keyring with the given ID.
319
+ *
320
+ * @param id - The keyring metadata ID.
321
+ * @param assertType - Verifies the resolved keyring has the expected type.
322
+ * @param operation - Callback invoked with the resolved keyring.
323
+ * @returns The value returned by `operation`.
324
+ */
325
+ async #withKeyring(id, assertType, operation) {
326
+ return (await this.messenger.call('KeyringController:withKeyring', { id }, async ({ keyring }) => {
327
+ if (!assertType(keyring)) {
328
+ throw new Error(`Keyring ${id} has an unexpected type`);
329
+ }
330
+ return operation(keyring);
331
+ }));
201
332
  }
202
333
  /**
203
- * Adds a new money keyring for the given entropy source and returns its metadata.
334
+ * Calls `KeyringController:withKeyring` for the `MoneyKeyring` with the
335
+ * given ID.
204
336
  *
205
- * NOTE: This function won't check if a money keyring for the given entropy source already
206
- * exists!
337
+ * @param id - The keyring metadata ID.
338
+ * @param operation - Callback invoked with the resolved `MoneyKeyring`.
339
+ * @returns The value returned by `operation`.
340
+ */
341
+ async #withMoneyKeyring(id, operation) {
342
+ return await this.#withKeyring(id, isMoneyKeyring, async (keyring) => operation(keyring));
343
+ }
344
+ /**
345
+ * Calls `KeyringController:withKeyring` for the MPC Money keyring with the given
346
+ * ID.
207
347
  *
208
- * @param entropySource - The entropy source ID to create the money keyring for.
209
- * @returns The metadata of the newly created money keyring.
348
+ * @param id - The keyring metadata ID.
349
+ * @param operation - Callback invoked with the resolved MPC Money keyring.
350
+ * @returns The value returned by `operation`.
210
351
  */
211
- #createMoneyKeyring(entropySource) {
212
- return this.messenger.call('KeyringController:addNewKeyring', KeyringTypes.money, {
213
- entropySource,
214
- });
352
+ async #withMpcMoneyKeyring(id, operation) {
353
+ return await this.#withKeyring(id, isMpcMoneyKeyring, async (keyring) => operation(keyring));
215
354
  }
216
355
  /**
217
356
  * Gets the primary entropy source ID.
@@ -1 +1 @@
1
- {"version":3,"file":"MoneyAccountController.js","sourceRoot":"","sources":["../src/MoneyAccountController.ts"],"names":[],"mappings":"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","sourcesContent":["import { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n MoneyKeyring,\n MoneyKeyringSerializedState,\n} from '@metamask/eth-money-keyring';\nimport { MONEY_DERIVATION_PATH } from '@metamask/eth-money-keyring';\nimport { EthAccountType, EthMethod, EthScope } from '@metamask/keyring-api';\nimport type { EntropySourceId } from '@metamask/keyring-api';\nimport type {\n KeyringControllerAddNewKeyringAction,\n KeyringControllerGetStateAction,\n KeyringControllerWithKeyringAction,\n KeyringMetadata,\n KeyringSelector,\n} from '@metamask/keyring-controller';\nimport {\n isKeyringNotFoundError,\n KeyringTypes,\n} from '@metamask/keyring-controller';\nimport { EthKeyring } from '@metamask/keyring-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport { Mutex } from 'async-mutex';\n\nimport { projectLogger as log } from './logger.js';\nimport type { MoneyAccountControllerMethodActions } from './MoneyAccountController-method-action-types.js';\nimport type { MoneyAccount } from './types.js';\nimport { isMoneyKeyring } from './utils.js';\n\nexport const controllerName = 'MoneyAccountController';\n\nexport type MoneyAccountControllerState = {\n moneyAccounts: {\n [id: MoneyAccount['id']]: MoneyAccount;\n };\n};\n\nconst moneyAccountControllerMetadata = {\n moneyAccounts: {\n includeInDebugSnapshot: false,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n} satisfies StateMetadata<MoneyAccountControllerState>;\n\nexport function getDefaultMoneyAccountControllerState(): MoneyAccountControllerState {\n return {\n moneyAccounts: {},\n };\n}\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'createMoneyAccount',\n 'getMoneyAccount',\n 'clearState',\n 'init',\n] as const;\n\nexport type MoneyAccountControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n MoneyAccountControllerState\n>;\n\nexport type MoneyAccountControllerActions =\n | MoneyAccountControllerGetStateAction\n | MoneyAccountControllerMethodActions;\n\ntype AllowedActions =\n | KeyringControllerGetStateAction\n | KeyringControllerAddNewKeyringAction\n | KeyringControllerWithKeyringAction;\n\nexport type MoneyAccountControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n MoneyAccountControllerState\n>;\n\nexport type MoneyAccountControllerEvents =\n MoneyAccountControllerStateChangeEvent;\n\ntype AllowedEvents = never;\n\nexport type MoneyAccountControllerMessenger = Messenger<\n typeof controllerName,\n MoneyAccountControllerActions | AllowedActions,\n MoneyAccountControllerEvents | AllowedEvents\n>;\n\n/**\n * Controller for managing money accounts.\n */\nexport class MoneyAccountController extends BaseController<\n typeof controllerName,\n MoneyAccountControllerState,\n MoneyAccountControllerMessenger\n> {\n readonly #lock: Mutex;\n\n /**\n * Constructor for the MoneyAccountController.\n *\n * @param options - The options for constructing the controller.\n * @param options.messenger - The messenger to use for inter-controller communication.\n * @param options.state - The initial state of the controller. If not provided, the default state will be used.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: MoneyAccountControllerMessenger;\n state?: Partial<MoneyAccountControllerState>;\n }) {\n super({\n messenger,\n metadata: moneyAccountControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultMoneyAccountControllerState(),\n ...state,\n },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n this.#lock = new Mutex();\n }\n\n /**\n * Initializes the controller by creating a money account for the primary\n * entropy source if one does not already exist.\n */\n async init(): Promise<void> {\n this.#assertIsUnlocked();\n\n const primaryEntropySource = this.#getPrimaryEntropySource();\n if (primaryEntropySource) {\n const { id, address } =\n await this.createMoneyAccount(primaryEntropySource);\n log(\n `Money keyring (entropy:${primaryEntropySource} - primary) account is: ${address} (${id})`,\n );\n } else {\n const message =\n 'No primary HD keyring found, skipping default Money account creation!';\n\n console.warn(message);\n log(`WARNING -- ${message}`);\n }\n }\n\n /**\n * Creates a money account for the given entropy source. If an account\n * already exists for that entropy source, it is returned as-is (idempotent).\n *\n * @param entropySource - The entropy source ID to create the money account for.\n * @returns The money account.\n */\n async createMoneyAccount(\n entropySource: EntropySourceId,\n ): Promise<MoneyAccount> {\n this.#assertIsUnlocked();\n\n // Idempotent: return existing account if already in state.\n const existingAccount = this.getMoneyAccount({ entropySource });\n if (existingAccount) {\n return existingAccount;\n }\n\n const address = await this.#withKeyring(entropySource, async (keyring) => {\n // We're adding this logic to be defensive against the possibility of a money keyring\n // existing without any accounts, which shouldn't normally happen but we want to be\n // sure we can handle it if it does.\n // If there are no accounts, we'll add one and then get the address.\n const accounts = await keyring.getAccounts();\n if (accounts.length > 0) {\n const [moneyAddress] = accounts;\n return moneyAddress;\n }\n\n log(\n `Money keyring (entropy:${entropySource}) has no accounts, creating one...`,\n );\n const [moneyAddress] = await keyring.addAccounts(1);\n return moneyAddress;\n });\n\n const account: MoneyAccount = {\n // This is an EVM account, so let's re-use the deterministic ID generation logic of\n // EVM accounts.\n id: getUUIDFromAddressOfNormalAccount(address),\n type: EthAccountType.Eoa,\n address,\n scopes: [EthScope.Eoa],\n options: {\n entropy: {\n type: 'mnemonic',\n id: entropySource,\n groupIndex: 0,\n derivationPath: MONEY_DERIVATION_PATH,\n },\n exportable: false,\n },\n methods: [\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n // TODO: Update this once the `keyring-api` package supports `SignEip7702Authorization` method.\n ],\n };\n\n // Store the account in state.\n this.update((state) => {\n state.moneyAccounts[account.id] = account;\n });\n\n log(\n `Money keyring (entropy:${account.options.entropy.id}) account created: ${account.address} (${account.id})`,\n );\n return account;\n }\n\n /**\n * Gets a money account by its associated entropy source ID. If no ID is\n * provided, the primary entropy source will be used.\n *\n * @param selector - Selector options for getting the money account.\n * @param selector.entropySource - The entropy source ID to get the money account for. If not provided, the primary entropy source will be used.\n * @returns The money account, or `undefined` if no account exists for the given entropy source.\n */\n getMoneyAccount(\n selector: { entropySource?: EntropySourceId } = {},\n ): MoneyAccount | undefined {\n const entropySource =\n selector.entropySource ?? this.#getPrimaryEntropySource();\n if (entropySource === undefined) {\n return undefined;\n }\n\n // We should never have more than one money account per entropy source, but if we\n // do, just return the first one we find.\n return Object.values(this.state.moneyAccounts).find(\n (account) => account.options.entropy.id === entropySource,\n );\n }\n\n /**\n * Resets the controller state to its default, removing all money accounts.\n *\n * Intended for use during a full app reset (e.g. when the user wipes all\n * wallet data). Does not interact with the keyring — the caller is\n * responsible for ensuring the associated keyring state is also cleared.\n */\n clearState(): void {\n this.update((state) => {\n state.moneyAccounts = {};\n });\n }\n\n /**\n * Calls `KeyringController:withKeyring` for the `MoneyKeyring` associated with the\n * given entropy source, creating one first if it does not yet exist.\n *\n * @param entropySource - The entropy source ID identifying the target keyring.\n * @param operation - Callback invoked with the resolved `MoneyKeyring`.\n * @returns The value returned by `operation`.\n */\n async #withKeyring<Result>(\n entropySource: EntropySourceId,\n operation: (keyring: MoneyKeyring) => Promise<Result>,\n ): Promise<Result> {\n // Filter to find a specific `MoneyKeyring` for the given entropy source.\n const isMoneyKeyringForEntropySource = (\n keyring: EthKeyring,\n ): keyring is MoneyKeyring =>\n isMoneyKeyring(keyring) && keyring.entropySource === entropySource;\n\n // We cannot use proper generic-type inference using the messenger\n // here, so we have to use a type casts for `keyring` and the return type.\n const withKeyring = async (\n selector: KeyringSelector<MoneyKeyring>,\n callback: (keyring: MoneyKeyring) => Promise<Result>,\n ): Promise<Result> =>\n this.messenger.call(\n 'KeyringController:withKeyring',\n selector,\n async ({ keyring }) => callback(keyring as MoneyKeyring),\n ) as Promise<Result>;\n\n // We have an extra lock here to avoid a race-condition where 2 calls to\n // `#withKeyring` for the same entropy source happen at the same time, and\n // both don't find an existing keyring, so they both try to create a new\n // one, which creates multiple keyrings for the same entropy source.\n // NOTE: We cannot use `createIfMissing` here either, since it's only supported\n // for selectors by type (and we want to deprecate this option).\n // TODO: Move this new pattern in the `KeyringController`.\n return await this.#lock.runExclusive(async () => {\n try {\n return await withKeyring(\n {\n filter: isMoneyKeyringForEntropySource,\n },\n operation,\n );\n } catch (error) {\n // Forward any unexpected errors, but if the error is that\n // the keyring wasn't found, we'll create it below.\n if (!isKeyringNotFoundError(error)) {\n throw error;\n }\n\n // Create the keyring so we can use `withKeyring` to operate on it in the\n // retry below.\n log(\n `Money keyring (entropy:${entropySource}) not found, creating one...`,\n );\n const { id } = await this.#createMoneyKeyring(entropySource);\n\n // Use the ID directly on the retry (we just created this keyring so we\n // know exactly which one to target).\n return await withKeyring({ id }, operation);\n }\n });\n }\n\n /**\n * Adds a new money keyring for the given entropy source and returns its metadata.\n *\n * NOTE: This function won't check if a money keyring for the given entropy source already\n * exists!\n *\n * @param entropySource - The entropy source ID to create the money keyring for.\n * @returns The metadata of the newly created money keyring.\n */\n #createMoneyKeyring(\n entropySource: EntropySourceId,\n ): Promise<KeyringMetadata> {\n return this.messenger.call(\n 'KeyringController:addNewKeyring',\n KeyringTypes.money,\n {\n entropySource,\n },\n );\n }\n\n /**\n * Gets the primary entropy source ID.\n *\n * @returns The primary entropy source ID, or `undefined` if no HD keyring exists.\n */\n #getPrimaryEntropySource(): EntropySourceId | undefined {\n const { keyrings } = this.messenger.call('KeyringController:getState');\n const primaryHdKeyring = keyrings.find(\n (keyring) => keyring.type === KeyringTypes.hd,\n );\n return primaryHdKeyring?.metadata.id;\n }\n\n /**\n * Throws if the keyring is currently locked.\n */\n #assertIsUnlocked(): void {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n throw new Error(\n 'Cannot create a money account while the keyring is locked',\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"MoneyAccountController.js","sourceRoot":"","sources":["../src/MoneyAccountController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAE,MAAM,+BAA+B,CAAC;AAMlF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAQ5E,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAK5D,OAAO,EAAE,aAAa,IAAI,GAAG,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAmCvD,MAAM,8BAA8B,GAAG;IACrC,aAAa,EAAE;QACb,sBAAsB,EAAE,KAAK;QAC7B,kBAAkB,EAAE,IAAI;QACxB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf;IACD,qBAAqB,EAAE;QACrB,sBAAsB,EAAE,IAAI;QAC5B,kBAAkB,EAAE,IAAI;QACxB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf;CACmD,CAAC;AAEvD,MAAM,UAAU,qCAAqC;IACnD,OAAO;QACL,aAAa,EAAE,EAAE;QACjB,qBAAqB,EAAE,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,yBAAyB,GAAG;IAChC,oBAAoB;IACpB,iBAAiB;IACjB,wBAAwB;IACxB,YAAY;IACZ,MAAM;CACE,CAAC;AAEX;;GAEG;AACH,MAAM,qBAAqB,GAAG;IAC5B,SAAS,CAAC,YAAY;IACtB,SAAS,CAAC,eAAe;IACzB,SAAS,CAAC,eAAe;IACzB,SAAS,CAAC,eAAe;IACzB,+FAA+F;CACvF,CAAC;AA0CX;;GAEG;AACH,MAAM,OAAO,sBAAuB,SAAQ,cAI3C;IACC;;;;;;OAMG;IACH,YAAY,EACV,SAAS,EACT,KAAK,GAIN;QACC,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ,EAAE,8BAA8B;YACxC,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE;gBACL,GAAG,qCAAqC,EAAE;gBAC1C,GAAG,KAAK;aACT;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,CAAC,4BAA4B,CACzC,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzB,MAAM,oBAAoB,GAAG,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAC7D,IAAI,oBAAoB,EAAE,CAAC;YACzB,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC;gBACpD,aAAa,EAAE,oBAAoB;aACpC,CAAC,CAAC;YACH,GAAG,CACD,0BAA0B,oBAAoB,2BAA2B,OAAO,KAAK,EAAE,GAAG,CAC3F,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GACX,uEAAuE,CAAC;YAE1E,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,GAAG,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,kBAAkB,CACtB,MAAgC;QAEhC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzB,sEAAsE;QACtE,mEAAmE;QACnE,MAAM,eAAe,GACnB,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;QACvE,MAAM,eAAe,GACnB,IAAI,CAAC,+BAA+B,CAAC,eAAe,CAAC,CAAC;QACxD,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,eAAe,CAAC;QACzB,CAAC;QAED,MAAM,OAAO,GACX,MAAM,CAAC,IAAI,KAAK,KAAK;YACnB,CAAC,CAAC,MAAM,IAAI,CAAC,6BAA6B,EAAE;YAC5C,CAAC,CAAC,MAAM,IAAI,CAAC,0BAA0B,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAElE,GAAG,CACD,0BAA0B,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,yBAAyB,eAAe,EAAE,CACnG,CAAC;QACF,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACH,sBAAsB,CAAC,EAAsB;QAC3C,IAAI,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,SAAS,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,eAAe,CACb,QAAQ,GAGJ,EAAE;QAEN,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,QAAQ,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,+BAA+B,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,qBAAqB,GAAG,IAAI,CAAC,KAAK,CAAC,qBAAqB,IAAI,IAAI,CAAC;QACvE,IAAI,qBAAqB,KAAK,IAAI,EAAE,CAAC;YACnC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;OAMG;IACH,UAAU;QACR,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,aAAa,GAAG,EAAE,CAAC;YACzB,KAAK,CAAC,qBAAqB,GAAG,IAAI,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,0BAA0B,CAC9B,aAA8B;QAE9B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAEzD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACjE,qFAAqF;YACrF,mFAAmF;YACnF,oCAAoC;YACpC,oEAAoE;YACpE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,CAAC,YAAY,CAAC,GAAG,QAAQ,CAAC;gBAChC,OAAO,YAAY,CAAC;YACtB,CAAC;YAED,GAAG,CACD,qBAAqB,EAAE,aAAa,aAAa,oCAAoC,CACtF,CAAC;YACF,MAAM,CAAC,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YACpD,OAAO,YAAY,CAAC;QACtB,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,qBAAqB,CAAC;YAChC,OAAO;YACP,OAAO,EAAE;gBACP,IAAI,EAAE,UAAU;gBAChB,EAAE,EAAE,aAAa;gBACjB,UAAU,EAAE,CAAC;gBACb,cAAc,EAAE,qBAAqB;aACtC;SACF,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,6BAA6B;QACjC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAE/C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACpE,oEAAoE;YACpE,gEAAgE;YAChE,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YAErB,wEAAwE;YACxE,4EAA4E;YAC5E,6DAA6D;YAC7D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC;gBAC9B,OAAO,UAAU,CAAC;YACpB,CAAC;YAED,GAAG,CAAC,sBAAsB,EAAE,kCAAkC,CAAC,CAAC;YAChE,MAAM,CAAC,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAClD,OAAO,UAAU,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,qBAAqB,CAAC;YAChC,OAAO;YACP,OAAO,EAAE;gBACP,IAAI,EAAE,KAAK;gBACX,EAAE,EAAE,qBAAqB;aAC1B;SACF,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;OASG;IACH,qBAAqB,CAAC,EACpB,OAAO,EACP,OAAO,GAIR;QACC,MAAM,OAAO,GAAiB;YAC5B,mFAAmF;YACnF,gBAAgB;YAChB,EAAE,EAAE,iCAAiC,CAAC,OAAO,CAAC;YAC9C,IAAI,EAAE,cAAc,CAAC,GAAG;YACxB,OAAO;YACP,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC;YACtB,OAAO,EAAE;gBACP,OAAO;gBACP,UAAU,EAAE,KAAK;aAClB;YACD,OAAO,EAAE,CAAC,GAAG,qBAAqB,CAAC;SACpC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;YAC1C,KAAK,CAAC,qBAAqB,KAAK,OAAO,CAAC,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACH,+BAA+B,CAC7B,aAA8B;QAE9B,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CACjD,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,aAAa,CAC1D,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,mBAAmB,CAAC,aAA8B;QACtD,OAAO,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC/B,kCAAkC,EAClC,KAAK,EAAE,oBAAoB,EAAE,EAAE;YAC7B,MAAM,aAAa,GAAG,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CACxD,CAAC,KAAK,EAAE,EAAE,CACR,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC;gBAC7B,KAAK,CAAC,OAAO,CAAC,aAAa,KAAK,aAAa,CAChD,CAAC;YAEF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,CAAC;YAED,GAAG,CACD,0BAA0B,aAAa,8BAA8B,CACtE,CAAC;YACF,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,aAAa,CACpD,YAAY,CAAC,KAAK,EAClB,EAAE,aAAa,EAAE,CAClB,CAAC;YACF,OAAO,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,CAAC,CACF,CAAW,CAAC;IACf,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,sBAAsB;QAC1B,OAAO,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC/B,kCAAkC,EAClC,KAAK,EAAE,oBAAoB,EAAE,EAAE;YAC7B,MAAM,WAAW,GAAG,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CACjE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CACjC,CAAC;YAEF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,CAAC;YAED,GAAG,CAAC,8CAA8C,CAAC,CAAC;YACpD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,aAAa,CACpD,YAAY,CAAC,QAAQ,CACtB,CAAC;YACF,OAAO,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,CAAC,CACF,CAAW,CAAC;IACf,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,YAAY,CAChB,EAAU,EACV,UAA4C,EAC5C,SAAmD;QAEnD,OAAO,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC/B,+BAA+B,EAC/B,EAAE,EAAE,EAAE,EACN,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YACpB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE,yBAAyB,CAAC,CAAC;YAC1D,CAAC;YACD,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC,CACF,CAAW,CAAC;IACf,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,iBAAiB,CACrB,EAAU,EACV,SAAqD;QAErD,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CACnE,SAAS,CAAC,OAAuB,CAAC,CACnC,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,oBAAoB,CACxB,EAAU,EACV,SAA4D;QAE5D,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CACtE,SAAS,CAAC,OAA8B,CAAC,CAC1C,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,wBAAwB;QACtB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACvE,MAAM,gBAAgB,GAAG,QAAQ,CAAC,IAAI,CACpC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,EAAE,CAC9C,CAAC;QACF,OAAO,gBAAgB,EAAE,QAAQ,CAAC,EAAE,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,iBAAiB;QACf,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;QACJ,CAAC;IACH,CAAC;CACF","sourcesContent":["import { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { MoneyKeyring } from '@metamask/eth-money-keyring';\nimport { MONEY_DERIVATION_PATH } from '@metamask/eth-money-keyring';\nimport { EthAccountType, EthMethod, EthScope } from '@metamask/keyring-api';\nimport type { EntropySourceId } from '@metamask/keyring-api';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerWithControllerAction,\n KeyringControllerWithKeyringAction,\n KeyringMetadata,\n} from '@metamask/keyring-controller';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport { EthKeyring } from '@metamask/keyring-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Hex } from '@metamask/utils';\n\nimport { projectLogger as log } from './logger.js';\nimport type { MoneyAccountControllerMethodActions } from './MoneyAccountController-method-action-types.js';\nimport type { MoneyAccount, MoneyAccountEntropyOptions } from './types.js';\nimport {\n isMoneyKeyring,\n isMpcMoneyKeyring,\n MPC_ENTROPY_SOURCE_ID,\n} from './utils.js';\n\nexport const controllerName = 'MoneyAccountController';\n\n/**\n * Parameters for creating a money account.\n *\n * - `{ type: 'mpc' }`: create the MFA account backed by the MPC Money keyring.\n * - `{ type?: 'mnemonic', entropySource }` (the default): create the SFA\n * account backed by the `MoneyKeyring` for the given entropy source.\n */\nexport type CreateMoneyAccountParams =\n | {\n /**\n * The kind of money account to create. Defaults to `'mnemonic'`.\n */\n type?: 'mnemonic';\n\n /**\n * The entropy source ID of the SRP backing the account.\n */\n entropySource: EntropySourceId;\n }\n | {\n /**\n * The kind of money account to create.\n */\n type: 'mpc';\n };\n\nexport type MoneyAccountControllerState = {\n moneyAccounts: {\n [id: MoneyAccount['id']]: MoneyAccount;\n };\n defaultMoneyAccountId: MoneyAccount['id'] | null;\n};\n\nconst moneyAccountControllerMetadata = {\n moneyAccounts: {\n includeInDebugSnapshot: false,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n defaultMoneyAccountId: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n} satisfies StateMetadata<MoneyAccountControllerState>;\n\nexport function getDefaultMoneyAccountControllerState(): MoneyAccountControllerState {\n return {\n moneyAccounts: {},\n defaultMoneyAccountId: null,\n };\n}\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'createMoneyAccount',\n 'getMoneyAccount',\n 'setDefaultMoneyAccount',\n 'clearState',\n 'init',\n] as const;\n\n/**\n * The signing methods supported by money accounts.\n */\nconst MONEY_ACCOUNT_METHODS = [\n EthMethod.PersonalSign,\n EthMethod.SignTypedDataV1,\n EthMethod.SignTypedDataV3,\n EthMethod.SignTypedDataV4,\n // TODO: Update this once the `keyring-api` package supports `SignEip7702Authorization` method.\n] as const;\n\nexport type MoneyAccountControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n MoneyAccountControllerState\n>;\n\nexport type MoneyAccountControllerActions =\n | MoneyAccountControllerGetStateAction\n | MoneyAccountControllerMethodActions;\n\ntype AllowedActions =\n | KeyringControllerGetStateAction\n | KeyringControllerWithControllerAction\n | KeyringControllerWithKeyringAction;\n\nexport type MoneyAccountControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n MoneyAccountControllerState\n>;\n\nexport type MoneyAccountControllerEvents =\n MoneyAccountControllerStateChangeEvent;\n\ntype AllowedEvents = never;\n\nexport type MoneyAccountControllerMessenger = Messenger<\n typeof controllerName,\n MoneyAccountControllerActions | AllowedActions,\n MoneyAccountControllerEvents | AllowedEvents\n>;\n\n/**\n * The shape of the MPC Money keyring operations used by this controller. The MPC\n * keyring is an atomic keyring: `init` is cheap if the keyring is already\n * initialized, and long-running work is dispatched without holding the\n * keyring controller mutex.\n */\ntype MpcMoneyKeyringLike = EthKeyring & {\n init: () => Promise<void>;\n};\n\n/**\n * Controller for managing money accounts.\n */\nexport class MoneyAccountController extends BaseController<\n typeof controllerName,\n MoneyAccountControllerState,\n MoneyAccountControllerMessenger\n> {\n /**\n * Constructor for the MoneyAccountController.\n *\n * @param options - The options for constructing the controller.\n * @param options.messenger - The messenger to use for inter-controller communication.\n * @param options.state - The initial state of the controller. If not provided, the default state will be used.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: MoneyAccountControllerMessenger;\n state?: Partial<MoneyAccountControllerState>;\n }) {\n super({\n messenger,\n metadata: moneyAccountControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultMoneyAccountControllerState(),\n ...state,\n },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Initializes the controller by creating a money account for the primary\n * entropy source if one does not already exist.\n */\n async init(): Promise<void> {\n this.#assertIsUnlocked();\n\n const primaryEntropySource = this.#getPrimaryEntropySource();\n if (primaryEntropySource) {\n const { id, address } = await this.createMoneyAccount({\n entropySource: primaryEntropySource,\n });\n log(\n `Money keyring (entropy:${primaryEntropySource} - primary) account is: ${address} (${id})`,\n );\n } else {\n const message =\n 'No primary HD keyring found, skipping default Money account creation!';\n\n console.warn(message);\n log(`WARNING -- ${message}`);\n }\n }\n\n /**\n * Creates a money account. If an account already exists for the given\n * source, it is returned as-is (idempotent).\n *\n * The parameters determine the backing keyring:\n * - `{ type: 'mpc' }`: the MPC Money keyring (MFA account), which is created and\n * initialized if it does not exist yet.\n * - `{ type?: 'mnemonic', entropySource }` (the default): the `MoneyKeyring`\n * for that entropy source (SFA account), which is created if it does not\n * exist yet.\n *\n * @param params - The parameters for creating the money account.\n * @returns The money account.\n */\n async createMoneyAccount(\n params: CreateMoneyAccountParams,\n ): Promise<MoneyAccount> {\n this.#assertIsUnlocked();\n\n // Idempotent: return existing account if already in state. The stored\n // entropy source ID identifies the account for both account kinds.\n const entropySourceId =\n params.type === 'mpc' ? MPC_ENTROPY_SOURCE_ID : params.entropySource;\n const existingAccount =\n this.#getMoneyAccountByEntropySource(entropySourceId);\n if (existingAccount) {\n return existingAccount;\n }\n\n const account =\n params.type === 'mpc'\n ? await this.#createMpcMoneyKeyringAccount()\n : await this.#createMoneyKeyringAccount(params.entropySource);\n\n log(\n `Money account created: ${account.address} (${account.id}) for entropy source: ${entropySourceId}`,\n );\n return account;\n }\n\n /**\n * Sets the default money account.\n *\n * @param id - The id of the money account to use as the default.\n */\n setDefaultMoneyAccount(id: MoneyAccount['id']): void {\n if (this.state.moneyAccounts[id] === undefined) {\n throw new Error(`Unknown money account: ${id}`);\n }\n\n this.update((state) => {\n state.defaultMoneyAccountId = id;\n });\n }\n\n /**\n * Gets a money account by id, by entropy source, or the default one.\n *\n * @param selector - Selector options for getting the money account.\n * @param selector.id - The account id to look up. Takes precedence over `entropySource`.\n * @param selector.entropySource - The entropy source ID to get the money account for.\n * @returns The money account, or `undefined` if none matches.\n */\n getMoneyAccount(\n selector: {\n id?: MoneyAccount['id'];\n entropySource?: EntropySourceId;\n } = {},\n ): MoneyAccount | undefined {\n if (selector.id !== undefined) {\n return this.state.moneyAccounts[selector.id];\n }\n\n if (selector.entropySource !== undefined) {\n return this.#getMoneyAccountByEntropySource(selector.entropySource);\n }\n\n const defaultMoneyAccountId = this.state.defaultMoneyAccountId ?? null;\n if (defaultMoneyAccountId === null) {\n return undefined;\n }\n\n return this.state.moneyAccounts[defaultMoneyAccountId];\n }\n\n /**\n * Resets the controller state to its default, removing all money accounts.\n *\n * Intended for use during a full app reset (e.g. when the user wipes all\n * wallet data). Does not interact with the keyring — the caller is\n * responsible for ensuring the associated keyring state is also cleared.\n */\n clearState(): void {\n this.update((state) => {\n state.moneyAccounts = {};\n state.defaultMoneyAccountId = null;\n });\n }\n\n /**\n * Creates or reuses a `MoneyKeyring` account for the given entropy source.\n *\n * @param entropySource - The entropy source ID to create the money account for.\n * @returns The money account.\n */\n async #createMoneyKeyringAccount(\n entropySource: EntropySourceId,\n ): Promise<MoneyAccount> {\n const id = await this.#ensureMoneyKeyring(entropySource);\n\n const address = await this.#withMoneyKeyring(id, async (keyring) => {\n // We're adding this logic to be defensive against the possibility of a money keyring\n // existing without any accounts, which shouldn't normally happen but we want to be\n // sure we can handle it if it does.\n // If there are no accounts, we'll add one and then get the address.\n const accounts = await keyring.getAccounts();\n if (accounts.length > 0) {\n const [moneyAddress] = accounts;\n return moneyAddress;\n }\n\n log(\n `Money keyring (id:${id}, entropy:${entropySource}) has no accounts, creating one...`,\n );\n const [moneyAddress] = await keyring.addAccounts(1);\n return moneyAddress;\n });\n\n return this.#createKeyringAccount({\n address,\n entropy: {\n type: 'mnemonic',\n id: entropySource,\n groupIndex: 0,\n derivationPath: MONEY_DERIVATION_PATH,\n },\n });\n }\n\n /**\n * Creates or reuses an account on the MPC Money keyring.\n *\n * The MPC Money keyring is an atomic keyring: its initialization is cheap when\n * already initialized, and long-running work is dispatched without holding\n * the keyring controller mutex.\n *\n * @returns The money account.\n */\n async #createMpcMoneyKeyringAccount(): Promise<MoneyAccount> {\n const id = await this.#ensureMpcMoneyKeyring();\n\n const address = await this.#withMpcMoneyKeyring(id, async (keyring) => {\n // The keyring infers the setup mode (create or import) from its own\n // state. This is a no-op if the keyring is already initialized.\n await keyring.init();\n\n // We're adding this logic to be defensive against the possibility of an\n // MPC Money keyring existing without any accounts, which shouldn't normally\n // happen but we want to be sure we can handle it if it does.\n const accounts = await keyring.getAccounts();\n if (accounts.length > 0) {\n const [mpcAddress] = accounts;\n return mpcAddress;\n }\n\n log(`MPC Money keyring (${id}) has no accounts, adding one...`);\n const [mpcAddress] = await keyring.addAccounts(1);\n return mpcAddress;\n });\n\n return this.#createKeyringAccount({\n address,\n entropy: {\n type: 'mpc',\n id: MPC_ENTROPY_SOURCE_ID,\n },\n });\n }\n\n /**\n * Builds a money account for the given address and entropy options, stores\n * it in state, and returns it. If no default account is set, the new account\n * becomes the default.\n *\n * @param params - The parameters for creating the account.\n * @param params.address - The account address.\n * @param params.entropy - The entropy options of the backing keyring.\n * @returns The money account.\n */\n #createKeyringAccount({\n address,\n entropy,\n }: {\n address: Hex;\n entropy: MoneyAccountEntropyOptions;\n }): MoneyAccount {\n const account: MoneyAccount = {\n // This is an EVM account, so let's re-use the deterministic ID generation logic of\n // EVM accounts.\n id: getUUIDFromAddressOfNormalAccount(address),\n type: EthAccountType.Eoa,\n address,\n scopes: [EthScope.Eoa],\n options: {\n entropy,\n exportable: false,\n },\n methods: [...MONEY_ACCOUNT_METHODS],\n };\n\n this.update((state) => {\n state.moneyAccounts[account.id] = account;\n state.defaultMoneyAccountId ??= account.id;\n });\n\n return account;\n }\n\n /**\n * Gets a money account by entropy source ID.\n *\n * @param entropySource - The entropy source ID.\n * @returns The matching account, if any.\n */\n #getMoneyAccountByEntropySource(\n entropySource: EntropySourceId,\n ): MoneyAccount | undefined {\n return Object.values(this.state.moneyAccounts).find(\n (account) => account.options.entropy.id === entropySource,\n );\n }\n\n /**\n * Ensures a `MoneyKeyring` exists for the given entropy source, creating one\n * atomically if it does not, and returns its keyring ID.\n *\n * The check-or-create is performed within a single\n * `KeyringController:withController` transaction, which is mutually\n * exclusive and rolls back on error.\n *\n * @param entropySource - The entropy source ID identifying the target keyring.\n * @returns The keyring ID of the existing or newly created keyring.\n */\n async #ensureMoneyKeyring(entropySource: EntropySourceId): Promise<string> {\n return (await this.messenger.call(\n 'KeyringController:withController',\n async (restrictedController) => {\n const moneyKeyrings = restrictedController.keyrings.filter(\n (entry) =>\n isMoneyKeyring(entry.keyring) &&\n entry.keyring.entropySource === entropySource,\n );\n\n if (moneyKeyrings.length > 0) {\n return moneyKeyrings[0].metadata.id;\n }\n\n log(\n `Money keyring (entropy:${entropySource}) not found, creating one...`,\n );\n const entry = await restrictedController.addNewKeyring(\n KeyringTypes.money,\n { entropySource },\n );\n return entry.metadata.id;\n },\n )) as string;\n }\n\n /**\n * Ensures the MPC Money keyring exists, creating it atomically if it does not, and\n * returns its keyring ID.\n *\n * The check-or-create is performed within a single\n * `KeyringController:withController` transaction, which is mutually\n * exclusive and rolls back on error.\n *\n * @returns The keyring ID of the existing or newly created keyring.\n */\n async #ensureMpcMoneyKeyring(): Promise<string> {\n return (await this.messenger.call(\n 'KeyringController:withController',\n async (restrictedController) => {\n const mpcKeyrings = restrictedController.keyrings.filter((entry) =>\n isMpcMoneyKeyring(entry.keyring),\n );\n\n if (mpcKeyrings.length > 1) {\n throw new Error('Multiple MPC Money keyrings found');\n }\n\n if (mpcKeyrings.length === 1) {\n return mpcKeyrings[0].metadata.id;\n }\n\n log('MPC Money keyring not found, creating one...');\n const entry = await restrictedController.addNewKeyring(\n KeyringTypes.mpcMoney,\n );\n return entry.metadata.id;\n },\n )) as string;\n }\n\n /**\n * Calls `KeyringController:withKeyring` for the keyring with the given ID.\n *\n * @param id - The keyring metadata ID.\n * @param assertType - Verifies the resolved keyring has the expected type.\n * @param operation - Callback invoked with the resolved keyring.\n * @returns The value returned by `operation`.\n */\n async #withKeyring<Result>(\n id: string,\n assertType: (keyring: EthKeyring) => boolean,\n operation: (keyring: EthKeyring) => Promise<Result>,\n ): Promise<Result> {\n return (await this.messenger.call(\n 'KeyringController:withKeyring',\n { id },\n async ({ keyring }) => {\n if (!assertType(keyring)) {\n throw new Error(`Keyring ${id} has an unexpected type`);\n }\n return operation(keyring);\n },\n )) as Result;\n }\n\n /**\n * Calls `KeyringController:withKeyring` for the `MoneyKeyring` with the\n * given ID.\n *\n * @param id - The keyring metadata ID.\n * @param operation - Callback invoked with the resolved `MoneyKeyring`.\n * @returns The value returned by `operation`.\n */\n async #withMoneyKeyring<Result>(\n id: string,\n operation: (keyring: MoneyKeyring) => Promise<Result>,\n ): Promise<Result> {\n return await this.#withKeyring(id, isMoneyKeyring, async (keyring) =>\n operation(keyring as MoneyKeyring),\n );\n }\n\n /**\n * Calls `KeyringController:withKeyring` for the MPC Money keyring with the given\n * ID.\n *\n * @param id - The keyring metadata ID.\n * @param operation - Callback invoked with the resolved MPC Money keyring.\n * @returns The value returned by `operation`.\n */\n async #withMpcMoneyKeyring<Result>(\n id: string,\n operation: (keyring: MpcMoneyKeyringLike) => Promise<Result>,\n ): Promise<Result> {\n return await this.#withKeyring(id, isMpcMoneyKeyring, async (keyring) =>\n operation(keyring as MpcMoneyKeyringLike),\n );\n }\n\n /**\n * Gets the primary entropy source ID.\n *\n * @returns The primary entropy source ID, or `undefined` if no HD keyring exists.\n */\n #getPrimaryEntropySource(): EntropySourceId | undefined {\n const { keyrings } = this.messenger.call('KeyringController:getState');\n const primaryHdKeyring = keyrings.find(\n (keyring) => keyring.type === KeyringTypes.hd,\n );\n return primaryHdKeyring?.metadata.id;\n }\n\n /**\n * Throws if the keyring is currently locked.\n */\n #assertIsUnlocked(): void {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n throw new Error(\n 'Cannot create a money account while the keyring is locked',\n );\n }\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export type { MoneyAccount } from './types.js';
2
- export { isMoneyKeyring } from './utils.js';
1
+ export type { MoneyAccount, MoneyAccountEntropyMpcOptions, MoneyAccountEntropyOptions, } from './types.js';
2
+ export { MPC_ENTROPY_SOURCE_ID, isMoneyKeyring, isMpcMoneyKeyring, } from './utils.js';
3
3
  export { MoneyAccountController, controllerName, getDefaultMoneyAccountControllerState, } from './MoneyAccountController.js';
4
- export type { MoneyAccountControllerState, MoneyAccountControllerGetStateAction, MoneyAccountControllerActions, MoneyAccountControllerStateChangeEvent, MoneyAccountControllerEvents, MoneyAccountControllerMessenger, } from './MoneyAccountController.js';
5
- export type { MoneyAccountControllerClearStateAction, MoneyAccountControllerCreateMoneyAccountAction, MoneyAccountControllerGetMoneyAccountAction, MoneyAccountControllerInitAction, } from './MoneyAccountController-method-action-types.js';
4
+ export type { MoneyAccountControllerState, MoneyAccountControllerGetStateAction, MoneyAccountControllerActions, MoneyAccountControllerStateChangeEvent, MoneyAccountControllerEvents, MoneyAccountControllerMessenger, CreateMoneyAccountParams, } from './MoneyAccountController.js';
5
+ export type { MoneyAccountControllerClearStateAction, MoneyAccountControllerCreateMoneyAccountAction, MoneyAccountControllerGetMoneyAccountAction, MoneyAccountControllerInitAction, MoneyAccountControllerSetDefaultMoneyAccountAction, } from './MoneyAccountController-method-action-types.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,qCAAqC,GACtC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,2BAA2B,EAC3B,oCAAoC,EACpC,6BAA6B,EAC7B,sCAAsC,EACtC,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,sCAAsC,EACtC,8CAA8C,EAC9C,2CAA2C,EAC3C,gCAAgC,GACjC,MAAM,iDAAiD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,qCAAqC,GACtC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,2BAA2B,EAC3B,oCAAoC,EACpC,6BAA6B,EAC7B,sCAAsC,EACtC,4BAA4B,EAC5B,+BAA+B,EAC/B,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,sCAAsC,EACtC,8CAA8C,EAC9C,2CAA2C,EAC3C,gCAAgC,EAChC,kDAAkD,GACnD,MAAM,iDAAiD,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { isMoneyKeyring } from './utils.js';
1
+ export { MPC_ENTROPY_SOURCE_ID, isMoneyKeyring, isMpcMoneyKeyring, } from './utils.js';
2
2
  export { MoneyAccountController, controllerName, getDefaultMoneyAccountControllerState, } from './MoneyAccountController.js';
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,qCAAqC,GACtC,MAAM,6BAA6B,CAAC","sourcesContent":["export type { MoneyAccount } from './types.js';\nexport { isMoneyKeyring } from './utils.js';\nexport {\n MoneyAccountController,\n controllerName,\n getDefaultMoneyAccountControllerState,\n} from './MoneyAccountController.js';\nexport type {\n MoneyAccountControllerState,\n MoneyAccountControllerGetStateAction,\n MoneyAccountControllerActions,\n MoneyAccountControllerStateChangeEvent,\n MoneyAccountControllerEvents,\n MoneyAccountControllerMessenger,\n} from './MoneyAccountController.js';\nexport type {\n MoneyAccountControllerClearStateAction,\n MoneyAccountControllerCreateMoneyAccountAction,\n MoneyAccountControllerGetMoneyAccountAction,\n MoneyAccountControllerInitAction,\n} from './MoneyAccountController-method-action-types.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,qCAAqC,GACtC,MAAM,6BAA6B,CAAC","sourcesContent":["export type {\n MoneyAccount,\n MoneyAccountEntropyMpcOptions,\n MoneyAccountEntropyOptions,\n} from './types.js';\nexport {\n MPC_ENTROPY_SOURCE_ID,\n isMoneyKeyring,\n isMpcMoneyKeyring,\n} from './utils.js';\nexport {\n MoneyAccountController,\n controllerName,\n getDefaultMoneyAccountControllerState,\n} from './MoneyAccountController.js';\nexport type {\n MoneyAccountControllerState,\n MoneyAccountControllerGetStateAction,\n MoneyAccountControllerActions,\n MoneyAccountControllerStateChangeEvent,\n MoneyAccountControllerEvents,\n MoneyAccountControllerMessenger,\n CreateMoneyAccountParams,\n} from './MoneyAccountController.js';\nexport type {\n MoneyAccountControllerClearStateAction,\n MoneyAccountControllerCreateMoneyAccountAction,\n MoneyAccountControllerGetMoneyAccountAction,\n MoneyAccountControllerInitAction,\n MoneyAccountControllerSetDefaultMoneyAccountAction,\n} from './MoneyAccountController-method-action-types.js';\n"]}
package/dist/types.d.ts CHANGED
@@ -1,8 +1,29 @@
1
- import type { KeyringAccount, KeyringAccountEntropyMnemonicOptions } from '@metamask/keyring-api';
1
+ import type { KeyringAccount, KeyringAccountEntropyMnemonicOptions, EntropySourceId } from '@metamask/keyring-api';
2
+ /**
3
+ * Entropy options for MPC-backed money accounts. The entropy source ID is a
4
+ * static identifier, as the MPC architecture currently yields a single keyring
5
+ * (and account) per wallet.
6
+ */
7
+ export type MoneyAccountEntropyMpcOptions = {
8
+ type: 'mpc';
9
+ /**
10
+ * The entropy source ID (e.g. `entropy:mpc:_`).
11
+ */
12
+ id: EntropySourceId;
13
+ };
14
+ /**
15
+ * Entropy options for money accounts.
16
+ *
17
+ * - `'mnemonic'`: the account is derived from a BIP-44 mnemonic (SRP). This is
18
+ * the SFA (single-factor authentication) account.
19
+ * - `'mpc'`: the account is backed by an MPC Money keyring. This is the MFA
20
+ * (multi-factor authentication) account.
21
+ */
22
+ export type MoneyAccountEntropyOptions = KeyringAccountEntropyMnemonicOptions | MoneyAccountEntropyMpcOptions;
2
23
  /** A money account represents an account managed by the MoneyAccountController. */
3
24
  export type MoneyAccount = Omit<KeyringAccount, 'options'> & {
4
25
  options: {
5
- entropy: KeyringAccountEntropyMnemonicOptions;
26
+ entropy: MoneyAccountEntropyOptions;
6
27
  exportable: false;
7
28
  };
8
29
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,oCAAoC,EACrC,MAAM,uBAAuB,CAAC;AAE/B,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG;IAG3D,OAAO,EAAE;QACP,OAAO,EAAE,oCAAoC,CAAC;QAC9C,UAAU,EAAE,KAAK,CAAC;KACnB,CAAC;CACH,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,oCAAoC,EACpC,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAE/B;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,IAAI,EAAE,KAAK,CAAC;IAEZ;;OAEG;IACH,EAAE,EAAE,eAAe,CAAC;CACrB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,0BAA0B,GAClC,oCAAoC,GACpC,6BAA6B,CAAC;AAElC,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG;IAG3D,OAAO,EAAE;QACP,OAAO,EAAE,0BAA0B,CAAC;QACpC,UAAU,EAAE,KAAK,CAAC;KACnB,CAAC;CACH,CAAC"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n KeyringAccount,\n KeyringAccountEntropyMnemonicOptions,\n} from '@metamask/keyring-api';\n\n/** A money account represents an account managed by the MoneyAccountController. */\nexport type MoneyAccount = Omit<KeyringAccount, 'options'> & {\n // We use stricter options for money accounts. They can be seen as BIP-44 accounts\n // and we make them non-exportable too.\n options: {\n entropy: KeyringAccountEntropyMnemonicOptions;\n exportable: false;\n };\n};\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n KeyringAccount,\n KeyringAccountEntropyMnemonicOptions,\n EntropySourceId,\n} from '@metamask/keyring-api';\n\n/**\n * Entropy options for MPC-backed money accounts. The entropy source ID is a\n * static identifier, as the MPC architecture currently yields a single keyring\n * (and account) per wallet.\n */\nexport type MoneyAccountEntropyMpcOptions = {\n type: 'mpc';\n\n /**\n * The entropy source ID (e.g. `entropy:mpc:_`).\n */\n id: EntropySourceId;\n};\n\n/**\n * Entropy options for money accounts.\n *\n * - `'mnemonic'`: the account is derived from a BIP-44 mnemonic (SRP). This is\n * the SFA (single-factor authentication) account.\n * - `'mpc'`: the account is backed by an MPC Money keyring. This is the MFA\n * (multi-factor authentication) account.\n */\nexport type MoneyAccountEntropyOptions =\n | KeyringAccountEntropyMnemonicOptions\n | MoneyAccountEntropyMpcOptions;\n\n/** A money account represents an account managed by the MoneyAccountController. */\nexport type MoneyAccount = Omit<KeyringAccount, 'options'> & {\n // We use stricter options for money accounts. They can be seen as BIP-44 accounts\n // and we make them non-exportable too.\n options: {\n entropy: MoneyAccountEntropyOptions;\n exportable: false;\n };\n};\n"]}
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  import type { MoneyKeyring } from '@metamask/eth-money-keyring';
2
2
  import { EthKeyring } from '@metamask/keyring-utils';
3
+ /**
4
+ * The static entropy source ID for MPC-backed money accounts. The MPC
5
+ * architecture currently yields a single keyring (and account) per wallet, so
6
+ * a static identifier is sufficient.
7
+ */
8
+ export declare const MPC_ENTROPY_SOURCE_ID: 'entropy:mpc:_';
3
9
  /**
4
10
  * Returns `true` if the given keyring is a {@link MoneyKeyring}.
5
11
  *
@@ -7,4 +13,11 @@ import { EthKeyring } from '@metamask/keyring-utils';
7
13
  * @returns Whether the keyring is a `MoneyKeyring`.
8
14
  */
9
15
  export declare function isMoneyKeyring(keyring: EthKeyring): keyring is MoneyKeyring;
16
+ /**
17
+ * Returns `true` if the given keyring is an MPC Money keyring.
18
+ *
19
+ * @param keyring - The keyring to check.
20
+ * @returns Whether the keyring is an MPC Money keyring.
21
+ */
22
+ export declare function isMpcMoneyKeyring(keyring: EthKeyring): boolean;
10
23
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,IAAI,YAAY,CAE3E"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAG,eAAwB,CAAC;AAE9D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,IAAI,YAAY,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAE9D"}
package/dist/utils.js CHANGED
@@ -1,4 +1,10 @@
1
1
  import { KeyringTypes } from '@metamask/keyring-controller';
2
+ /**
3
+ * The static entropy source ID for MPC-backed money accounts. The MPC
4
+ * architecture currently yields a single keyring (and account) per wallet, so
5
+ * a static identifier is sufficient.
6
+ */
7
+ export const MPC_ENTROPY_SOURCE_ID = 'entropy:mpc:_';
2
8
  /**
3
9
  * Returns `true` if the given keyring is a {@link MoneyKeyring}.
4
10
  *
@@ -8,4 +14,13 @@ import { KeyringTypes } from '@metamask/keyring-controller';
8
14
  export function isMoneyKeyring(keyring) {
9
15
  return keyring.type === KeyringTypes.money;
10
16
  }
17
+ /**
18
+ * Returns `true` if the given keyring is an MPC Money keyring.
19
+ *
20
+ * @param keyring - The keyring to check.
21
+ * @returns Whether the keyring is an MPC Money keyring.
22
+ */
23
+ export function isMpcMoneyKeyring(keyring) {
24
+ return keyring.type === KeyringTypes.mpcMoney;
25
+ }
11
26
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAG5D;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAmB;IAChD,OAAO,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,KAAK,CAAC;AAC7C,CAAC","sourcesContent":["import type { MoneyKeyring } from '@metamask/eth-money-keyring';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport { EthKeyring } from '@metamask/keyring-utils';\n\n/**\n * Returns `true` if the given keyring is a {@link MoneyKeyring}.\n *\n * @param keyring - The keyring to check.\n * @returns Whether the keyring is a `MoneyKeyring`.\n */\nexport function isMoneyKeyring(keyring: EthKeyring): keyring is MoneyKeyring {\n return keyring.type === KeyringTypes.money;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAG5D;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAwB,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAmB;IAChD,OAAO,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,KAAK,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAmB;IACnD,OAAO,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,QAAQ,CAAC;AAChD,CAAC","sourcesContent":["import type { MoneyKeyring } from '@metamask/eth-money-keyring';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport { EthKeyring } from '@metamask/keyring-utils';\n\n/**\n * The static entropy source ID for MPC-backed money accounts. The MPC\n * architecture currently yields a single keyring (and account) per wallet, so\n * a static identifier is sufficient.\n */\nexport const MPC_ENTROPY_SOURCE_ID = 'entropy:mpc:_' as const;\n\n/**\n * Returns `true` if the given keyring is a {@link MoneyKeyring}.\n *\n * @param keyring - The keyring to check.\n * @returns Whether the keyring is a `MoneyKeyring`.\n */\nexport function isMoneyKeyring(keyring: EthKeyring): keyring is MoneyKeyring {\n return keyring.type === KeyringTypes.money;\n}\n\n/**\n * Returns `true` if the given keyring is an MPC Money keyring.\n *\n * @param keyring - The keyring to check.\n * @returns Whether the keyring is an MPC Money keyring.\n */\nexport function isMpcMoneyKeyring(keyring: EthKeyring): boolean {\n return keyring.type === KeyringTypes.mpcMoney;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/money-account-controller",
3
- "version": "2.0.0-preview-7ef511c85",
3
+ "version": "2.0.0-preview-5d0e7527f",
4
4
  "description": "MetaMask Money account controller",
5
5
  "keywords": [
6
6
  "Ethereum",
@@ -51,12 +51,11 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@metamask/accounts-controller": "^40.1.0",
54
- "@metamask/base-controller": "^10.0.0",
54
+ "@metamask/base-controller": "^10.1.0",
55
55
  "@metamask/eth-money-keyring": "^4.0.0",
56
56
  "@metamask/keyring-api": "^24.3.0",
57
57
  "@metamask/keyring-controller": "^28.2.0",
58
- "@metamask/messenger": "^3.0.0",
59
- "async-mutex": "^0.5.0"
58
+ "@metamask/messenger": "^3.0.0"
60
59
  },
61
60
  "devDependencies": {
62
61
  "@metamask/auto-changelog": "^6.2.1",