feat(money): centralize money account balance fetching - #9554
Merged
Conversation
Member
Author
|
@metamaskbot publish-preview |
Contributor
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
Member
Author
|
@metamaskbot publish-preview |
Contributor
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
ffmcgee725
marked this pull request as ready for review
July 20, 2026 14:41
ffmcgee725
temporarily deployed
to
default-branch
July 20, 2026 14:42 — with
GitHub Actions
Inactive
Member
Author
|
@metamaskbot publish-preview |
10 tasks
Contributor
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
ffmcgee725
enabled auto-merge
July 21, 2026 06:53
shane-t
approved these changes
Jul 21, 2026
Merged
pull Bot
pushed a commit
to Reality2byte/core
that referenced
this pull request
Jul 21, 2026
## @metamask/chain-agnostic-permission ## [0.2.0] ### Added - Add optional nullable `balance` field to the positions response (`musd_balance`, `vmusd_value_in_musd`, `total_balance`), matching the Money Account API contract. Export `PositionBalance` type. ([MetaMask#9554](MetaMask#9554)) ## @metamask/money-account-balance-service ## [2.3.0] ### Added - Add `fetchBalanceWithFallback` facade that selects Money API or RPC balance sources from the `moneyAccountBalanceSource` remote feature flag (`api` | `rpc` | `api-only` | `rpc-only`; default `rpc` = RPC primary with Money API fallback). Returns canonical amounts plus `source` and `usedFallback` provenance; reports validation/unavailable source defects via messenger `captureException`; throws `MoneyAccountBalanceFetchError` when all eligible sources fail. ([MetaMask#9554](MetaMask#9554)) - Permit `MoneyAccountApiDataService:fetchPositions` on the balance service messenger so the facade can read Money API balances. ([MetaMask#9554](MetaMask#9554)) - Export `CanonicalMoneyAccountBalanceResponse`, balance-source constants/types, and `MoneyAccountBalanceFetchError` / `MoneyAccountBalanceUnavailableError` / `MoneyAccountBalanceValidationError`. ([MetaMask#9554](MetaMask#9554)) ### Changed - Bump `@metamask/money-account-api-data-service` from `^0.1.0` to `^0.2.0` ([MetaMask#9573](MetaMask#9573)) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > No application code in the diff—only semver, changelog entries, and lockfile resolution for already-merged features. > > **Overview** > **Monorepo release 1132.0.0** that publishes version bumps for Money Account packages with no runtime code changes in this diff—only `package.json`, changelogs, and `yarn.lock`. > > **`@metamask/money-account-api-data-service@0.2.0`** (documented in changelog): optional nullable `balance` on positions (`musd_balance`, `vmusd_value_in_musd`, `total_balance`) and exported `PositionBalance` ([MetaMask#9554]). > > **`@metamask/money-account-balance-service@2.3.0`**: documents `fetchBalanceWithFallback` driven by `moneyAccountBalanceSource`, messenger access to `fetchPositions`, new exports/errors ([MetaMask#9554]), and bumps the api-data-service dependency to `^0.2.0` ([MetaMask#9573]). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 0fbca63. 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: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
ffmcgee725
added a commit
that referenced
this pull request
Jul 21, 2026
Resolve conflicts by keeping API data service network tracing and adopting main's nullable PositionBalance contract from #9554. Co-authored-by: Cursor <cursoragent@cursor.com>
pull Bot
pushed a commit
to Reality2byte/metamask-mobile
that referenced
this pull request
Jul 23, 2026
## **Description** Adopts the Money Account balance facade from `@metamask/money-account-balance-service` so presentation always goes through `fetchBalanceWithFallback` instead of the RPC-only `getMoneyAccountBalance`. Balances can come from either the Money API (HTTP via `@metamask/money-account-api-data-service`) or Multicall3 RPC. Source selection, failover, and canonical response mapping live in the balance-service package (see [MetaMask/core#9554](MetaMask/core#9554)); Mobile wires the API data service and switches consumers to the facade. Default routing is RPC-primary with API fallback (`moneyAccountBalanceSource` remote flag; absent/malformed → `rpc`). ### Changes **New / updated service plumbing:** - Added preview packages for `@metamask/money-account-api-data-service` and `@metamask/money-account-balance-service` - Created messenger + init for `MoneyAccountApiDataService` (production API host `Env.PRD`) - Wired into Engine (`Engine.ts`, types, messengers index, `STATELESS_NON_CONTROLLER_NAMES`, `DATA_SERVICES`) - Delegated `MoneyAccountApiDataService:fetchPositions` onto the `MoneyAccountBalanceService` messenger (required by the facade) **Consumer-side:** - `useMoneyAccountBalance` queries `MoneyAccountBalanceService:fetchBalanceWithFallback` and exposes provenance (`balanceSource`, `usedFallback`, `isBalanceDegraded`) - Query key / cache invalidation updated for refresh-on-tx-confirm and first-time deposit helpers - Vault APY continues to use `MoneyAccountBalanceService:getVaultApy` (unchanged) **Out of scope / deferred (per ADR):** - UI indication of fallback/degraded balance (logs/provenance fields only) - Shadow-read equivalence, request deadlines, per-source circuit split beyond what the package already ships ## **Changelog** CHANGELOG entry: Centralize Money Account balance fetching behind `fetchBalanceWithFallback` (RPC primary with Money API fallback) ## **Related issues** Fixes: N/A Related: - Core facade PoC: MetaMask/core#9554 - ADR: `Centralize-MoneyAccount-Balance.md` (proposed) ## **Manual testing steps** ```gherkin Feature: Money Account balance via fetchBalanceWithFallback Scenario: User views Money Account balance on wallet home Given the user has a funded Money Account And the app can reach money.api.cx.metamask.io When the user navigates to the wallet home / Money home screen Then the Money balance displays the correct USD total (mUSD + vmUSD valued in mUSD) And the APY tag still loads from the vault APY query Scenario: Balance refreshes after a deposit or withdraw Given the user has completed a Money Account deposit or withdraw When the transaction is confirmed Then the balance query is invalidated and refetched via fetchBalanceWithFallback And the updated balance is displayed without requiring a manual refresh Scenario: RPC primary with API fallback Given moneyAccountBalanceSource is absent or set to "rpc" And the Multicall3 RPC is temporarily unavailable When the user loads Money balance Then the facade falls back to Money Account API And a valid non-zero balance is still shown when on-chain funds exist And the result reports usedFallback / source provenance on the hook Scenario: Loading and error states are unchanged Given the user opens the app with a Money Account When the balance query is in flight Then skeleton / loading UI behaves as before When both API and RPC fail Then the unavailable / last-known balance UX behaves as before ``` ## **Screenshots/Recordings** N/A — no intentional visual changes; balance source is transparent to the user ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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 - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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] > **Medium Risk** > Touches core Money balance display and refresh across API/RPC failover; incorrect cache invalidation or facade wiring could show stale balances after transactions, though behavior is heavily tested. > > **Overview** > **Routes Money Account balance through the `fetchBalanceWithFallback` facade** instead of RPC-only `getMoneyAccountBalance`, bumping `@metamask/money-account-balance-service` and adding `@metamask/money-account-api-data-service` with Engine init, messengers, and delegation of `fetchPositions` into the balance service. > > **UI and refresh paths** switch React Query keys to `FETCH_BALANCE_WITH_FALLBACK`, use `CanonicalMoneyAccountBalanceResponse`, and expose `balanceSource`, `usedFallback`, and `isBalanceDegraded` from `useMoneyAccountBalance`. Analytics, first-time deposit checks, and post-tx refresh read the same facade key. > > **Forced refresh** goes through new `invalidateMoneyAccountBalanceCaches`, which clears RPC (`getMoneyAccountBalance`) and API (`fetchPositions`) source caches via messenger before invalidating the UI facade—fixing stale reads after deposits/withdraws and pull-to-refresh. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c691077. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Explanation
Money Account balances can be fetched from two sources: Multicall3 RPC via
@metamask/money-account-balance-service(getMoneyAccountBalance) and HTTP via@metamask/money-account-api-data-service(fetchPositions, which includes abalancesummary). Exposing both to clients would push feature-flag handling, failover, and response mapping into every call site (e.g.useMoneyAccountBalance).This PR centralizes source selection behind a facade inside
@metamask/money-account-balance-service, matching the “single service facade” approach:Changes
@metamask/money-account-api-data-servicebalancefield (musd_balance,vmusd_value_in_musd,total_balance).balancemay benullwhen the API balance path is disabled/unavailable; omit remains valid for backwards compatibility.PositionBalance.@metamask/money-account-balance-servicefetchBalanceWithFallback(accountAddress).moneyAccountBalanceSource:api— Money API primary, RPC fallbackrpc— RPC primary, Money API fallback (hard default when absent/malformed)api-only/rpc-only— incident kill switches (no fallback)MoneyAccountApiDataService:fetchPositions(dependency on@metamask/money-account-api-data-serviceadded for action/types).getMoneyAccountBalanceas the RPC source adapter (no breaking change).{ musdBalance, vmusdValueInMusd, totalBalance, source, usedFallback }.totalBalance === musdBalance + vmusdValueInMusd.MoneyAccountBalanceFetchErrorwith both causes — never invent a zero balance.Out of scope (deferred per ADR)
Request deadlines, separate circuit breakers per source, APY policy split from balance RPC, shadow-read / equivalence checks, freshness-based failover, and client hook adoption in this repo.
Client adoption notes
MoneyAccountBalanceService:fetchBalanceWithFallback.MoneyAccountApiDataService:fetchPositionsonto the balance-service messenger (same pattern as NetworkController / RemoteFeatureFlagController actions).moneyAccountBalanceSource.Checklist
Note
Medium Risk
Touches balance presentation and dual-source failover for financial amounts; incorrect routing or validation could show wrong balances, though defaults keep RPC primary and failures do not invent zeros.
Overview
Centralizes Money account balance reads behind
MoneyAccountBalanceService.fetchBalanceWithFallback, so clients no longer choose between RPC multicall and the Money Account API at each call site.@metamask/money-account-api-data-serviceextends the positions payload with an optional nullablebalancesummary (musd_balance,vmusd_value_in_musd,total_balance), validates it in superstruct, and exportsPositionBalance.@metamask/money-account-balance-serviceadds routing via remote flagmoneyAccountBalanceSource(api|rpc|api-only|rpc-only; defaultrpc= RPC primary with API fallback). The facade callsMoneyAccountApiDataService:fetchPositionsthrough the messenger (new package dependency and README wiring note), reusesgetMoneyAccountBalancefor RPC, validates integer amounts andtotalBalance === musdBalance + vmusdValueInMusd, returnssourceandusedFallback, reports validation/unavailable API balance viacaptureException, and throwsMoneyAccountBalanceFetchErrorwhen all eligible sources fail (no synthetic zero).Reviewed by Cursor Bugbot for commit 12f2a71. Bugbot is set up for automated code reviews on this repo. Configure here.