Skip to content

feat(money): centralize money account balance fetching - #9554

Merged
ffmcgee725 merged 5 commits into
mainfrom
jc/centralize-money-account-balance-fetching
Jul 21, 2026
Merged

feat(money): centralize money account balance fetching#9554
ffmcgee725 merged 5 commits into
mainfrom
jc/centralize-money-account-balance-fetching

Conversation

@ffmcgee725

@ffmcgee725 ffmcgee725 commented Jul 20, 2026

Copy link
Copy Markdown
Member

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 a balance summary). 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:

useMoneyAccountBalance
  -> MoneyAccountBalanceService.fetchBalanceWithFallback
    -> getMoneyAccountBalance                     (RPC multicall)
    -> MoneyAccountApiDataService:fetchPositions  (Money API)

Changes

@metamask/money-account-api-data-service

  • Align the positions response contract with the Money Account API by adding an optional nullable balance field (musd_balance, vmusd_value_in_musd, total_balance).
  • balance may be null when the API balance path is disabled/unavailable; omit remains valid for backwards compatibility.
  • Export PositionBalance.

@metamask/money-account-balance-service

  • Add non-breaking facade method fetchBalanceWithFallback(accountAddress).
  • Route via remote feature flag moneyAccountBalanceSource:
    • api — Money API primary, RPC fallback
    • rpc — RPC primary, Money API fallback (hard default when absent/malformed)
    • api-only / rpc-only — incident kill switches (no fallback)
  • Call the Money API through messenger action MoneyAccountApiDataService:fetchPositions (dependency on @metamask/money-account-api-data-service added for action/types).
  • Keep existing getMoneyAccountBalance as the RPC source adapter (no breaking change).
  • Return a canonical result with provenance: { musdBalance, vmusdValueInMusd, totalBalance, source, usedFallback }.
  • Validate non-negative integer amounts and totalBalance === musdBalance + vmusdValueInMusd.
  • On eligible primary failure (transport error, null/missing API balance, semantic validation), try fallback when allowed.
  • If all eligible sources fail, throw MoneyAccountBalanceFetchError with 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

  1. Switch the balance hook to MoneyAccountBalanceService:fetchBalanceWithFallback.
  2. Delegate MoneyAccountApiDataService:fetchPositions onto the balance-service messenger (same pattern as NetworkController / RemoteFeatureFlagController actions).
  3. Optionally configure remote flag moneyAccountBalanceSource.

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
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-service extends the positions payload with an optional nullable balance summary (musd_balance, vmusd_value_in_musd, total_balance), validates it in superstruct, and exports PositionBalance.

@metamask/money-account-balance-service adds routing via remote flag moneyAccountBalanceSource (api | rpc | api-only | rpc-only; default rpc = RPC primary with API fallback). The facade calls MoneyAccountApiDataService:fetchPositions through the messenger (new package dependency and README wiring note), reuses getMoneyAccountBalance for RPC, validates integer amounts and totalBalance === musdBalance + vmusdValueInMusd, returns source and usedFallback, reports validation/unavailable API balance via captureException, and throws MoneyAccountBalanceFetchError when 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.

