Skip to content

Commit 69ccbd9

Browse files
authored
feat(assets-controller): add balance state in snaps request (#10819)
## Explanation v6 `SnapDataSource` fetches request the snap's listed holdings plus visible assets (native, pin, and default tracked). Accounts API and the websocket already return a wider token set than the snap lists. If a chain rolls back to the snap, those extra tokens would stop refreshing. This adds a temporary, deletable block so the v6 request is the union of: - the snap's listed holdings - visible assets - every token already stored in balance state for the requested chains Hidden assets stay out, and tokens stored for other chains stay out. A visible token with no balance entry is still requested. If the snap omits a balance-state token it was asked for, that token stays out of the snapshot. Delete `#includeSnapRollbackBalanceStateTokens` and its call in `#fetchV6` once balance reads fully move to Accounts API. The visible-asset path is unchanged. Unsubscribing from account activity now releases every tracked chain the same way a WebSocket disconnect does. `#unsubscribeFromAllAccountActivity` publishes one `AccountActivityService:statusChanged` event with status `down` for every tracked chain, including any status still buffered, and then clears that set. A snaps-migration flag change and an account switch both go through this unsubscribe before resubscribing. The next system notification marks the chains that are still up, so chains whose flag turned off can be subscribed through snaps. ## References * Related to the Accounts API v6 snap migration notes in `packages/assets-controller/docs/decisions/2026-09-23-accounts-api-v6-integration.md` ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] 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** > Changes v6 snap balance fetch scope and when AssetsController sees chains as down during migration flag toggles; incorrect signaling could mis-route balance sources until the next system notification. > > **Overview** > **Snap v6 balance requests** temporarily include every token already in balance state for the requested chains (plus listed holdings and visible assets), in a marked-for-deletion block, so a rollback to Snaps still refreshes tokens Accounts API / websocket already track. Snap-omitted balance-state tokens are **not** zero-filled or backfilled from state. > > **Account activity chain status** is refactored: `#publishTrackedChainsDown` centralizes publishing `down` for all tracked chains (including debounced pending). WebSocket disconnect and **snaps-migration feature-flag** resubscribe use it; **account switches** only unsubscribe/resubscribe and do **not** publish chains down. > > Docs, changelogs, and tests (`SnapDataSource`, `AccountActivityService`) are updated for the new request union and status semantics. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c18f4a6. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent bb58aab commit 69ccbd9

8 files changed

Lines changed: 508 additions & 142 deletions

File tree

‎oxlint-suppressions.json‎

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -816,15 +816,6 @@
816816
"packages/assets-controller/src/data-sources/SnapDataSource.test.ts": {
817817
"no-useless-return": {
818818
"count": 1
819-
},
820-
"typescript/no-unsafe-assignment": {
821-
"count": 6
822-
},
823-
"typescript/no-unsafe-member-access": {
824-
"count": 1
825-
},
826-
"typescript/no-unsafe-return": {
827-
"count": 1
828819
}
829820
},
830821
"packages/assets-controller/src/data-sources/SnapDataSource.ts": {
@@ -2553,7 +2544,7 @@
25532544
"count": 1
25542545
},
25552546
"typescript/no-unsafe-assignment": {
2556-
"count": 9
2547+
"count": 11
25572548
},
25582549
"typescript/no-unsafe-member-access": {
25592550
"count": 2

‎packages/assets-controller/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Changed
1111

12+
- Temporarily extend `SnapDataSource` v6 balance fetches, in a deletable block, to also request every token already stored in balance state for the requested chains, so a rollback to Snaps still refreshes tokens that Accounts API and the websocket already support. Remove that block once balance reads fully move to Accounts API ([#10819](https://github.com/MetaMask/core/pull/10819))
1213
- Bump `@metamask/keyring-api` from `^24.1.0` to `^24.3.0` ([#10792](https://github.com/MetaMask/core/pull/10792), [#10844](https://github.com/MetaMask/core/pull/10844))
1314
- Bump `@metamask/keyring-internal-api` from `^12.1.0` to `^12.1.2` ([#10792](https://github.com/MetaMask/core/pull/10792), [#10844](https://github.com/MetaMask/core/pull/10844))
1415
- Bump `@metamask/keyring-snap-client` from `^10.0.0` to `^10.0.1` ([#10792](https://github.com/MetaMask/core/pull/10792))

‎packages/assets-controller/docs/decisions/2026-09-23-accounts-api-v6-integration.md‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,13 @@ The requests differ as well:
142142
in full from state. RPC always stamps `full`: resolved tokens get a fresh
143143
amount, unread tokens keep the amount already in state, and a chain that
144144
resolved nothing is listed in `errors` instead of writing an empty slice.
145-
Snap `#fetchV6` requests visible assets with listed holdings, stamps `full`,
146-
and fills omitted visible assets from current state (`0` if none). An empty
145+
Snap `#fetchV6` requests listed holdings and visible assets, stamps `full`,
146+
and fills omitted visible assets from current state (`0` if none). A separate
147+
temporary block also requests every token already in balance state for those
148+
chains. A token the snap omits stays out of the snapshot. Accounts API and
149+
the websocket already cover more tokens than the snap lists, so a chain that
150+
rolls back to the snap still refreshes them. Delete that block once balance
151+
reads fully move to Accounts API. An empty
147152
`getAccountBalances` map (or a thrown fetch) contributes nothing, so last-
148153
known amounts are kept. Background Snap and
149154
RPC both stamp `full`. `mergeDataResponses` promotes `full` if any source did.
@@ -184,7 +189,7 @@ flowchart TB
184189
V6A["Subscribe each source with accounts + assigned chains only"]
185190
V6WS["Account Activity · event deltas · merge"]
186191
V6API["Accounts API · visibility from state · full"]
187-
V6SNAP["Snap · visible assets from state · full snapshot<br/>balance events stay merge"]
192+
V6SNAP["Snap · visible assets · full snapshot<br/>temporary balance-state tokens<br/>balance events stay merge"]
188193
V6RPC["RPC · visible assets from state · full"]
189194
V6A --> V6WS
190195
V6A --> V6API

0 commit comments

Comments
 (0)