Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix: fix cursor comments
  • Loading branch information
salimtb committed Dec 13, 2025
commit cb4a07d593a77975e745011ec831f95df18a46ff
3 changes: 3 additions & 0 deletions packages/assets-controllers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix `TokenDetectionController` methods `addDetectedTokensViaPolling` and `addDetectedTokensViaWs` to refresh token metadata cache before use ([#7469](https://github.com/MetaMask/core/pull/7469))
- Previously, these methods used a potentially stale/empty `#tokensChainsCache` from construction time
- Now they fetch the latest `tokensChainsCache` from `TokenListController:getState` before looking up token metadata
- Fix `AccountTrackerController.syncBalanceWithAddresses` to also check `isOnboarded()` before fetching balances ([#7469](https://github.com/MetaMask/core/pull/7469))
- Previously, only `#refreshAccounts` checked `isOnboarded()`, but `syncBalanceWithAddresses` would still make RPC calls during onboarding
- Now `syncBalanceWithAddresses` returns an empty object when `isOnboarded()` returns `false`

## [94.0.0]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,71 @@ describe('AccountTrackerController', () => {
},
);
});

it('should skip balance fetching when isOnboarded returns false', async () => {
await withController(
{
options: { isOnboarded: () => false },
isMultiAccountBalancesEnabled: true,
selectedAccount: ACCOUNT_1,
listAccounts: [],
},
async ({ controller }) => {
// Reset query mock to track calls
mockedQuery.mockClear();

const result = await controller.syncBalanceWithAddresses([
ADDRESS_1,
ADDRESS_2,
]);

// Should return empty object without making any RPC calls
expect(result).toStrictEqual({});

// Verify no RPC calls were made (query should not have been called for getBalance)
expect(mockedQuery).not.toHaveBeenCalled();
},
);
});

it('should evaluate isOnboarded dynamically at call time', async () => {
let onboarded = false;

await withController(
{
options: { isOnboarded: () => onboarded },
isMultiAccountBalancesEnabled: true,
selectedAccount: ACCOUNT_1,
listAccounts: [],
},
async ({ controller }) => {
// First call: isOnboarded returns false, should skip fetching
mockedQuery.mockClear();

const result1 = await controller.syncBalanceWithAddresses([
ADDRESS_1,
]);

// Should return empty object
expect(result1).toStrictEqual({});
expect(mockedQuery).not.toHaveBeenCalled();

// Now set onboarded to true
onboarded = true;

mockedQuery.mockReturnValueOnce(Promise.resolve('0xabc123'));

// Second call: isOnboarded now returns true, should fetch balances
const result2 = await controller.syncBalanceWithAddresses([
ADDRESS_1,
]);

// Should have fetched balance
expect(result2[ADDRESS_1].balance).toBe('0xabc123');
expect(mockedQuery).toHaveBeenCalled();
},
);
});
});

it('should call refresh every interval on polling', async () => {
Expand Down
5 changes: 5 additions & 0 deletions packages/assets-controllers/src/AccountTrackerController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,11 @@ export class AccountTrackerController extends StaticIntervalPollingController<Ac
): Promise<
Record<string, { balance: string; stakedBalance?: StakedBalance }>
> {
// Skip balance fetching if not onboarded to avoid unnecessary RPC calls during onboarding
if (!this.#isOnboarded()) {
return {};
}

const { ethQuery } = this.#getCorrectNetworkClient(networkClientId);

// TODO: This should use multicall when enabled by the user.
Expand Down
Loading