@ffmcgee725

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.5-preview-4343321
@metamask-previews/accounts-controller@39.0.5-preview-4343321
@metamask-previews/address-book-controller@7.1.2-preview-4343321
@metamask-previews/ai-controllers@0.8.0-preview-4343321
@metamask-previews/analytics-controller@1.2.1-preview-4343321
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-4343321
@metamask-previews/announcement-controller@8.1.0-preview-4343321
@metamask-previews/app-metadata-controller@2.0.1-preview-4343321
@metamask-previews/approval-controller@9.0.2-preview-4343321
@metamask-previews/assets-controller@11.0.0-preview-4343321
@metamask-previews/assets-controllers@109.4.1-preview-4343321
@metamask-previews/authenticated-user-storage@3.0.1-preview-4343321
@metamask-previews/base-controller@9.1.0-preview-4343321
@metamask-previews/base-data-service@0.1.3-preview-4343321
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-4343321
@metamask-previews/bridge-controller@77.5.0-preview-4343321
@metamask-previews/bridge-status-controller@74.3.0-preview-4343321
@metamask-previews/build-utils@3.0.4-preview-4343321
@metamask-previews/chain-agnostic-permission@1.7.0-preview-4343321
@metamask-previews/chomp-api-service@3.1.0-preview-4343321
@metamask-previews/claims-controller@0.5.3-preview-4343321
@metamask-previews/client-controller@1.0.1-preview-4343321
@metamask-previews/client-utils@1.1.0-preview-4343321
@metamask-previews/compliance-controller@2.1.0-preview-4343321
@metamask-previews/composable-controller@12.0.1-preview-4343321
@metamask-previews/config-registry-controller@0.4.1-preview-4343321
@metamask-previews/connectivity-controller@0.3.0-preview-4343321
@metamask-previews/controller-utils@12.3.0-preview-4343321
@metamask-previews/core-backend@6.5.0-preview-4343321
@metamask-previews/delegation-controller@3.0.2-preview-4343321
@metamask-previews/earn-controller@12.2.2-preview-4343321
@metamask-previews/eip-5792-middleware@3.0.5-preview-4343321
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-4343321
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-4343321
@metamask-previews/ens-controller@19.1.5-preview-4343321
@metamask-previews/eth-block-tracker@15.0.1-preview-4343321
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-4343321
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-4343321
@metamask-previews/foundryup@1.0.1-preview-4343321
@metamask-previews/gas-fee-controller@26.2.4-preview-4343321
@metamask-previews/gator-permissions-controller@4.2.3-preview-4343321
@metamask-previews/geolocation-controller@0.1.3-preview-4343321
@metamask-previews/java-tron-up@1.0.0-preview-4343321
@metamask-previews/json-rpc-engine@10.5.0-preview-4343321
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-4343321
@metamask-previews/keyring-controller@27.1.0-preview-4343321
@metamask-previews/local-node-utils@1.0.0-preview-4343321
@metamask-previews/logging-controller@8.0.2-preview-4343321
@metamask-previews/message-manager@14.1.2-preview-4343321
@metamask-previews/messenger@2.0.0-preview-4343321
@metamask-previews/messenger-cli@0.2.0-preview-4343321
@metamask-previews/money-account-api-data-service@0.1.0-preview-4343321
@metamask-previews/money-account-balance-service@2.2.0-preview-4343321
@metamask-previews/money-account-controller@0.3.3-preview-4343321
@metamask-previews/money-account-upgrade-controller@2.2.1-preview-4343321
@metamask-previews/multichain-account-service@13.0.0-preview-4343321
@metamask-previews/multichain-api-middleware@4.0.1-preview-4343321
@metamask-previews/multichain-network-controller@3.2.1-preview-4343321
@metamask-previews/multichain-transactions-controller@7.1.1-preview-4343321
@metamask-previews/name-controller@9.1.2-preview-4343321
@metamask-previews/network-connection-banner-controller@0.1.0-preview-4343321
@metamask-previews/network-controller@34.0.0-preview-4343321
@metamask-previews/network-enablement-controller@5.6.0-preview-4343321
@metamask-previews/notification-services-controller@25.0.0-preview-4343321
@metamask-previews/passkey-controller@2.1.0-preview-4343321
@metamask-previews/permission-controller@13.1.1-preview-4343321
@metamask-previews/permission-log-controller@5.1.0-preview-4343321
@metamask-previews/perps-controller@9.2.1-preview-4343321
@metamask-previews/phishing-controller@17.3.0-preview-4343321
@metamask-previews/platform-api-docs@0.0.0-preview-4343321
@metamask-previews/polling-controller@16.0.8-preview-4343321
@metamask-previews/preferences-controller@23.1.0-preview-4343321
@metamask-previews/profile-metrics-controller@4.0.2-preview-4343321
@metamask-previews/profile-sync-controller@28.3.0-preview-4343321
@metamask-previews/ramps-controller@17.0.0-preview-4343321
@metamask-previews/rate-limit-controller@7.0.1-preview-4343321
@metamask-previews/react-data-query@0.2.2-preview-4343321
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-4343321
@metamask-previews/sample-controllers@5.0.3-preview-4343321
@metamask-previews/seedless-onboarding-controller@10.0.3-preview-4343321
@metamask-previews/selected-network-controller@26.1.5-preview-4343321
@metamask-previews/sentinel-api-service@1.0.0-preview-4343321
@metamask-previews/shield-controller@5.1.3-preview-4343321
@metamask-previews/signature-controller@39.2.7-preview-4343321
@metamask-previews/smart-transactions-controller@25.0.1-preview-4343321
@metamask-previews/snap-account-service@2.0.0-preview-4343321
@metamask-previews/social-controllers@2.5.0-preview-4343321
@metamask-previews/solana-test-validator-up@1.0.0-preview-4343321
@metamask-previews/stellar-quickstart-up@0.0.0-preview-4343321
@metamask-previews/storage-service@1.0.2-preview-4343321
@metamask-previews/subscription-controller@6.2.1-preview-4343321
@metamask-previews/transaction-controller@69.0.0-preview-4343321
@metamask-previews/transaction-pay-controller@25.0.0-preview-4343321
@metamask-previews/user-operation-controller@41.2.7-preview-4343321
@metamask-previews/wallet@7.0.1-preview-4343321
@metamask-previews/wallet-cli@0.0.0-preview-4343321

