Skip to content

feat: add money-account-controller#8361

Merged
ccharly merged 30 commits intomainfrom
cc/feat/money-account-controller
Apr 2, 2026
Merged

feat: add money-account-controller#8361
ccharly merged 30 commits intomainfrom
cc/feat/money-account-controller

Conversation

@ccharly
Copy link
Copy Markdown
Contributor

@ccharly ccharly commented Apr 1, 2026

Explanation

Initial implementation of the MoneyAccountController.

References

N/A

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Introduces new controller logic that creates and manages a new MoneyKeyring via KeyringController, including concurrency locking and state persistence; bugs here could affect keyring creation behavior and account derivation for Money accounts.

Overview
Adds a new package, @metamask/money-account-controller, implementing MoneyAccountController to create and track one Money account per entropy source (defaulting to the primary HD keyring) and expose createMoneyAccount, getMoneyAccount, and clearState via the messenger.

The controller integrates with KeyringController to find or create a MoneyKeyring, defensively ensures an address exists, and uses a mutex to prevent duplicate keyring creation under concurrent calls; comprehensive Jest tests and package build/docs configs are included.

Repo wiring is updated to include the new package in README.md, root tsconfig references, CODEOWNERS, teams.json, and yarn.lock (including adding @metamask/eth-money-keyring and bumping @metamask/eth-hd-keyring resolution).

Written by Cursor Bugbot for commit 1beb776. This will update automatically on new commits. Configure here.

@ccharly ccharly force-pushed the cc/feat/money-account-controller branch 2 times, most recently from e754aaa to 373edc9 Compare April 1, 2026 17:23
@ccharly
Copy link
Copy Markdown
Contributor Author

ccharly commented Apr 1, 2026

@metamaskbot publish-preview

@socket-security
Copy link
Copy Markdown

socket-security bot commented Apr 1, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​metamask/​eth-money-keyring@​2.0.0731008191100
Updated@​metamask/​eth-hd-keyring@​13.0.0 ⏵ 13.1.09910010090 +4100

