Commit 9a12df4
authored
chore: decouple controllers from tokens list (MetaMask#8700)
## Explanation
This PR decouples the `TokenDetectionController` and `TokensController`
from the `TokenListController` by introducing a new shared
`TokenListService`. This architectural improvement provides:
- **Reduced coupling**: Controllers no longer depend on
`TokenListController` state/messaging
- **Enhanced caching**: Token lists are cached in-memory per chain for 4
hours using TanStack Query
- **Better performance**: Optimized token list fetching with proper
caching and deduplication
- **Simplified data flow**: Token enrichment moves from reactive events
to one-time initialization
### Key Changes
#### New `TokenListService`
- Introduces a TanStack Query-backed service for fetching and caching
token lists
- Provides 4-hour in-memory caching per chain ID
- Exports `TokenListService` class and `buildTokenListMap` utility
function
- Adds `@tanstack/query-core` as a new dependency
#### Breaking Changes to Controllers
- **`TokenDetectionController`**: Now requires `tokenListService` in
constructor options
- **`TokensController`**: Now requires `tokenListService` in constructor
options
- Both controllers are decoupled from `TokenListController` messaging
system
- `TokenDetectionController` no longer automatically restarts detection
on `TokenListController:stateChange`
#### Token Detection Improvements
- Token list metadata fetched per detection pass with address
normalization
- Enhanced error handling with failure-safe early returns
- Improved mUSD deduplication and websocket/polling guards
#### Token Enrichment Changes
- `TokensController` switches from reactive events to one-time async
enrichment at initialization
- Multi-chain enrichment using `Promise.allSettled` for resilience
- Token `name` and `rwaData` enriched once during initialization vs. on
every state change
### Testing Updates
- Updated tests for new architecture
- Added comprehensive `TokenListService` unit tests
- Enhanced token detection test coverage
**Note**: This introduces breaking changes requiring constructor updates
for both controllers. Consumers will need to provide the new
`tokenListService` dependency.
<!--
Thanks for your contribution! Take a moment to answer these questions so
that reviewers have the information they need to properly understand
your changes:
* What is the current state of things and why does it need to change?
* What is the solution your changes offer and how does it work?
* Are there any changes whose purpose might not obvious to those
unfamiliar with the domain?
* If your primary goal was to update one package but you found you had
to update another one along the way, why did you do so?
* If you had to upgrade a dependency, why did you do so?
-->
## References
Mobile: MetaMask/metamask-mobile#29743
<!--
Are there any issues that this pull request is tied to?
Are there other links that reviewers should consult to understand these
changes better?
Are there client or consumer pull requests to adopt any breaking
changes?
For example:
* Fixes #12345
* Related to #67890
-->
## 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 a new shared caching layer and changes
`TokenDetectionController`/`TokensController` construction and runtime
behavior, which can impact token discovery/enrichment if consumers don’t
wire `tokenListService` correctly or if cache/normalization assumptions
differ across chains.
>
> **Overview**
> Adds a new `TokenListService` (TanStack Query-backed) to fetch + cache
per-chain token lists in-memory for 4 hours, exporting both
`TokenListService` and `buildTokenListMap`, and adds
`@tanstack/query-core` as a direct dependency.
>
> **BREAKING:** `TokenDetectionController` and `TokensController` now
require a `tokenListService` constructor option and no longer depend on
`TokenListController` actions/events; token detection now pulls fresh
token-list snapshots per chain from the service (with lowercase-key
normalization and graceful early-return on fetch failures) and no longer
restarts on `TokenListController:stateChange`.
>
> Changes token metadata enrichment in `TokensController` from reactive
updates on token-list state changes to a one-time async initialization
pass (multi-chain, `Promise.allSettled`) that fills `name`/`rwaData`,
and updates tests/changelog accordingly (including new
`TokenListService` unit tests and expanded mUSD/detection guard
coverage).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c67b9ef. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent 526896d commit 9a12df4
12 files changed
Lines changed: 1016 additions & 896 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
423 | 423 | | |
424 | 424 | | |
425 | 425 | | |
426 | | - | |
| 426 | + | |
427 | 427 | | |
428 | 428 | | |
429 | 429 | | |
430 | 430 | | |
431 | | - | |
| 431 | + | |
432 | 432 | | |
433 | 433 | | |
434 | 434 | | |
| |||
475 | 475 | | |
476 | 476 | | |
477 | 477 | | |
478 | | - | |
| 478 | + | |
479 | 479 | | |
480 | 480 | | |
481 | 481 | | |
| |||
486 | 486 | | |
487 | 487 | | |
488 | 488 | | |
489 | | - | |
| 489 | + | |
490 | 490 | | |
491 | 491 | | |
492 | 492 | | |
| |||
498 | 498 | | |
499 | 499 | | |
500 | 500 | | |
501 | | - | |
| 501 | + | |
502 | 502 | | |
503 | 503 | | |
504 | 504 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
12 | 17 | | |
13 | 18 | | |
14 | 19 | | |
| |||
22 | 27 | | |
23 | 28 | | |
24 | 29 | | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
25 | 36 | | |
26 | 37 | | |
27 | 38 | | |
| |||
34 | 45 | | |
35 | 46 | | |
36 | 47 | | |
| 48 | + | |
| 49 | + | |
37 | 50 | | |
38 | 51 | | |
39 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| 90 | + | |
90 | 91 | | |
91 | 92 | | |
92 | 93 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
| 41 | + | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| |||
0 commit comments