Skip to content

feat(wallet): add TransactionController to wallet package - #8975

Merged
matthewwalsh0 merged 5 commits into
mainfrom
feat/wallet-wire-transaction-controller
Jul 6, 2026
Merged

feat(wallet): add TransactionController to wallet package#8975
matthewwalsh0 merged 5 commits into
mainfrom
feat/wallet-wire-transaction-controller

Conversation

@matthewwalsh0

@matthewwalsh0 matthewwalsh0 commented Jun 2, 2026

Copy link
Copy Markdown
Member

Explanation

Adds TransactionController to the @metamask/wallet package. Wallet initializes the controller during setup; consumers pass platform-specific options via instanceOptions.transactionController.

References

MetaMask/metamask-extension#43182

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
Expands the default wallet controller graph into transaction submission/signing paths via delegated Keyring and Approval actions; breaking for consumers that assumed TransactionController was not part of default init.

Overview
BREAKING: Default @metamask/wallet setup now boots TransactionController alongside the other core controllers, so consumers get transaction state and messenger actions without wiring it themselves.

A new initialization module constructs the controller from optional instanceOptions.transactionController (including a default disableSwaps: false), restores persisted state, and delegates parent messenger access for signing, approvals, accounts, network clients, gas estimates, and feature flags. Wallet integration tests assert TransactionController:getState is available on the root messenger.

Also adds the @metamask/transaction-controller dependency, TypeScript project references, CODEOWNERS for the new init path, changelog entry, and focused unit tests for registration, default state, and state hydration.

Reviewed by Cursor Bugbot for commit 2e54b30. Bugbot is set up for automated code reviews on this repo. Configure here.

@matthewwalsh0
matthewwalsh0 force-pushed the feat/wallet-wire-transaction-controller branch 4 times, most recently from c3042bb to 9677e31 Compare June 2, 2026 21:23
@matthewwalsh0
matthewwalsh0 force-pushed the feat/wallet-wire-transaction-controller branch from 58d79cc to 0069b11 Compare June 3, 2026 09:02
@matthewwalsh0
matthewwalsh0 force-pushed the feat/wallet-wire-transaction-controller branch from 4bf9b25 to 2aac690 Compare June 3, 2026 12:36
@matthewwalsh0
matthewwalsh0 changed the base branch from main to chore/remove-deprecated-tx-options June 3, 2026 12:36
@matthewwalsh0
matthewwalsh0 force-pushed the chore/remove-deprecated-tx-options branch from de6504d to bfc8a1a Compare June 4, 2026 16:24
Base automatically changed from chore/remove-deprecated-tx-options to main June 5, 2026 08:33
@matthewwalsh0
matthewwalsh0 force-pushed the feat/wallet-wire-transaction-controller branch 5 times, most recently from 26ad858 to 5c48b39 Compare June 16, 2026 20:45
@matthewwalsh0
matthewwalsh0 marked this pull request as ready for review June 16, 2026 20:58
@matthewwalsh0
matthewwalsh0 requested a review from a team as a code owner June 16, 2026 20:58
@matthewwalsh0
matthewwalsh0 force-pushed the feat/wallet-wire-transaction-controller branch 2 times, most recently from 3711bf1 to 3149fd2 Compare July 1, 2026 10:27
@matthewwalsh0
matthewwalsh0 force-pushed the feat/wallet-wire-transaction-controller branch 3 times, most recently from 3d4c0ed to c97a549 Compare July 1, 2026 11:37
@matthewwalsh0

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@matthewwalsh0 matthewwalsh0 changed the title feat(wallet): wire TransactionController into default initialization feat(wallet): add TransactionController to wallet package Jul 3, 2026
@matthewwalsh0
matthewwalsh0 force-pushed the feat/wallet-wire-transaction-controller branch from c97a549 to fb9db90 Compare July 3, 2026 14:56
@socket-security

socket-security Bot commented Jul 3, 2026

Copy link
Copy Markdown

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

Comment thread packages/wallet/src/initialization/instances/transaction-controller/types.ts Outdated
Comment thread packages/wallet/src/Wallet.test.ts Outdated
Comment thread packages/wallet/src/Wallet.test.ts
@matthewwalsh0
matthewwalsh0 added this pull request to the merge queue Jul 6, 2026
Merged via the queue into main with commit 7481e42 Jul 6, 2026
413 checks passed
@matthewwalsh0
matthewwalsh0 deleted the feat/wallet-wire-transaction-controller branch July 6, 2026 10:23
@matthewwalsh0

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

pull Bot pushed a commit to Reality2byte/metamask-extension that referenced this pull request Jul 9, 2026
…k#43182)

## **Description**

TransactionController is now initialized through `@metamask/wallet`.

To support this:

- Extension-specific setup (options, event listeners, background API
bindings) moved into `app/scripts/wallet-init`.
- A new `InitializeWalletRequest` type passes extension dependencies
into wallet initialization.
- TransactionController removed from the old `messenger-client-init`
path.

Background and UI behaviour is unchanged — the same state keys and API
surface are preserved.

Note: Some `InitializeWalletRequest` properties are broader than needed
for TransactionController specifically, so unnecessary properties will
be removed in future.

Depends on MetaMask/core#8975.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

1. `yarn install`
2. `yarn lint:tsc`
3. Build and load the extension; confirm transactions work end-to-end.

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Moves core transaction controller startup and background API wiring to
the wallet package; regressions could break signing, publishing, state
persistence, or UI transaction flows despite preserved store keys.
> 
> **Overview**
> **TransactionController** is no longer created through
`messenger-client-init`; it is owned by `@metamask/wallet` (`^7.0.0`)
with extension-specific wiring under `app/scripts/wallet-init`.
> 
> `initializeWallet` now takes an `InitializeWalletRequest` (including
`getFlatState`, `getPermittedAccounts`, and
`getTransactionMetricsRequest`) and passes `transactionController`
instance options built from `getTransactionControllerInstanceOptions`,
plus `setupTransactionControllerListeners` for metrics subscriptions.
Background API methods are exposed via
`getTransactionControllerApi(this.txController)` merged into the
extension API. `MetaMaskController` resolves the controller with
`wallet.getInstance('TransactionController')` and keeps the same
persisted/mem store keys (`TransactionController` / `TxController`).
> 
> The init messenger module moves to `wallet-init/messengers`
(controller messenger factory removed; init messenger types exported).
Transaction hooks and containers update imports to that path.
`TransactionController` is dropped from `MESSENGER_FACTORIES` and
related init typing; Lavamoat policies allow
`@metamask/transaction-controller` from `@metamask/wallet`. Tests shift
from the old init test file to `wallet-init` coverage.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
20571a5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
pull Bot pushed a commit to Reality2byte/core that referenced this pull request Jul 14, 2026
…allet (MetaMask#9509)

## Explanation

`TransactionController` was wired into `@metamask/wallet` in MetaMask#8975,
which left the daemon's wallet factory with a stubbed slot: `//
TODO(MetaMask#8975): add the transactionController slot once it is wired`. Until
now the daemon still *constructed* the controller (it runs during
`wallet.init()`), but only with the controller's implicit defaults,
because `buildInstanceOptions` passed no `transactionController`
options.

This PR populates that slot so the daemon's transaction configuration is
explicit and reviewable alongside the other wired slots.

## What changed

`buildInstanceOptions` now sets:

```ts
transactionController: {
  disableSwaps: true,
  hooks: {},
},
```

- **`disableSwaps: true`** — the headless CLI has no swaps feature, so
the swaps-specific post-processing a full wallet client runs would only
produce data nothing reads. This mirrors mobile's choice; the extension
keeps swaps enabled because it ships the full Swaps UI.
- **`hooks: {}`** — no CLI-specific transaction hooks. The controller's
built-in publish path already broadcasts through the wired
`NetworkController` provider (the default `publish` hook returns an
undefined hash, and the controller then falls back to its own
network-client broadcast), and the remaining hooks (metrics,
notifications, gas-fee tokens) are client-UI concerns the daemon has no
equivalent for.
- Every other option (`getPermittedAccounts`, `isSimulationEnabled`,
`trace`, …) is left at the controller's default.

This is a configuration change only — no new command surface. Mutating
RPC (sign/send) hardening remains future work (see the retry-idempotency
note in the wallet-cli plan).

### Client references for the `disableSwaps` posture

- Extension (`disableSwaps: false`):
[`app/scripts/wallet-init/instance-options/transaction-controller.ts`](https://github.com/MetaMask/metamask-extension/blob/main/app/scripts/wallet-init/instance-options/transaction-controller.ts)
- Mobile (`disableSwaps: true`):
[`app/core/Engine/wallet-init/instance-options/transaction-controller.ts`](https://github.com/MetaMask/metamask-mobile/blob/main/app/core/Engine/wallet-init/instance-options/transaction-controller.ts)

## References

- Wires the consumer side of MetaMask#8975.

## Testing

- Unit (`wallet-factory.test.ts`): asserts the wired slot values.
- Integration (`wallet-factory.integration.test.ts`): the real `Wallet`
path constructs and runs with the new options.
- Gates: full test suite at 100% coverage, dep-subtree build/type-check,
ESLint, oxfmt, changelog validation — all green.

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, `CHANGELOG.md`) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for affected
packages](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs),
highlighting breaking changes as necessary
- [x] I've prepared draft pull requests for clients and consumer
packages to resolve any breaking changes (n/a — no breaking changes)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Small, explicit daemon configuration change with no new RPC surface;
swaps processing is disabled in a headless host where it was previously
left at wallet defaults (swaps on).
> 
> **Overview**
> The daemon’s `buildInstanceOptions` **replaces the
`transactionController` TODO** with an explicit slot configuration so
headless CLI behavior is documented alongside the other wired
controllers.
> 
> **`disableSwaps: true`** turns off swaps-specific transaction
post-processing the CLI has no surface for (aligned with mobile;
extension keeps swaps on). **`hooks: {}`** declares no client-specific
transaction hooks—publish still uses the controller’s default path
through `NetworkController`; metrics/notifications-style hooks are
omitted for the headless daemon. Other `TransactionController` options
stay at controller defaults.
> 
> `wallet-factory.test.ts` asserts these values on the real wallet
construction call, and `CHANGELOG.md` records the addition.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
0f8d304. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants