Skip to content

Revert "fix(assets-controller): increase stale and gc time for accounts api request (#9591) - #9870

Merged
salimtb merged 5 commits into
mainfrom
revert/accounts-api-stale-gc-9591
Aug 14, 2026
Merged

Revert "fix(assets-controller): increase stale and gc time for accounts api request (#9591)#9870
salimtb merged 5 commits into
mainfrom
revert/accounts-api-stale-gc-9591

Conversation

@salimtb

@salimtbsalimtb commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This reverts commit 1b082f7.

Extension PR: MetaMask/metamask-extension#45494
Mobile PR: MetaMask/metamask-mobile#34748

Explanation

References

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 refresh behavior on user-visible paths (force refresh); tradeoff is fresher balances vs slightly more Accounts API traffic, with low security impact.

Overview
Reverts #9591: when AccountsApiDataSource handles a balance fetch with forceUpdate: true, TanStack Query options go back to staleTime: 0 and gcTime: 0 instead of a 100ms window.

Forced refreshes (e.g. after unlock, account/network changes, or explicit refresh) are meant to hit the Accounts API with a fresh request; the short cache window could reuse a just-fetched entry and leave balances stale. The unit test is renamed/updated to assert cache bypass on forceUpdate.

The Unreleased changelog documents this revert; it also consolidates the Arc native USDC default-tracking note under Unreleased and drops a duplicate entry from the 13.1.3 section.

Reviewed by Cursor Bugbot for commit ed2395f. Bugbot is set up for automated code reviews on this repo. Configure here.

@salimtbsalimtb changed the title Revert "fix(assets-controller): increase stale and gc time for accoun…Revert "fix(assets-controller): increase stale and gc time for accounts api request (#9591)Aug 13, 2026
salimtb added a commit to MetaMask/metamask-mobile that referenced this pull request Aug 13, 2026
Revert forceUpdate balance cache window from 100ms to staleTime/gcTime
0 so forced refreshes bypass TanStack cache (MetaMask/core#9870).
salimtb added a commit to MetaMask/metamask-extension that referenced this pull request Aug 13, 2026
Revert forceUpdate balance cache window from 100ms to staleTime/gcTime
0 so forced refreshes bypass TanStack cache (MetaMask/core#9870).
@salimtb
salimtb marked this pull request as ready for review August 13, 2026 14:44
@salimtb
salimtb requested review from a team as code ownersAugust 13, 2026 14:44
juanmigdr
juanmigdr previously approved these changes Aug 13, 2026
@salimtb

Copy link
Copy Markdown
ContributorAuthor

@cursor pls merge latest main and address conflict

@cursor

cursorBot commented Aug 14, 2026

Copy link
Copy Markdown

I've successfully merged the latest main branch and resolved the merge conflict. Here's what was done:

Conflict Resolution:

Changes:

  • Created merge commit 160d4c1e89
  • Pushed to revert/accounts-api-stale-gc-9591 branch
  • PR is now mergeable (status: BLOCKED is expected for other requirements)

The branch is now up-to-date with main, and all conflicts are resolved.

Open in WebOpen in Cursor

cursoragentand others added 2 commits August 14, 2026 08:19
Resolved merge conflict in CHANGELOG.md by keeping both Fixed entries:
- Revert of AccountsApiDataSource forceUpdate cache window (#9870)
- Arc native USDC default-tracking fix (#9869)
Co-authored-by: Salim TOUBAL <salimtb@users.noreply.github.com>
@salimtb
salimtb added this pull request to the merge queueAug 14, 2026
Merged via the queue into main with commit f55d3f5Aug 14, 2026
58 checks passed
@salimtb
salimtb deleted the revert/accounts-api-stale-gc-9591 branch August 14, 2026 08:40
runway-githubBot added a commit to MetaMask/metamask-mobile that referenced this pull request Aug 17, 2026
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
comment but do not block the PR.
Sections without a directive are checked for structural presence only.
-->
## **Description**
This PR removes cache usage when requesting the Account API to fetch
balances, ensuring that forceUpdate calls result in a real network
request rather than a near-immediate cache hit.
Currently, AccountsApiDataSource uses { staleTime: 100, gcTime: 100 }
for all fetches — including forced ones. This means that even when
forceUpdate: true is set (e.g. via AssetsController.getAssets), React
Query may return stale cached data within the 100ms window instead of
hitting the network. This is incorrect behavior for an explicit
force-refresh path.
The fix patches @metamask/assets-controller@13.1.3 so that when
request.forceUpdate is set, fetchOptions uses { staleTime: 0, gcTime: 0
} — bypassing the cache entirely and guaranteeing a fresh network fetch.
Both .cjs and .mjs builds are patched, and package.json (resolutions +
dependencies) and yarn.lock are updated accordingly.
Core PR: MetaMask/core#9870
<!-- mms-check: type=text required=true -->
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!-- mms-check: type=changelog required=true blocking=true -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: remove account api cache
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes:
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Force-refresh account balances bypass cache
Scenario: User triggers a forced balance refresh
Given the app is open with at least one account with token balances
And the account API has been called at least once (cache is warm)
When a force-refresh is triggered (e.g. pull-to-refresh or returning to the wallet tab)
Then the app fetches fresh balances from the network
And the balance displayed reflects the latest on-chain state, not a cached value
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
https://github.com/user-attachments/assets/593c8a93-5f6d-4f79-ae9f-848d47bca240
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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]
> **Low Risk**
> Small behavioral change in dependency caching for explicit
force-refresh only; slightly more API traffic on those paths but no auth
or data-model changes.
> > **Overview**
> **Patches `@metamask/assets-controller@13.1.3`** so forced
account/asset fetches actually skip the React Query cache instead of
reusing data for ~100ms.
> > In `AccountsApiDataSource`, when `request.forceUpdate` is set,
`fetchOptions` changes from `{ staleTime: 100, gcTime: 100 }` to **`{
staleTime: 0, gcTime: 0 }`** (both `.cjs` and `.mjs` builds). That
aligns “force update” paths—such as `AssetsController.getAssets` with
`forceUpdate: true`—with a real network refresh rather than a
near-immediate cache hit.
> > Wiring is updated in **`package.json`** (`resolutions` +
`dependencies`) and **`yarn.lock`** so the app resolves the patched
package instead of the stock npm release.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a26f683. 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 <cursoragent@cursor.com>
runway-githubBot added a commit to MetaMask/metamask-mobile that referenced this pull request Aug 17, 2026
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
comment but do not block the PR.
Sections without a directive are checked for structural presence only.
-->
## **Description**
This PR removes cache usage when requesting the Account API to fetch
balances, ensuring that forceUpdate calls result in a real network
request rather than a near-immediate cache hit.
Currently, AccountsApiDataSource uses { staleTime: 100, gcTime: 100 }
for all fetches — including forced ones. This means that even when
forceUpdate: true is set (e.g. via AssetsController.getAssets), React
Query may return stale cached data within the 100ms window instead of
hitting the network. This is incorrect behavior for an explicit
force-refresh path.
The fix patches @metamask/assets-controller@13.1.3 so that when
request.forceUpdate is set, fetchOptions uses { staleTime: 0, gcTime: 0
} — bypassing the cache entirely and guaranteeing a fresh network fetch.
Both .cjs and .mjs builds are patched, and package.json (resolutions +
dependencies) and yarn.lock are updated accordingly.
Core PR: MetaMask/core#9870
<!-- mms-check: type=text required=true -->
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!-- mms-check: type=changelog required=true blocking=true -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: remove account api cache
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes:
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Force-refresh account balances bypass cache
Scenario: User triggers a forced balance refresh
Given the app is open with at least one account with token balances
And the account API has been called at least once (cache is warm)
When a force-refresh is triggered (e.g. pull-to-refresh or returning to the wallet tab)
Then the app fetches fresh balances from the network
And the balance displayed reflects the latest on-chain state, not a cached value
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
https://github.com/user-attachments/assets/593c8a93-5f6d-4f79-ae9f-848d47bca240
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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]
> **Low Risk**
> Small behavioral change in dependency caching for explicit
force-refresh only; slightly more API traffic on those paths but no auth
or data-model changes.
> > **Overview**
> **Patches `@metamask/assets-controller@13.1.3`** so forced
account/asset fetches actually skip the React Query cache instead of
reusing data for ~100ms.
> > In `AccountsApiDataSource`, when `request.forceUpdate` is set,
`fetchOptions` changes from `{ staleTime: 100, gcTime: 100 }` to **`{
staleTime: 0, gcTime: 0 }`** (both `.cjs` and `.mjs` builds). That
aligns “force update” paths—such as `AssetsController.getAssets` with
`forceUpdate: true`—with a real network refresh rather than a
near-immediate cache hit.
> > Wiring is updated in **`package.json`** (`resolutions` +
`dependencies`) and **`yarn.lock`** so the app resolves the patched
package instead of the stock npm release.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a26f683. 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 <cursoragent@cursor.com>
runway-githubBot added a commit to MetaMask/metamask-mobile that referenced this pull request Aug 17, 2026
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
comment but do not block the PR.
Sections without a directive are checked for structural presence only.
-->
## **Description**
This PR removes cache usage when requesting the Account API to fetch
balances, ensuring that forceUpdate calls result in a real network
request rather than a near-immediate cache hit.
Currently, AccountsApiDataSource uses { staleTime: 100, gcTime: 100 }
for all fetches — including forced ones. This means that even when
forceUpdate: true is set (e.g. via AssetsController.getAssets), React
Query may return stale cached data within the 100ms window instead of
hitting the network. This is incorrect behavior for an explicit
force-refresh path.
The fix patches @metamask/assets-controller@13.1.3 so that when
request.forceUpdate is set, fetchOptions uses { staleTime: 0, gcTime: 0
} — bypassing the cache entirely and guaranteeing a fresh network fetch.
Both .cjs and .mjs builds are patched, and package.json (resolutions +
dependencies) and yarn.lock are updated accordingly.
Core PR: MetaMask/core#9870
<!-- mms-check: type=text required=true -->
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!-- mms-check: type=changelog required=true blocking=true -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: remove account api cache
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes:
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Force-refresh account balances bypass cache
Scenario: User triggers a forced balance refresh
Given the app is open with at least one account with token balances
And the account API has been called at least once (cache is warm)
When a force-refresh is triggered (e.g. pull-to-refresh or returning to the wallet tab)
Then the app fetches fresh balances from the network
And the balance displayed reflects the latest on-chain state, not a cached value
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
https://github.com/user-attachments/assets/593c8a93-5f6d-4f79-ae9f-848d47bca240
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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]
> **Low Risk**
> Small behavioral change in dependency caching for explicit
force-refresh only; slightly more API traffic on those paths but no auth
or data-model changes.
> > **Overview**
> **Patches `@metamask/assets-controller@13.1.3`** so forced
account/asset fetches actually skip the React Query cache instead of
reusing data for ~100ms.
> > In `AccountsApiDataSource`, when `request.forceUpdate` is set,
`fetchOptions` changes from `{ staleTime: 100, gcTime: 100 }` to **`{
staleTime: 0, gcTime: 0 }`** (both `.cjs` and `.mjs` builds). That
aligns “force update” paths—such as `AssetsController.getAssets` with
`forceUpdate: true`—with a real network refresh rather than a
near-immediate cache hit.
> > Wiring is updated in **`package.json`** (`resolutions` +
`dependencies`) and **`yarn.lock`** so the app resolves the patched
package instead of the stock npm release.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a26f683. 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 <cursoragent@cursor.com>
runway-githubBot added a commit to MetaMask/metamask-mobile that referenced this pull request Aug 17, 2026
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
comment but do not block the PR.
Sections without a directive are checked for structural presence only.
-->
## **Description**
This PR removes cache usage when requesting the Account API to fetch
balances, ensuring that forceUpdate calls result in a real network
request rather than a near-immediate cache hit.
Currently, AccountsApiDataSource uses { staleTime: 100, gcTime: 100 }
for all fetches — including forced ones. This means that even when
forceUpdate: true is set (e.g. via AssetsController.getAssets), React
Query may return stale cached data within the 100ms window instead of
hitting the network. This is incorrect behavior for an explicit
force-refresh path.
The fix patches @metamask/assets-controller@13.1.3 so that when
request.forceUpdate is set, fetchOptions uses { staleTime: 0, gcTime: 0
} — bypassing the cache entirely and guaranteeing a fresh network fetch.
Both .cjs and .mjs builds are patched, and package.json (resolutions +
dependencies) and yarn.lock are updated accordingly.
Core PR: MetaMask/core#9870
<!-- mms-check: type=text required=true -->
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!-- mms-check: type=changelog required=true blocking=true -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: remove account api cache
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes:
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Force-refresh account balances bypass cache
Scenario: User triggers a forced balance refresh
Given the app is open with at least one account with token balances
And the account API has been called at least once (cache is warm)
When a force-refresh is triggered (e.g. pull-to-refresh or returning to the wallet tab)
Then the app fetches fresh balances from the network
And the balance displayed reflects the latest on-chain state, not a cached value
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
https://github.com/user-attachments/assets/593c8a93-5f6d-4f79-ae9f-848d47bca240
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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]
> **Low Risk**
> Small behavioral change in dependency caching for explicit
force-refresh only; slightly more API traffic on those paths but no auth
or data-model changes.
> > **Overview**
> **Patches `@metamask/assets-controller@13.1.3`** so forced
account/asset fetches actually skip the React Query cache instead of
reusing data for ~100ms.
> > In `AccountsApiDataSource`, when `request.forceUpdate` is set,
`fetchOptions` changes from `{ staleTime: 100, gcTime: 100 }` to **`{
staleTime: 0, gcTime: 0 }`** (both `.cjs` and `.mjs` builds). That
aligns “force update” paths—such as `AssetsController.getAssets` with
`forceUpdate: true`—with a real network refresh rather than a
near-immediate cache hit.
> > Wiring is updated in **`package.json`** (`resolutions` +
`dependencies`) and **`yarn.lock`** so the app resolves the patched
package instead of the stock npm release.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a26f683. 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 <cursoragent@cursor.com>
runway-githubBot added a commit to MetaMask/metamask-mobile that referenced this pull request Aug 17, 2026
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
comment but do not block the PR.
Sections without a directive are checked for structural presence only.
-->
## **Description**
This PR removes cache usage when requesting the Account API to fetch
balances, ensuring that forceUpdate calls result in a real network
request rather than a near-immediate cache hit.
Currently, AccountsApiDataSource uses { staleTime: 100, gcTime: 100 }
for all fetches — including forced ones. This means that even when
forceUpdate: true is set (e.g. via AssetsController.getAssets), React
Query may return stale cached data within the 100ms window instead of
hitting the network. This is incorrect behavior for an explicit
force-refresh path.
The fix patches @metamask/assets-controller@13.1.3 so that when
request.forceUpdate is set, fetchOptions uses { staleTime: 0, gcTime: 0
} — bypassing the cache entirely and guaranteeing a fresh network fetch.
Both .cjs and .mjs builds are patched, and package.json (resolutions +
dependencies) and yarn.lock are updated accordingly.
Core PR: MetaMask/core#9870
<!-- mms-check: type=text required=true -->
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!-- mms-check: type=changelog required=true blocking=true -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: remove account api cache
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes:
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Force-refresh account balances bypass cache
Scenario: User triggers a forced balance refresh
Given the app is open with at least one account with token balances
And the account API has been called at least once (cache is warm)
When a force-refresh is triggered (e.g. pull-to-refresh or returning to the wallet tab)
Then the app fetches fresh balances from the network
And the balance displayed reflects the latest on-chain state, not a cached value
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
https://github.com/user-attachments/assets/593c8a93-5f6d-4f79-ae9f-848d47bca240
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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]
> **Low Risk**
> Small behavioral change in dependency caching for explicit
force-refresh only; slightly more API traffic on those paths but no auth
or data-model changes.
> > **Overview**
> **Patches `@metamask/assets-controller@13.1.3`** so forced
account/asset fetches actually skip the React Query cache instead of
reusing data for ~100ms.
> > In `AccountsApiDataSource`, when `request.forceUpdate` is set,
`fetchOptions` changes from `{ staleTime: 100, gcTime: 100 }` to **`{
staleTime: 0, gcTime: 0 }`** (both `.cjs` and `.mjs` builds). That
aligns “force update” paths—such as `AssetsController.getAssets` with
`forceUpdate: true`—with a real network refresh rather than a
near-immediate cache hit.
> > Wiring is updated in **`package.json`** (`resolutions` +
`dependencies`) and **`yarn.lock`** so the app resolves the patched
package instead of the stock npm release.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a26f683. 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 <cursoragent@cursor.com>
pullBot pushed a commit to Reality2byte/metamask-mobile that referenced this pull request Aug 17, 2026
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
comment but do not block the PR.
Sections without a directive are checked for structural presence only.
-->
## **Description**
This PR removes cache usage when requesting the Account API to fetch
balances, ensuring that forceUpdate calls result in a real network
request rather than a near-immediate cache hit.
Currently, AccountsApiDataSource uses { staleTime: 100, gcTime: 100 }
for all fetches — including forced ones. This means that even when
forceUpdate: true is set (e.g. via AssetsController.getAssets), React
Query may return stale cached data within the 100ms window instead of
hitting the network. This is incorrect behavior for an explicit
force-refresh path.
The fix patches @metamask/assets-controller@13.1.3 so that when
request.forceUpdate is set, fetchOptions uses { staleTime: 0, gcTime: 0
} — bypassing the cache entirely and guaranteeing a fresh network fetch.
Both .cjs and .mjs builds are patched, and package.json (resolutions +
dependencies) and yarn.lock are updated accordingly.
Core PR: MetaMask/core#9870
<!-- mms-check: type=text required=true -->
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!-- mms-check: type=changelog required=true blocking=true -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: remove account api cache
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes:
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Force-refresh account balances bypass cache
Scenario: User triggers a forced balance refresh
Given the app is open with at least one account with token balances
And the account API has been called at least once (cache is warm)
When a force-refresh is triggered (e.g. pull-to-refresh or returning to the wallet tab)
Then the app fetches fresh balances from the network
And the balance displayed reflects the latest on-chain state, not a cached value
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
https://github.com/user-attachments/assets/593c8a93-5f6d-4f79-ae9f-848d47bca240
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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]
> **Low Risk**
> Small behavioral change in dependency caching for explicit
force-refresh only; slightly more API traffic on those paths but no auth
or data-model changes.
> > **Overview**
> **Patches `@metamask/assets-controller@13.1.3`** so forced
account/asset fetches actually skip the React Query cache instead of
reusing data for ~100ms.
> > In `AccountsApiDataSource`, when `request.forceUpdate` is set,
`fetchOptions` changes from `{ staleTime: 100, gcTime: 100 }` to **`{
staleTime: 0, gcTime: 0 }`** (both `.cjs` and `.mjs` builds). That
aligns “force update” paths—such as `AssetsController.getAssets` with
`forceUpdate: true`—with a real network refresh rather than a
near-immediate cache hit.
> > Wiring is updated in **`package.json`** (`resolutions` +
`dependencies`) and **`yarn.lock`** so the app resolves the patched
package instead of the stock npm release.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a26f683. 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 <cursoragent@cursor.com>
sleepytanya pushed a commit to MetaMask/metamask-mobile that referenced this pull request Aug 17, 2026
- fix: fix account api cache cp-8.8.0 (#34748)
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.
type=text Section must contain non-placeholder prose.
type=changelog Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
comment but do not block the PR.
Sections without a directive are checked for structural presence only.
-->
## **Description**
This PR removes cache usage when requesting the Account API to fetch
balances, ensuring that forceUpdate calls result in a real network
request rather than a near-immediate cache hit.
Currently, AccountsApiDataSource uses { staleTime: 100, gcTime: 100 }
for all fetches — including forced ones. This means that even when
forceUpdate: true is set (e.g. via AssetsController.getAssets), React
Query may return stale cached data within the 100ms window instead of
hitting the network. This is incorrect behavior for an explicit
force-refresh path.
The fix patches @metamask/assets-controller@13.1.3 so that when
request.forceUpdate is set, fetchOptions uses { staleTime: 0, gcTime: 0
} — bypassing the cache entirely and guaranteeing a fresh network fetch.
Both .cjs and .mjs builds are patched, and package.json (resolutions +
dependencies) and yarn.lock are updated accordingly.
Core PR: MetaMask/core#9870
<!-- mms-check: type=text required=true -->
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!-- mms-check: type=changelog required=true blocking=true -->
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: remove account api cache
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes:
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Feature: Force-refresh account balances bypass cache
Scenario: User triggers a forced balance refresh
Given the app is open with at least one account with token balances
And the account API has been called at least once (cache is warm)
When a force-refresh is triggered (e.g. pull-to-refresh or returning to the wallet tab)
Then the app fetches fresh balances from the network
And the balance displayed reflects the latest on-chain state, not a cached value
```
## **Screenshots/Recordings**
<!-- mms-check: type=screenshot required=true -->
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
https://github.com/user-attachments/assets/593c8a93-5f6d-4f79-ae9f-848d47bca240
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!-- mms-check: type=checklist required=true -->
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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]
> **Low Risk**
> Small behavioral change in dependency caching for explicit
force-refresh only; slightly more API traffic on those paths but no auth
or data-model changes.
> > **Overview**
> **Patches `@metamask/assets-controller@13.1.3`** so forced
account/asset fetches actually skip the React Query cache instead of
reusing data for ~100ms.
> > In `AccountsApiDataSource`, when `request.forceUpdate` is set,
`fetchOptions` changes from `{ staleTime: 100, gcTime: 100 }` to **`{
staleTime: 0, gcTime: 0 }`** (both `.cjs` and `.mjs` builds). That
aligns “force update” paths—such as `AssetsController.getAssets` with
`forceUpdate: true`—with a real network refresh rather than a
near-immediate cache hit.
> > Wiring is updated in **`package.json`** (`resolutions` +
`dependencies`) and **`yarn.lock`** so the app resolves the patched
package instead of the stock npm release.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a26f683. 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 <cursoragent@cursor.com>
[682db20](682db20)
Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
pullBot pushed a commit to firas9941/metamask-mobile that referenced this pull request Aug 20, 2026
## **Description**
`AccountsApiDataSource`'s recurring balance poll (`pollInterval`
defaults to 30s) fetches balances via `@metamask/core-backend`'s
`ApiPlatformClient`, which caches balance responses with
`STALE_TIMES.BALANCES = 60s`. Because the poll's `fetch()` call didn't
set `forceUpdate`, roughly half of its 30s ticks were silently served a
cached response instead of hitting the network — so balances fetched via
the Accounts API fallback (used when the backend websocket connection is
degraded/unavailable) were effectively only refreshed every ~60s instead
of the intended 30s.
This patches `@metamask/assets-controller`'s `AccountsApiDataSource`
(both `.cjs`/`.mjs` build outputs, via the existing `.yarn/patches`
mechanism for this package) to pass `forceUpdate: true` on every poll
tick, so each 30s tick always bypasses the cache (`staleTime: 0, gcTime:
0`) and issues a real request.
Also re-applies the pre-existing `staleTime`/`gcTime` `100ms → 0ms` fix
for the `forceUpdate` branch, which had to be reapplied because `yarn
patch`/`yarn patch-commit` extracts from the unpatched base package when
regenerating a patch.
Checked whether upstream `@metamask/core`
[MetaMask#9870](MetaMask/core#9870) (released in
`13.1.4`) already covers this — it doesn't; that PR only reverts the
`forceUpdate`-path cache window and is unrelated to the periodic-poll
cache-staleness gap this PR addresses.
## **Changelog**
CHANGELOG entry: Fixed a bug where token balances fetched via the
Accounts API polling fallback refreshed only every ~60 seconds instead
of the intended 30 seconds
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Accounts API balance polling cadence
Scenario: Balances refresh every 30 seconds via the Accounts API fallback
Given the backend websocket connection is unavailable or disabled
And the wallet is unlocked with active accounts and enabled chains
When 30 seconds elapse
Then a new balance request is sent to the Accounts API (accounts.api.cx.metamask.io)
When another 30 seconds elapse
Then another new balance request is sent to the Accounts API (not served from cache)
```
## **Screenshots/Recordings**
N/A — non-visual fix to a vendored dependency's data-fetching cadence;
verified via console instrumentation showing `pollFn` fetch durations
(~600ms network round-trip) on every 30s tick instead of alternating
with ~10ms cache-hit ticks.
### **Before**
N/A
### **After**
https://github.com/user-attachments/assets/19f6744b-0cb1-443b-9f3c-a646e0a701ae
## **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
- [x] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **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**
> Changes how often live token balances are fetched via the Accounts API
fallback, which can increase API traffic and affect displayed balances.
Scope is a small vendored-dependency patch, not auth or core wallet
logic.
> > **Overview**
> Fixes Accounts API fallback polling so token balances refresh on the
intended ~30s cadence instead of being served from a 60s cache.
> > The existing `@metamask/assets-controller` yarn patch now passes
`forceUpdate: true` on each recurring poll tick in
`AccountsApiDataSource` (CJS and ESM). Combined with
`staleTime`/`gcTime` of `0` on the force-update path (reapplied because
regenerating the patch reset that earlier change), every tick issues a
real network request instead of a cached hit.
> > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f97df07. 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 freeto 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.

3 participants

@salimtb@juanmigdr@cursoragent