View full report

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.0.0-preview-373edc9
@metamask-previews/accounts-controller@37.2.0-preview-373edc9
@metamask-previews/address-book-controller@7.1.1-preview-373edc9
@metamask-previews/ai-controllers@0.6.3-preview-373edc9
@metamask-previews/analytics-controller@1.0.1-preview-373edc9
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-373edc9
@metamask-previews/announcement-controller@8.1.0-preview-373edc9
@metamask-previews/app-metadata-controller@2.0.1-preview-373edc9
@metamask-previews/approval-controller@9.0.1-preview-373edc9
@metamask-previews/assets-controller@4.0.0-preview-373edc9
@metamask-previews/assets-controllers@103.1.1-preview-373edc9
@metamask-previews/base-controller@9.0.1-preview-373edc9
@metamask-previews/base-data-service@0.1.1-preview-373edc9
@metamask-previews/bridge-controller@70.0.1-preview-373edc9
@metamask-previews/bridge-status-controller@70.0.5-preview-373edc9
@metamask-previews/build-utils@3.0.4-preview-373edc9
@metamask-previews/chain-agnostic-permission@1.5.0-preview-373edc9
@metamask-previews/claims-controller@0.5.0-preview-373edc9
@metamask-previews/client-controller@1.0.1-preview-373edc9
@metamask-previews/compliance-controller@1.0.2-preview-373edc9
@metamask-previews/composable-controller@12.0.1-preview-373edc9
@metamask-previews/config-registry-controller@0.2.0-preview-373edc9
@metamask-previews/connectivity-controller@0.2.0-preview-373edc9
@metamask-previews/controller-utils@11.20.0-preview-373edc9
@metamask-previews/core-backend@6.2.1-preview-373edc9
@metamask-previews/delegation-controller@2.1.0-preview-373edc9
@metamask-previews/earn-controller@11.2.1-preview-373edc9
@metamask-previews/eip-5792-middleware@3.0.3-preview-373edc9
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.0-preview-373edc9
@metamask-previews/eip1193-permission-middleware@1.0.3-preview-373edc9
@metamask-previews/ens-controller@19.1.1-preview-373edc9
@metamask-previews/eth-block-tracker@15.0.1-preview-373edc9
@metamask-previews/eth-json-rpc-middleware@23.1.1-preview-373edc9
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-373edc9
@metamask-previews/foundryup@1.0.1-preview-373edc9
@metamask-previews/gas-fee-controller@26.1.1-preview-373edc9
@metamask-previews/gator-permissions-controller@3.0.1-preview-373edc9
@metamask-previews/geolocation-controller@0.1.2-preview-373edc9
@metamask-previews/json-rpc-engine@10.2.4-preview-373edc9
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-373edc9
@metamask-previews/keyring-controller@25.2.0-preview-373edc9
@metamask-previews/logging-controller@8.0.1-preview-373edc9
@metamask-previews/message-manager@14.1.1-preview-373edc9
@metamask-previews/messenger@1.0.0-preview-373edc9
@metamask-previews/money-account-controller@0.0.0-preview-373edc9
@metamask-previews/multichain-account-service@8.0.1-preview-373edc9
@metamask-previews/multichain-api-middleware@2.0.0-preview-373edc9
@metamask-previews/multichain-network-controller@3.0.6-preview-373edc9
@metamask-previews/multichain-transactions-controller@7.0.4-preview-373edc9
@metamask-previews/name-controller@9.1.1-preview-373edc9
@metamask-previews/network-controller@30.0.1-preview-373edc9
@metamask-previews/network-enablement-controller@5.0.2-preview-373edc9
@metamask-previews/notification-services-controller@23.0.1-preview-373edc9
@metamask-previews/permission-controller@12.3.0-preview-373edc9
@metamask-previews/permission-log-controller@5.1.0-preview-373edc9
@metamask-previews/perps-controller@2.0.0-preview-373edc9
@metamask-previews/phishing-controller@17.1.1-preview-373edc9
@metamask-previews/polling-controller@16.0.4-preview-373edc9
@metamask-previews/preferences-controller@23.1.0-preview-373edc9
@metamask-previews/profile-metrics-controller@3.1.3-preview-373edc9
@metamask-previews/profile-sync-controller@28.0.2-preview-373edc9
@metamask-previews/ramps-controller@12.1.0-preview-373edc9
@metamask-previews/rate-limit-controller@7.0.1-preview-373edc9
@metamask-previews/react-data-query@0.2.0-preview-373edc9
@metamask-previews/remote-feature-flag-controller@4.2.0-preview-373edc9
@metamask-previews/sample-controllers@4.0.4-preview-373edc9
@metamask-previews/seedless-onboarding-controller@9.1.0-preview-373edc9
@metamask-previews/selected-network-controller@26.1.0-preview-373edc9
@metamask-previews/shield-controller@5.1.1-preview-373edc9
@metamask-previews/signature-controller@39.1.2-preview-373edc9
@metamask-previews/social-controllers@0.0.0-preview-373edc9
@metamask-previews/storage-service@1.0.1-preview-373edc9
@metamask-previews/subscription-controller@6.1.2-preview-373edc9
@metamask-previews/transaction-controller@64.0.0-preview-373edc9
@metamask-previews/transaction-pay-controller@19.0.2-preview-373edc9
@metamask-previews/user-operation-controller@41.2.0-preview-373edc9

@ccharly ccharly force-pushed the cc/feat/money-account-controller branch 2 times, most recently from a2a81b2 to 4615569 Compare April 1, 2026 20:44
@ccharly ccharly force-pushed the cc/feat/money-account-controller branch from 4615569 to 9eb6b60 Compare April 1, 2026 21:04
languageName: node
linkType: hard

"@metamask/keyring-api@npm:^22.0.0":
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll align this package later.

@ccharly ccharly marked this pull request as ready for review April 1, 2026 21:53
@ccharly ccharly requested a review from a team as a code owner April 1, 2026 21:53
KeyringTypes.money,
{
entropySource,
} as MoneyKeyringSerializedState,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a type-constraint here so we know the data payload is well-shaped.

Comment on lines +36 to +40
export type MoneyAccountControllerState = {
moneyAccounts: {
[id: MoneyAccount['id']]: MoneyAccount;
};
};
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed a similar pattern than the internalAccounts.accounts mapping. We still have a unique ID for those accounts and having a mapping would allow us to have more than 1 MoneyAccount if we decide too (makes it also easier to combine "normal accounts" + "money accounts" IMO)