@ffmcgee725

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.5-preview-8ab4ba253
@metamask-previews/accounts-controller@39.0.5-preview-8ab4ba253
@metamask-previews/address-book-controller@7.1.2-preview-8ab4ba253
@metamask-previews/ai-controllers@0.8.0-preview-8ab4ba253
@metamask-previews/analytics-controller@1.2.1-preview-8ab4ba253
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-8ab4ba253
@metamask-previews/announcement-controller@8.1.0-preview-8ab4ba253
@metamask-previews/app-metadata-controller@2.0.1-preview-8ab4ba253
@metamask-previews/approval-controller@9.0.2-preview-8ab4ba253
@metamask-previews/assets-controller@11.0.0-preview-8ab4ba253
@metamask-previews/assets-controllers@109.4.1-preview-8ab4ba253
@metamask-previews/authenticated-user-storage@3.0.1-preview-8ab4ba253
@metamask-previews/base-controller@9.1.0-preview-8ab4ba253
@metamask-previews/base-data-service@0.1.3-preview-8ab4ba253
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-8ab4ba253
@metamask-previews/bridge-controller@77.5.0-preview-8ab4ba253
@metamask-previews/bridge-status-controller@74.3.0-preview-8ab4ba253
@metamask-previews/build-utils@3.0.4-preview-8ab4ba253
@metamask-previews/chain-agnostic-permission@1.7.0-preview-8ab4ba253
@metamask-previews/chomp-api-service@3.1.0-preview-8ab4ba253
@metamask-previews/claims-controller@0.5.3-preview-8ab4ba253
@metamask-previews/client-controller@1.0.1-preview-8ab4ba253
@metamask-previews/client-utils@1.1.0-preview-8ab4ba253
@metamask-previews/compliance-controller@2.1.0-preview-8ab4ba253
@metamask-previews/composable-controller@12.0.1-preview-8ab4ba253
@metamask-previews/config-registry-controller@0.4.1-preview-8ab4ba253
@metamask-previews/connectivity-controller@0.3.0-preview-8ab4ba253
@metamask-previews/controller-utils@12.3.0-preview-8ab4ba253
@metamask-previews/core-backend@6.5.0-preview-8ab4ba253
@metamask-previews/delegation-controller@3.0.2-preview-8ab4ba253
@metamask-previews/earn-controller@12.2.2-preview-8ab4ba253
@metamask-previews/eip-5792-middleware@3.0.5-preview-8ab4ba253
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-8ab4ba253
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-8ab4ba253
@metamask-previews/ens-controller@19.1.5-preview-8ab4ba253
@metamask-previews/eth-block-tracker@15.0.1-preview-8ab4ba253
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-8ab4ba253
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-8ab4ba253
@metamask-previews/foundryup@1.0.1-preview-8ab4ba253
@metamask-previews/gas-fee-controller@26.2.4-preview-8ab4ba253
@metamask-previews/gator-permissions-controller@4.2.3-preview-8ab4ba253
@metamask-previews/geolocation-controller@0.1.3-preview-8ab4ba253
@metamask-previews/java-tron-up@1.0.0-preview-8ab4ba253
@metamask-previews/json-rpc-engine@10.5.0-preview-8ab4ba253
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-8ab4ba253
@metamask-previews/keyring-controller@27.1.0-preview-8ab4ba253
@metamask-previews/local-node-utils@1.0.0-preview-8ab4ba253
@metamask-previews/logging-controller@8.0.2-preview-8ab4ba253
@metamask-previews/message-manager@14.1.2-preview-8ab4ba253
@metamask-previews/messenger@2.0.0-preview-8ab4ba253
@metamask-previews/messenger-cli@0.2.0-preview-8ab4ba253
@metamask-previews/money-account-api-data-service@0.1.0-preview-8ab4ba253
@metamask-previews/money-account-balance-service@2.2.0-preview-8ab4ba253
@metamask-previews/money-account-controller@0.3.3-preview-8ab4ba253
@metamask-previews/money-account-upgrade-controller@2.2.1-preview-8ab4ba253
@metamask-previews/multichain-account-service@13.0.0-preview-8ab4ba253
@metamask-previews/multichain-api-middleware@4.0.1-preview-8ab4ba253
@metamask-previews/multichain-network-controller@3.2.1-preview-8ab4ba253
@metamask-previews/multichain-transactions-controller@7.1.1-preview-8ab4ba253
@metamask-previews/name-controller@9.1.2-preview-8ab4ba253
@metamask-previews/network-connection-banner-controller@0.1.0-preview-8ab4ba253
@metamask-previews/network-controller@34.0.0-preview-8ab4ba253
@metamask-previews/network-enablement-controller@5.6.0-preview-8ab4ba253
@metamask-previews/notification-services-controller@25.0.0-preview-8ab4ba253
@metamask-previews/passkey-controller@2.1.0-preview-8ab4ba253
@metamask-previews/permission-controller@13.1.1-preview-8ab4ba253
@metamask-previews/permission-log-controller@5.1.0-preview-8ab4ba253
@metamask-previews/perps-controller@9.2.1-preview-8ab4ba253
@metamask-previews/phishing-controller@17.3.0-preview-8ab4ba253
@metamask-previews/platform-api-docs@0.0.0-preview-8ab4ba253
@metamask-previews/polling-controller@16.0.8-preview-8ab4ba253
@metamask-previews/preferences-controller@23.1.0-preview-8ab4ba253
@metamask-previews/profile-metrics-controller@4.0.2-preview-8ab4ba253
@metamask-previews/profile-sync-controller@28.3.0-preview-8ab4ba253
@metamask-previews/ramps-controller@17.0.0-preview-8ab4ba253
@metamask-previews/rate-limit-controller@7.0.1-preview-8ab4ba253
@metamask-previews/react-data-query@0.2.2-preview-8ab4ba253
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-8ab4ba253
@metamask-previews/sample-controllers@5.0.3-preview-8ab4ba253
@metamask-previews/seedless-onboarding-controller@10.0.3-preview-8ab4ba253
@metamask-previews/selected-network-controller@26.1.5-preview-8ab4ba253
@metamask-previews/sentinel-api-service@1.0.0-preview-8ab4ba253
@metamask-previews/shield-controller@5.1.3-preview-8ab4ba253
@metamask-previews/signature-controller@39.2.7-preview-8ab4ba253
@metamask-previews/smart-transactions-controller@25.0.1-preview-8ab4ba253
@metamask-previews/snap-account-service@2.0.0-preview-8ab4ba253
@metamask-previews/social-controllers@2.5.0-preview-8ab4ba253
@metamask-previews/solana-test-validator-up@1.0.0-preview-8ab4ba253
@metamask-previews/stellar-quickstart-up@0.0.0-preview-8ab4ba253
@metamask-previews/storage-service@1.0.2-preview-8ab4ba253
@metamask-previews/subscription-controller@6.2.1-preview-8ab4ba253
@metamask-previews/transaction-controller@69.0.0-preview-8ab4ba253
@metamask-previews/transaction-pay-controller@25.0.0-preview-8ab4ba253
@metamask-previews/user-operation-controller@41.2.7-preview-8ab4ba253
@metamask-previews/wallet@7.0.1-preview-8ab4ba253
@metamask-previews/wallet-cli@0.0.0-preview-8ab4ba253

@ffmcgee725
ffmcgee725 marked this pull request as ready for review July 20, 2026 14:41
@ffmcgee725
ffmcgee725 requested review from a team as code owners July 20, 2026 14:41
@ffmcgee725

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.5-preview-b47b10d1b
@metamask-previews/accounts-controller@39.0.5-preview-b47b10d1b
@metamask-previews/address-book-controller@7.1.2-preview-b47b10d1b
@metamask-previews/ai-controllers@0.8.0-preview-b47b10d1b
@metamask-previews/analytics-controller@1.2.1-preview-b47b10d1b
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-b47b10d1b
@metamask-previews/announcement-controller@8.1.0-preview-b47b10d1b
@metamask-previews/app-metadata-controller@2.0.1-preview-b47b10d1b
@metamask-previews/approval-controller@9.0.2-preview-b47b10d1b
@metamask-previews/assets-controller@11.0.0-preview-b47b10d1b
@metamask-previews/assets-controllers@109.4.1-preview-b47b10d1b
@metamask-previews/authenticated-user-storage@3.0.1-preview-b47b10d1b
@metamask-previews/base-controller@9.1.0-preview-b47b10d1b
@metamask-previews/base-data-service@0.1.3-preview-b47b10d1b
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-b47b10d1b
@metamask-previews/bridge-controller@77.5.0-preview-b47b10d1b
@metamask-previews/bridge-status-controller@74.3.0-preview-b47b10d1b
@metamask-previews/build-utils@3.0.4-preview-b47b10d1b
@metamask-previews/chain-agnostic-permission@1.7.0-preview-b47b10d1b
@metamask-previews/chomp-api-service@3.1.0-preview-b47b10d1b
@metamask-previews/claims-controller@0.5.3-preview-b47b10d1b
@metamask-previews/client-controller@1.0.1-preview-b47b10d1b
@metamask-previews/client-utils@1.2.0-preview-b47b10d1b
@metamask-previews/compliance-controller@2.1.0-preview-b47b10d1b
@metamask-previews/composable-controller@12.0.1-preview-b47b10d1b
@metamask-previews/config-registry-controller@0.4.1-preview-b47b10d1b
@metamask-previews/connectivity-controller@0.3.0-preview-b47b10d1b
@metamask-previews/controller-utils@12.3.0-preview-b47b10d1b
@metamask-previews/core-backend@6.5.0-preview-b47b10d1b
@metamask-previews/delegation-controller@3.0.2-preview-b47b10d1b
@metamask-previews/earn-controller@12.2.2-preview-b47b10d1b
@metamask-previews/eip-5792-middleware@3.0.5-preview-b47b10d1b
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-b47b10d1b
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-b47b10d1b
@metamask-previews/ens-controller@19.1.5-preview-b47b10d1b
@metamask-previews/eth-block-tracker@15.0.1-preview-b47b10d1b
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-b47b10d1b
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-b47b10d1b
@metamask-previews/foundryup@1.0.1-preview-b47b10d1b
@metamask-previews/gas-fee-controller@26.2.4-preview-b47b10d1b
@metamask-previews/gator-permissions-controller@4.2.3-preview-b47b10d1b
@metamask-previews/geolocation-controller@0.1.3-preview-b47b10d1b
@metamask-previews/java-tron-up@1.0.0-preview-b47b10d1b
@metamask-previews/json-rpc-engine@10.5.0-preview-b47b10d1b
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-b47b10d1b
@metamask-previews/keyring-controller@27.1.0-preview-b47b10d1b
@metamask-previews/local-node-utils@1.0.0-preview-b47b10d1b
@metamask-previews/logging-controller@8.0.2-preview-b47b10d1b
@metamask-previews/message-manager@14.1.2-preview-b47b10d1b
@metamask-previews/messenger@2.0.0-preview-b47b10d1b
@metamask-previews/messenger-cli@0.2.0-preview-b47b10d1b
@metamask-previews/money-account-api-data-service@0.1.0-preview-b47b10d1b
@metamask-previews/money-account-balance-service@2.2.0-preview-b47b10d1b
@metamask-previews/money-account-controller@0.3.3-preview-b47b10d1b
@metamask-previews/money-account-upgrade-controller@2.2.1-preview-b47b10d1b
@metamask-previews/multichain-account-service@13.0.0-preview-b47b10d1b
@metamask-previews/multichain-api-middleware@4.0.1-preview-b47b10d1b
@metamask-previews/multichain-network-controller@3.2.1-preview-b47b10d1b
@metamask-previews/multichain-transactions-controller@7.1.1-preview-b47b10d1b
@metamask-previews/name-controller@9.1.2-preview-b47b10d1b
@metamask-previews/network-connection-banner-controller@0.1.0-preview-b47b10d1b
@metamask-previews/network-controller@34.0.0-preview-b47b10d1b
@metamask-previews/network-enablement-controller@5.6.0-preview-b47b10d1b
@metamask-previews/notification-services-controller@25.0.0-preview-b47b10d1b
@metamask-previews/passkey-controller@2.1.0-preview-b47b10d1b
@metamask-previews/permission-controller@13.1.1-preview-b47b10d1b
@metamask-previews/permission-log-controller@5.1.0-preview-b47b10d1b
@metamask-previews/perps-controller@9.2.1-preview-b47b10d1b
@metamask-previews/phishing-controller@17.3.0-preview-b47b10d1b
@metamask-previews/platform-api-docs@0.0.0-preview-b47b10d1b
@metamask-previews/polling-controller@16.0.8-preview-b47b10d1b
@metamask-previews/preferences-controller@23.1.0-preview-b47b10d1b
@metamask-previews/profile-metrics-controller@4.0.2-preview-b47b10d1b
@metamask-previews/profile-sync-controller@28.3.0-preview-b47b10d1b
@metamask-previews/ramps-controller@17.0.0-preview-b47b10d1b
@metamask-previews/rate-limit-controller@7.0.1-preview-b47b10d1b
@metamask-previews/react-data-query@0.2.2-preview-b47b10d1b
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-b47b10d1b
@metamask-previews/sample-controllers@5.0.3-preview-b47b10d1b
@metamask-previews/seedless-onboarding-controller@10.0.3-preview-b47b10d1b
@metamask-previews/selected-network-controller@26.1.5-preview-b47b10d1b
@metamask-previews/sentinel-api-service@1.0.0-preview-b47b10d1b
@metamask-previews/shield-controller@5.1.3-preview-b47b10d1b
@metamask-previews/signature-controller@39.2.7-preview-b47b10d1b
@metamask-previews/smart-transactions-controller@25.0.1-preview-b47b10d1b
@metamask-previews/snap-account-service@2.0.0-preview-b47b10d1b
@metamask-previews/social-controllers@2.5.0-preview-b47b10d1b
@metamask-previews/solana-test-validator-up@1.0.0-preview-b47b10d1b
@metamask-previews/stellar-quickstart-up@0.0.0-preview-b47b10d1b
@metamask-previews/storage-service@1.0.2-preview-b47b10d1b
@metamask-previews/subscription-controller@6.2.1-preview-b47b10d1b
@metamask-previews/transaction-controller@69.0.0-preview-b47b10d1b
@metamask-previews/transaction-pay-controller@25.0.0-preview-b47b10d1b
@metamask-previews/user-operation-controller@41.2.7-preview-b47b10d1b
@metamask-previews/wallet@7.0.1-preview-b47b10d1b
@metamask-previews/wallet-cli@0.0.0-preview-b47b10d1b

@ffmcgee725
ffmcgee725 enabled auto-merge July 21, 2026 06:53
@ffmcgee725
ffmcgee725 added this pull request to the merge queue Jul 21, 2026
Merged via the queue into main with commit 8fe8b1c Jul 21, 2026
427 checks passed
@ffmcgee725
ffmcgee725 deleted the jc/centralize-money-account-balance-fetching branch July 21, 2026 11:24
@cursor cursor Bot mentioned this pull request Jul 21, 2026
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 -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants