Repository navigation
test(assets-controller): add stale-balance scenario integration tests for accounts API v6 - #10584
Conversation
… for accounts API v6 Cover all 12 stale-balance scenarios documented in the accounts API v6 integration decision doc (7 `full` + 5 `merge`), booting the real AssetsController with mocked external boundaries: nock for the Accounts / tokens / prices HTTP APIs, and mock messenger action handlers for RPC, snap, and lifecycle events. Fixtures build on real API captures, with every fixture mutation documented inline.
…-balance suite Follow the shared-utils schema of the other AssetsController integration suites: `getIgnoringCase` moves to `__fixtures__/test-utils.ts` instead of a per-suite copy, and the account builders in `__fixtures__/stale-balance/staleBalanceWallet.ts` delegate to the shared `createMockInternalAccount` (as `AssetsController.spam-cleanup.integration test.ts` does) rather than hand-rolling `InternalAccount` boilerplate.
…teSurface assertion utils - The Multicall3 `aggregate3` fixture no longer prefixes a `blockNumber` `uint256` before the results array: the real contract returns `Result[]` only (only `aggregate`/`tryAggregate` return a block number), so the batched read path now decodes instead of silently falling back to single `balanceOf` calls (review finding). - Amount assertions now go through `StateSurface`-style utils (`buildBalancesSurface` + per-account `SOLANA_BALANCES`/`BSC_BALANCES`/ `MAINNET_BALANCES`), matching the other AssetsController integration suites.
…cenario describe Adopt the exact `StateSurface` pattern of the bsc-spam integration suite: a bare `type StateSurface` and a `const BALANCES: StateSurface` whose lookUp binds the account's balances record — copied verbatim into each scenario describe (the wallet spans three accounts, so each describe binds its own), replacing the `buildBalancesSurface` factory.
…fix, and verbatim StateSurface utils The three commits below (d3c9d4f, 48b3abd, 1c100ff) landed empty — their changes were never staged before the plumbing commit, so only the SHAs moved. This commit actually lands their changes: - Reuse the shared integration-test utils: consolidate `getIgnoringCase` into `__fixtures__/test-utils.ts` and delegate the account builders in `staleBalanceWallet.ts` to the shared `createMockInternalAccount`. - Fix the Multicall3 `aggregate3` fixture's wire shape: drop the `blockNumber` `uint256` prefix — the real contract returns `Result[]` only, so the batched read path decodes instead of silently falling back to single `balanceOf` calls. - Copy the bsc-spam suite's `StateSurface` utils verbatim: bare `type StateSurface` and a `const BALANCES: StateSurface` per scenario describe (this wallet spans three accounts), with all amount assertions reading `surface.lookUp`.
Assert with the bsc-spam-token exemplar dialect (direct BALANCES.lookUp(...).toMatchObject, inline key-set checks) instead of the invented expectAmount/expectedAmount/lowerKeySet helpers; carry-over states inline via buildEmptyStaleBalanceState. Drop all banner separators and rationale comments from the suite and the __fixtures__/stale-balance helpers, keeping one-to-two-line summaries only; remove the dead USDT_ASSET_ID_LOWERCASE constant.
…e-this-sp0 # Conflicts: # packages/assets-controller/src/__fixtures__/test-utils.ts
Per review: add getAssetIds and lookupAmount to each describe's BALANCES surface so the repeated lower-cased key-set checks and amount assertions read expect(BALANCES.getAssetIds(state)).toStrictEqual(...) and expect(BALANCES.lookupAmount(state, assetId)).toBe(...) across every scenario. Drop the scenario-3 key-set check (redundant with its balance assertions) and replace scenario-11's with a direct USDC amount assertion; S5/S8/S9/S10 key-sets now compare surfaces of captured states.
…r-stale-balance-scenarios
|
Mainly looked packages/assets-controller/src/AssetsController.stale-balance-scenarios.integration.test.ts and that looks good to me 👍 |
Thanks @Kriys94 - yep this was the main file that needed review. Good call on realistic data capture - I'm re-executing this now. |
…ted API captures Re-executed every capture query behind the stale-balance suite against the live APIs and rebuilt the fixture files from the 2026-09-30 responses, so each fixture is a verbatim capture whose header links the exact query made, including the asset ID lists for the v3 spot-price and asset queries. The accounts /v2/supportedNetworks capture now keeps solana in partialSupport as the live API returns it; the keyring snap still owns the Solana account in the suite (all 12 scenarios pass). Spot prices and a few drifted balances refresh to the new capture; USDT/GTAI/BNB/ETH rows are byte-identical to the previous capture.
…r-stale-balance-scenarios
Main added a lint:tsc:check job that compares repo-wide tsc errors against tsc-suppressions.json. The stale-balance suite files carry pre-existing latent test-file type errors that no CI job previously checked, so the new gate fails without suppressions. Merge main to pick up the tooling and record the 14 errors across the 5 suite files with the repo's own lint:tsc:check --suppress-all script.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8bef618. Configure here.
|
While re-capturing the fixtures I also fixed the newly-failing
Fix (8bef618): synced main to pick up the tooling and suppressions file, then recorded the 14 errors with the repo's own |
…f suppressing
Rather than adding the suite's 14 latent test-file type errors to
tsc-suppressions.json, fix them in place:
- Give V6BalanceEntry a structural type so the bsc-derived literal type
stops rejecting mainnet rows, balance-replacement spreads, and the
zero-balance stub.
- Annotate mockStaleBalanceApis's options with the shared
StaleBalanceApiMutations type; they were inferred as never[]/{}.
- Complete the account metadata in the wallet builders with keyring
and importTime defaults, mirroring createMockInternalAccount.
- Complete the transactionConfirmed payload's TransactionMeta fields
(id, networkClientId, status, time).
- Cast defaultAbiCoder.encode's result to Hex; it always returns hex.
Keep @ts-expect-error only for the deliberately malformed balance
rows and Hoodi's zero-address ERC-20 native-asset fallback, which the
extension itself uses for chains missing from the slip44 map.
Drop the tsc-suppressions.json entries added in 8bef618.
|
Follow-up on the
Verified: |

Explanation
Adds
AssetsController.stale-balance-scenarios.integration.test.ts, an AssetsController-level integration suite covering all 12 stale-balance scenarios from the accounts API v6 integration decision doc (fullandmergetables).The suite boots the real
AssetsController(withassetsAccountsApiV6: true) and mocks only the external boundaries, following the pattern ofAssetsController.bsc-spam-token-filtering.integration.test.ts:Accounts APIv6 + v2-supportedNetworks, tokens/v3/assets, prices/v3/spot-prices) are nocked from real captured responses insrc/__fixtures__/stale-balance/api-responses/. Every fixture mutation is documented inline (balance doubling to model wallet movement between passes,occurrencesstamping, chain omissions for RPC fallback).NetworkController,SnapController,KeyringController, staking reads) and live events (AccountActivityService:balanceUpdated,AccountsController:accountBalancesUpdated,TransactionController:transactionConfirmed,KeyringController:unlock).Scenario coverage (7
full+ 5merge): snap failure carry-over, skipped-asset last-amount copy, zero-seeding for never-seen visible assets, RPC fallback carry-over on failingbalanceOfreads, disappearing zero-balance seeds, failed-fetch carry-over, fresh amounts on healthy fallback, event overlays, malformed-row handling, wrong-amount correction at the next full poll, snap-event overlay + refresh, and staked ETH on mainnet + Hoodi across an unlock lifecycle with a staking deposit.Test plan
yarn workspace @metamask/assets-controller run testyarn lintchecks on the new files: oxlint and oxfmt cleanyarn build(root, full monorepo type-check) passesNotes for reviewers
unit, required by the keyring API'sBalancestruct viastrictMask(@metamask/keyring-api); the controller discards it downstream.eip155:560048/erc20:0x0000000000000000000000000000000000000000) — the controller's documented fallback for EVM chains absent from its native-asset seed map, which excludes testnets.aggregate3fixture encodes the contract's real return shape —Result[]only, with no leadingblockNumber(onlyaggregate/tryAggregatereturn one). An earlier draft of the fixture encoded(uint256, Result[]), which made every batch decode throw and silently fall through to singlebalanceOfcalls; caught in review and fixed, so the scenarios exercise the batched read path.MulticallClient's decoder is correct as shipped — no product bug here.References
Validate changelog diffsjob can resolveorigin/<head-ref>(the fork-PR limitation documented in that PR).Checklist
no-changeloglabel applied)Note
Low Risk
Test-only additions with mocked boundaries; no changes to runtime balance merge or fetch behavior shipped to consumers.
Overview
Adds
AssetsController.stale-balance-scenarios.integration.test.ts, an integration suite that runs the realAssetsControllerwithassetsAccountsApiV6: trueand exercises all 12 stale-balance scenarios from the accounts API v6 decision doc (Solana snap failures/skips, BNB Chain RPC fallback when v6 marks a chain unprocessed, Account Activity live overlays/malformed rows, and staked ETH across mainnet + Hoodi after unlock and a staking tx).Supporting changes introduce a
__fixtures__/stale-balance/tree: real HTTP captures for Accounts/Tokens/Prices APIs wired throughmockStaleBalanceApis, mutable mock EVM RPC (Multicall3aggregate3, failing tokens, staking reads), Solana keyring snap handlers, wallet/account builders, and messenger registration for BSC/mainnet/Hoodi networks.getIgnoringCaseis added totest-utilsfor case-insensitive balance assertions, andtsc-suppressions.jsonpicks up suppressions for fixture/test typing.There is no production logic change in this PR—only tests, fixtures, and type suppressions.
Reviewed by Cursor Bugbot for commit 245e36c. Bugbot is set up for automated code reviews on this repo. Configure here.