@ccharly
Copy link
Copy Markdown
Contributor Author

ccharly commented Apr 2, 2026

@metamaskbot publish-preview

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 2, 2026

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.0.0-preview-897b6844b
@metamask-previews/accounts-controller@37.2.0-preview-897b6844b
@metamask-previews/address-book-controller@7.1.1-preview-897b6844b
@metamask-previews/ai-controllers@0.6.3-preview-897b6844b
@metamask-previews/analytics-controller@1.0.1-preview-897b6844b
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-897b6844b
@metamask-previews/announcement-controller@8.1.0-preview-897b6844b
@metamask-previews/app-metadata-controller@2.0.1-preview-897b6844b
@metamask-previews/approval-controller@9.0.1-preview-897b6844b
@metamask-previews/assets-controller@4.0.0-preview-897b6844b
@metamask-previews/assets-controllers@103.1.1-preview-897b6844b
@metamask-previews/base-controller@9.0.1-preview-897b6844b
@metamask-previews/base-data-service@0.1.1-preview-897b6844b
@metamask-previews/bridge-controller@70.0.1-preview-897b6844b
@metamask-previews/bridge-status-controller@70.0.5-preview-897b6844b
@metamask-previews/build-utils@3.0.4-preview-897b6844b
@metamask-previews/chain-agnostic-permission@1.5.0-preview-897b6844b
@metamask-previews/claims-controller@0.5.0-preview-897b6844b
@metamask-previews/client-controller@1.0.1-preview-897b6844b
@metamask-previews/compliance-controller@1.0.2-preview-897b6844b
@metamask-previews/composable-controller@12.0.1-preview-897b6844b
@metamask-previews/config-registry-controller@0.2.0-preview-897b6844b
@metamask-previews/connectivity-controller@0.2.0-preview-897b6844b
@metamask-previews/controller-utils@11.20.0-preview-897b6844b
@metamask-previews/core-backend@6.2.1-preview-897b6844b
@metamask-previews/delegation-controller@2.1.0-preview-897b6844b
@metamask-previews/earn-controller@11.2.1-preview-897b6844b
@metamask-previews/eip-5792-middleware@3.0.3-preview-897b6844b
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.0-preview-897b6844b
@metamask-previews/eip1193-permission-middleware@1.0.3-preview-897b6844b
@metamask-previews/ens-controller@19.1.1-preview-897b6844b
@metamask-previews/eth-block-tracker@15.0.1-preview-897b6844b
@metamask-previews/eth-json-rpc-middleware@23.1.1-preview-897b6844b
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-897b6844b
@metamask-previews/foundryup@1.0.1-preview-897b6844b
@metamask-previews/gas-fee-controller@26.1.1-preview-897b6844b
@metamask-previews/gator-permissions-controller@3.0.1-preview-897b6844b
@metamask-previews/geolocation-controller@0.1.2-preview-897b6844b
@metamask-previews/json-rpc-engine@10.2.4-preview-897b6844b
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-897b6844b
@metamask-previews/keyring-controller@25.2.0-preview-897b6844b
@metamask-previews/logging-controller@8.0.1-preview-897b6844b
@metamask-previews/message-manager@14.1.1-preview-897b6844b
@metamask-previews/messenger@1.1.0-preview-897b6844b
@metamask-previews/money-account-controller@0.0.0-preview-897b6844b
@metamask-previews/multichain-account-service@8.0.1-preview-897b6844b
@metamask-previews/multichain-api-middleware@2.0.0-preview-897b6844b
@metamask-previews/multichain-network-controller@3.0.6-preview-897b6844b
@metamask-previews/multichain-transactions-controller@7.0.4-preview-897b6844b
@metamask-previews/name-controller@9.1.1-preview-897b6844b
@metamask-previews/network-controller@30.0.1-preview-897b6844b
@metamask-previews/network-enablement-controller@5.0.2-preview-897b6844b
@metamask-previews/notification-services-controller@23.0.1-preview-897b6844b
@metamask-previews/permission-controller@12.3.0-preview-897b6844b
@metamask-previews/permission-log-controller@5.1.0-preview-897b6844b
@metamask-previews/perps-controller@2.0.0-preview-897b6844b
@metamask-previews/phishing-controller@17.1.1-preview-897b6844b
@metamask-previews/polling-controller@16.0.4-preview-897b6844b
@metamask-previews/preferences-controller@23.1.0-preview-897b6844b
@metamask-previews/profile-metrics-controller@3.1.3-preview-897b6844b
@metamask-previews/profile-sync-controller@28.0.2-preview-897b6844b
@metamask-previews/ramps-controller@12.1.0-preview-897b6844b
@metamask-previews/rate-limit-controller@7.0.1-preview-897b6844b
@metamask-previews/react-data-query@0.2.0-preview-897b6844b
@metamask-previews/remote-feature-flag-controller@4.2.0-preview-897b6844b
@metamask-previews/sample-controllers@4.0.4-preview-897b6844b
@metamask-previews/seedless-onboarding-controller@9.1.0-preview-897b6844b
@metamask-previews/selected-network-controller@26.1.0-preview-897b6844b
@metamask-previews/shield-controller@5.1.1-preview-897b6844b
@metamask-previews/signature-controller@39.1.2-preview-897b6844b
@metamask-previews/social-controllers@0.0.0-preview-897b6844b
@metamask-previews/storage-service@1.0.1-preview-897b6844b
@metamask-previews/subscription-controller@6.1.2-preview-897b6844b
@metamask-previews/transaction-controller@64.0.0-preview-897b6844b
@metamask-previews/transaction-pay-controller@19.0.2-preview-897b6844b
@metamask-previews/user-operation-controller@41.2.0-preview-897b6844b

// Try to find an existing `MoneyKeyring` for this entropy source and get its address.
// If no such keyring exists, create one and add an account to get the address.
let address: Hex;
try {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal opinion, but instead of doing a try/catch, I think it would be more natural to do a #getOrCreateKeyring then #getOrCreateAccount.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, as discussed, here's the new pattern:

05d4d8e

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

persist: true,
usedInUi: true,
},
} satisfies StateMetadata<MoneyAccountControllerState>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State persistence contradicts agreed-upon PR discussion

Medium Severity

The moneyAccounts metadata has persist: true, but the PR discussion between reviewers concluded that the state should not be persisted and instead be recreated inside init(). @ccharly said "We could start with un-persisted state for now" and @danroc confirmed "Indeed, it's probably better to recreate the state inside init instead of persisting it." With persist: true, stale money account data could survive across sessions even if the underlying keyring state has changed, and clearing/resetting becomes more fragile.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, for now, we'll keep things simple. Our init and clearState are hooked in our app lifecycle, which means we should never be able to end up with stale Money accounts.

Also, our primary focus is to have a Money account for our primary HD keyring for now (hence the init implementation here).

We can think of adding a resync to re-synchronize the Money account states with what we have in the associated keyrings. But that will come later.

@ccharly ccharly enabled auto-merge April 2, 2026 10:17
@ccharly ccharly added this pull request to the merge queue Apr 2, 2026
Merged via the queue into main with commit 2932f9b Apr 2, 2026
336 checks passed
@ccharly ccharly deleted the cc/feat/money-account-controller branch April 2, 2026 11:10
micaelae pushed a commit that referenced this pull request Apr 7, 2026
## Explanation

Initial implementation of the `MoneyAccountController`.

## References

N/A

## Checklist

- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [ ] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Introduces new controller logic that creates and manages a new
`MoneyKeyring` via `KeyringController`, including concurrency locking
and state persistence; bugs here could affect keyring creation behavior
and account derivation for Money accounts.
> 
> **Overview**
> Adds a new package, `@metamask/money-account-controller`, implementing
`MoneyAccountController` to create and track **one Money account per
entropy source** (defaulting to the primary HD keyring) and expose
`createMoneyAccount`, `getMoneyAccount`, and `clearState` via the
messenger.
> 
> The controller integrates with `KeyringController` to find or create a
`MoneyKeyring`, defensively ensures an address exists, and uses a mutex
to prevent duplicate keyring creation under concurrent calls;
comprehensive Jest tests and package build/docs configs are included.
> 
> Repo wiring is updated to include the new package in `README.md`, root
`tsconfig` references, `CODEOWNERS`, `teams.json`, and `yarn.lock`
(including adding `@metamask/eth-money-keyring` and bumping
`@metamask/eth-hd-keyring` resolution).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1beb776. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants