Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions packages/assets-controllers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Extend `TokenBalancesController` `isDeprecated` handling to `startPolling`, `updateChainPollingConfigs`, and `TransactionController:transactionConfirmed`, so polling and post-transaction balance fetches are skipped and stale `tokenBalances` are cleared when the controller is deprecated ([#9327](https://github.com/MetaMask/core/pull/9327))
- Bump `@metamask/keyring-api` from `^23.1.0` to `^23.3.0` ([#9249](https://github.com/MetaMask/core/pull/9249))
- Bump `@metamask/transaction-controller` from `^68.1.1` to `^68.2.0` ([#9253](https://github.com/MetaMask/core/pull/9253))
- Bump `@metamask/multichain-account-service` from `^11.0.0` to `^11.1.0` ([#9264](https://github.com/MetaMask/core/pull/9264))
Expand Down
62 changes: 62 additions & 0 deletions packages/assets-controllers/src/TokenBalancesController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,68 @@ describe('TokenBalancesController', () => {

expect(controller.state.tokenBalances).toStrictEqual({});
});

it('does not start polling and clears stale tokenBalances on startPolling when isDeprecated toggles to true at runtime', () => {
let deprecated = false;
const { controller } = setupController({
config: { state: initialState, isDeprecated: () => deprecated },
});

const executePollSpy = jest.spyOn(controller, '_executePoll');

deprecated = true;

controller.startPolling({ chainIds: ['0x1'] });

expect(executePollSpy).not.toHaveBeenCalled();
expect(controller.state.tokenBalances).toStrictEqual({});
});

it('does not restart polling and clears stale tokenBalances on updateChainPollingConfigs when isDeprecated toggles to true at runtime', () => {
jest.useFakeTimers();
let deprecated = false;
const { controller } = setupController({
config: { state: initialState, isDeprecated: () => deprecated },
});

controller.startPolling({ chainIds: ['0x1'] });

const executePollSpy = jest.spyOn(controller, '_executePoll');
executePollSpy.mockClear();

deprecated = true;

controller.updateChainPollingConfigs(
{ '0x1': { interval: 60_000 } },
{ immediateUpdate: true },
);

expect(executePollSpy).not.toHaveBeenCalled();
expect(controller.state.tokenBalances).toStrictEqual({});
});

it('does not fetch and clears stale tokenBalances on TransactionController:transactionConfirmed when isDeprecated toggles to true at runtime', async () => {
let deprecated = false;
const { controller, messenger } = setupController({
config: { state: initialState, isDeprecated: () => deprecated },
});

const fetchSpy = jest.spyOn(
multicall,
'getTokenBalancesForMultipleAddresses',
);

deprecated = true;

messenger.publish('TransactionController:transactionConfirmed', {
chainId: '0x1',
});

await flushPromises();

expect(fetchSpy).not.toHaveBeenCalled();
expect(controller.state.tokenBalances).toStrictEqual({});
});
});

describe('when accountRemoved is published', () => {
Expand Down
30 changes: 23 additions & 7 deletions packages/assets-controllers/src/TokenBalancesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,13 +516,7 @@ export class TokenBalancesController extends StaticIntervalPollingController<{

this.messenger.subscribe(
'TransactionController:transactionConfirmed',
(transactionMeta) => {
this.updateBalances({
chainIds: [transactionMeta.chainId],
}).catch(() => {
// Silently handle balance update errors
});
},
this.#onTransactionConfirmed,
);
}

Expand Down Expand Up @@ -630,6 +624,10 @@ export class TokenBalancesController extends StaticIntervalPollingController<{
};

override _startPolling({ chainIds }: { chainIds: ChainIdHex[] }): void {
if (this.#isDeprecated()) {
this.#enforceDisabledState();
return;
}
this.#requestedChainIds = [...chainIds];
this.#isControllerPollingActive = true;
this.#startIntervalGroupPolling(chainIds, true);
Expand Down Expand Up @@ -759,6 +757,10 @@ export class TokenBalancesController extends StaticIntervalPollingController<{
configs: Record<ChainIdHex, ChainPollingConfig>,
options: UpdateChainPollingConfigsOptions = { immediateUpdate: true },
): void {
if (this.#isDeprecated()) {
this.#enforceDisabledState();
return;
}
Object.assign(this.#chainPollingConfig, configs);

if (this.#isControllerPollingActive) {
Expand Down Expand Up @@ -1428,6 +1430,20 @@ export class TokenBalancesController extends StaticIntervalPollingController<{
});
};

readonly #onTransactionConfirmed = (transactionMeta: {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we move this to a separate function instead of keeping it inline as it was?

chainId: ChainIdHex;
}): void => {
if (this.#isDeprecated()) {
this.#enforceDisabledState();
return;
}
this.updateBalances({
chainIds: [transactionMeta.chainId],
}).catch(() => {
// Silently handle balance update errors
});
};

readonly #onAccountChanged = (): void => {
if (this.#isDeprecated()) {
this.#enforceDisabledState();
Expand Down
Loading