Skip to content

Commit 39c3632

Browse files
fix: resolve balance aggregation issue for large token decimals (#9653)
## Explanation Removes old behaviour that was kept prior from WS issues around data in incorrect format, but now has been fixed. Also did some test spec cleaning... ## References MetaMask/metamask-extension#44786 ## 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) - [x] 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 ### Example Extension Test: <img width="534" height="658" alt="Screenshot 2026-07-29 at 12 37 58" src="https://github.com/user-attachments/assets/4b0e4417-bbe6-44ce-bcf7-433ac1305575" /> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes core balance aggregation math used for wallet/group fiat totals; the fix aligns with the invariant that state amounts are human-readable, but any edge case that still stored raw base units would now be mispriced. > > **Overview** > Fixes **incorrect portfolio totals** when token balances are large human-readable amounts (e.g. billions of tokens with 9 decimals) by removing the legacy `scaleToHumanIfRaw` path in `balance.ts` aggregation. > > **`assetsBalance` amounts are always human-readable**, but the old heuristic treated values ≥ `10^decimals` as raw base units and divided by `10^decimals`, which **under-counted** those holdings in `getAggregatedBalanceForAccount`, `getAggregatedBalanceForAccountIds`, `calculateBalanceForAllWallets`, and `calculateBalanceChangeForAccountGroup` (metamask-extension#44786). > > Tests add a TangYuan regression case, shared `arrangeAssetsControllerState` helpers, and coverage for group aggregation when only `accountTreeState` is passed (no `accountsById`). Changelog documents the fix. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7056a0b. 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: Cursor Agent <cursoragent@cursor.com>
1 parent be7e45d commit 39c3632

3 files changed

Lines changed: 211 additions & 242 deletions

File tree

packages/assets-controller/CHANGELOG.md

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

2727
- `withTrace` treats a rejected parent `trace` promise as best-effort (like `emitTrace`), so Sentry/adapter failures cannot fail full fetches or `handleAssetsUpdate` enrichment ([#9672](https://github.com/MetaMask/core/pull/9672))
2828
- `SnapDataSource` now delivers snap-sourced balance updates directly to `AssetsController` via a constructor-supplied `onAssetsUpdate` callback instead of fanning out to `activeSubscriptions`, so updates (e.g. Tron energy/bandwidth) are no longer dropped when no active subscription is tracked for the chain in the SnapDataSource ([#9656](https://github.com/MetaMask/core/pull/9656))
29+
- Balance aggregation selectors (`getAggregatedBalanceForAccount`, `getAggregatedBalanceForAccountIds`, `calculateBalanceForAllWallets`, `calculateBalanceChangeForAccountGroup`) no longer rescale balances whose amount is greater than or equal to `10^decimals`. Amounts in `assetsBalance` state are always human-readable, so the removed raw-vs-human magnitude heuristic corrupted legitimately large balances (e.g. 54.06B tokens with 9 decimals were divided by `10^9`), excluding them from aggregated fiat totals ([#9653](https://github.com/MetaMask/core/pull/9653))
2930

3031
## [11.2.1]
3132

0 commit comments

Comments
 (0)