Skip to content

Conversation

@Kriys94
Copy link
Contributor

@Kriys94 Kriys94 commented Jan 29, 2026

Explanation

This PR adds support for hidden assets in the AssetsController, similar to how allIgnoredAssets works in MultichainAssetsController.

Current State:
Users currently have no way to hide assets they don't want to see or track in the new AssetsController architecture. The MultichainAssetsController already has this capability via allIgnoredAssets, but the new unified AssetsController was missing this feature.

Solution:
Added a hiddenAssets field to the AssetsController state that stores hidden assets per account (CAIP-19 asset IDs). This allows users to hide assets they don't want to track and/or see.

Changes:

  1. State: Added hiddenAssets: { [accountId: string]: string[] } to AssetsControllerState
  2. Methods: Added hideAsset(), unhideAsset(), getHiddenAssets(), and isAssetHidden() methods
  3. Actions: Added corresponding action types (AssetsControllerHideAssetAction, AssetsControllerUnhideAssetAction, AssetsControllerGetHiddenAssetsAction) and registered handlers
  4. Custom Assets Integration: When a custom asset is added via addCustomAsset(), it's automatically unhidden if it was previously hidden (matching the behavior of MultichainAssetsController.addAssets())
  5. RPC Tracking: Updated RpcDataSource and BalanceFetcher to filter out hidden assets from balance polling, so hidden assets won't be tracked or updated

Type Updates:

  • Added hiddenAssets to AssetsControllerState
  • Added hiddenAssets to AssetsControllerStateInternal
  • Added hiddenAssets to AssetsBalanceState in evm-rpc-services types

References

  • Related to the Hide Token feature for the new unified AssetsController architecture
  • Pattern follows allIgnoredAssets in MultichainAssetsController

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
Medium risk: introduces new persisted controller state and new messenger actions that change balance polling behavior by filtering out hidden assets, which could impact what assets are tracked/displayed if misapplied.

Overview
Adds a persisted hiddenAssets map to AssetsController state and exports new messenger actions to hideAsset, unhideAsset, and getHiddenAssets (plus an isAssetHidden helper).

Updates addCustomAsset to automatically unhide an asset when it’s re-added, wires hiddenAssets through RpcDataSourceBalanceFetcher, and filters hidden asset IDs out of token balance polling. Tests and shared types are updated to include the new state shape.

Written by Cursor Bugbot for commit ea074cb. This will update automatically on new commits. Configure here.

@Kriys94 Kriys94 marked this pull request as ready for review January 29, 2026 15:25
@Kriys94 Kriys94 requested a review from a team as a code owner January 29, 2026 15:25
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

this.state.hiddenAssets[accountId]?.includes(normalizedAssetId) ?? false
);
}

Copy link

Choose a reason for hiding this comment

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

getAssets does not filter out hidden assets

High Severity

The hideAsset method's JSDoc states "Hidden assets are excluded from the asset list returned by getAssets", but #getAssetsFromState doesn't actually filter hidden assets. The method iterates through accountBalances and filters by chain, metadata, and asset type, but never checks this.state.hiddenAssets[account.id] to skip hidden assets. Users who hide assets will still see them returned by getAssets(), completely defeating the feature's purpose.

Additional Locations (1)

Fix in Cursor Fix in Web

return (
this.state.hiddenAssets[accountId]?.includes(normalizedAssetId) ?? false
);
}
Copy link

Choose a reason for hiding this comment

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

Method isAssetHidden is defined but never used

Low Severity

The isAssetHidden() method is defined but never used anywhere in the codebase. Unlike the other hidden asset methods (hideAsset, unhideAsset, getHiddenAssets), this method has no corresponding action type defined and is not registered as a messenger action handler. It cannot be called via the messenger pattern and is never called internally. This appears to be dead code that was added but never integrated.

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

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

not a huge deal, we can add some tests to cover this.

@Kriys94 Kriys94 marked this pull request as draft January 29, 2026 15:54
Comment on lines +137 to +139
if (hiddenAssets.has(assetId)) {
continue;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm does this mean we don't fetch and update balances for hidden assets?
Might be problematic for the swaps flow (you could be trying to swap a hidden asset, where the balance is outdated?)

High level, my initial thoughts are that "Hidden Assets" are a UI lever/control, we should still be performing data fetching if there are places that do show this asset.

allIgnoredTokens: Record<string, Record<string, string[]>>;
assetsMetadata: Record<Caip19AssetId, AssetMetadata>;
assetsBalance: Record<string, Record<string, { amount: string }>>;
hiddenAssets: Record<string, string[]>;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit (not a blocker) - I wonder if we add the JSDOC like we did for packages/assets-controller/src/data-sources/evm-rpc-services/types/state.ts, it helped readability on what this Record<string, string[]> is.

Copy link
Contributor

Choose a reason for hiding this comment

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

(optional, needs discussion), the Accounts team export a type alias, that could assist with readability

export type AccountId = string;

...Hesitant since it doesn't actually provide any additional type safety... maybe JSDOC is better?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually I actually much more prefer the approach you used below in packages/assets-controller/src/AssetsController.ts

type Foo = { [accountId: string]: string[] };

I think this is easier to read/understand then Record<string, string[]>

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add some tests on the new exposed methods from this controller?

Copy link
Contributor

@Prithpal-Sooriya Prithpal-Sooriya left a comment

Choose a reason for hiding this comment

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

Initial pass looks good. Lemme know when this PR is out of draft 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants