Skip to content

feat(assets-controller): add getAsset#9521

Open
Kriys94 wants to merge 4 commits into
mainfrom
feat/WPN-1473-assets-controller-get-asset
Open

feat(assets-controller): add getAsset#9521
Kriys94 wants to merge 4 commits into
mainfrom
feat/WPN-1473-assets-controller-get-asset

Conversation

@Kriys94

@Kriys94 Kriys94 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Explanation

WPN-1472 centralizes the Assets domain in @metamask/assets-controller so consumers (including Snaps) can read controller-owned balances, metadata, prices, and fiat values instead of tracking them independently. Today the controller exposes getAssets (bulk, per-account map), getAssetMetadata (metadata only), and getAssetsPrice, but there is no way to read a single combined asset for a specific account/asset pair.

This PR adds a getAsset read API to AssetsController:

  • getAsset(accountId, assetId): Asset | undefined returns the combined Asset (balance + metadata + price + computed fiatValue) for a single account/asset pair from current controller state, or undefined when a complete renderable asset is not available.
  • Exposed as the AssetsController:getAsset messenger action so it can be called through the messenger (e.g. by preinstalled Snaps once WPC-1017 lands).

Behavior details:

  • Reuses the same state-composition and filtering logic as getAssets (via the private #getAssetsFromState) so the returned shape never drifts: balance and metadata are required; a missing price falls back to { price: 0, lastUpdated: 0 } with fiatValue: 0; hidden/filtered assets resolve to undefined.
  • Reads from current state only — it does not trigger a data-source refresh.
  • Validates inputs and throws (rather than silently returning undefined) on an empty accountId or a malformed CAIP-19 assetId, so consumers can distinguish bad requests from absent data.
  • Normalizes the assetId (checksums EVM ERC-20 addresses) before lookup, consistent with how state is keyed.
  • #getAssetsFromState's accounts parameter was widened to Pick<InternalAccount, 'id'>[] (it only reads account.id) so getAsset can reuse it without constructing a full account object.

The generated messenger action types (AssetsControllerGetAssetAction) were regenerated and exported from index.ts, and a ### Added changelog entry was added.

References

  • Jira: WPN-1473 — [AssetsController] Add getAsset read API for Snap consumers
  • Part of the Assets migration epic (WPN-1472); sibling controller-side stories are WPN-1489 (stage-gated ingestion) and WPN-1490 (stage-gated ignoring of Snap events)
  • Consumer-side exposure to Snaps is blocked by WPC-1017 (messenger API exposure); the controller-side method in this PR is independent of that work

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

Low Risk
Additive read-only API with shared composition logic and tests; no fetch or persistence behavior changes beyond the internal refactor of #getAssetsFromState.

Overview
Adds getAsset(accountId, assetId) and the AssetsController:getAsset messenger action so callers can read one combined Asset (balance, metadata, price, fiatValue) from current state without running getAssets or triggering a fetch.

getAsset normalizes CAIP-19 IDs, throws on empty accountId or invalid assetId, and returns undefined when balance/metadata are missing, the asset is hidden, or other getAssets-style filters apply; missing price uses zero price/fiat like bulk reads.

Bulk state assembly is refactored: #getAssetFromState centralizes composition/filtering, #getAssetsFromState delegates per balance key (accounts typed as Pick<InternalAccount, 'id'>[]), and messenger registration/exports/changelog/tests cover the new API.

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

@Kriys94 Kriys94 force-pushed the feat/WPN-1473-assets-controller-get-asset branch 3 times, most recently from 8bdabbe to 6aa280d Compare July 15, 2026 14:55
@Kriys94 Kriys94 marked this pull request as ready for review July 15, 2026 14:58
@Kriys94 Kriys94 requested review from a team as code owners July 15, 2026 14:58
@Kriys94 Kriys94 temporarily deployed to default-branch July 15, 2026 14:59 — with GitHub Actions Inactive

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 1 potential issue.

Fix All in Cursor

❌ 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 6aa280d. Configure here.

Comment thread packages/assets-controller/src/AssetsController.ts Outdated
@Kriys94 Kriys94 force-pushed the feat/WPN-1473-assets-controller-get-asset branch from 6aa280d to 2ccbbe5 Compare July 15, 2026 15:02
Comment on lines +1815 to +1819
const assets = this.#getAssetsFromState(
[{ id: accountId }],
[chainId],
['fungible'],
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit - A tad nuts that we are calculating all assets, only to return a single asset here.

This is okay for now, we can raise/improve moving forward.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Great comment, I've refactored a bit to have #getAssetFromState and #getAssetsFromState is using #getAssetFromState


#getAssetsFromState(
accounts: InternalAccount[],
accounts: Pick<InternalAccount, 'id'>[],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Very good! Keep interface minimal!
Easier to test and use.

});
});

describe('getAsset', () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🌶️ this test file is too big, impossible to read!

Thoughts on:

  1. Making this spec more dry. I think we can leverage test tables (it.each)
  2. spicer -- separate test for each method, truly isolated, easy to read 😈

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm fine keeping this as is... but I'd like to pencil in test cleanup.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

YEah probably the best time will be after some cleaning

@Prithpal-Sooriya Prithpal-Sooriya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving with comments

@Kriys94 Kriys94 force-pushed the feat/WPN-1473-assets-controller-get-asset branch from 2ccbbe5 to e3a2e51 Compare July 16, 2026 09:29
Comment thread packages/assets-controller/src/AssetsController.ts Fixed
Kriys94 and others added 4 commits July 16, 2026 11:48
Co-authored-by: Cursor <cursoragent@cursor.com>
…assignment'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@Kriys94 Kriys94 force-pushed the feat/WPN-1473-assets-controller-get-asset branch from 4e07a57 to 71d02f4 Compare July 16, 2026 09:48
Sign up for free to 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