@metamask-previews/assets-controller 2.0.2-preview-980f677 → 2.0.2-preview-567bc78af

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/dist/AssetsController-method-action-types.cjs.map +1 -1
  3. package/dist/AssetsController-method-action-types.d.cts +5 -0
  4. package/dist/AssetsController-method-action-types.d.cts.map +1 -1
  5. package/dist/AssetsController-method-action-types.d.mts +5 -0
  6. package/dist/AssetsController-method-action-types.d.mts.map +1 -1
  7. package/dist/AssetsController-method-action-types.mjs.map +1 -1
  8. package/dist/AssetsController.cjs +30 -2
  9. package/dist/AssetsController.cjs.map +1 -1
  10. package/dist/AssetsController.d.cts +21 -1
  11. package/dist/AssetsController.d.cts.map +1 -1
  12. package/dist/AssetsController.d.mts +21 -1
  13. package/dist/AssetsController.d.mts.map +1 -1
  14. package/dist/AssetsController.mjs +30 -2
  15. package/dist/AssetsController.mjs.map +1 -1
  16. package/dist/data-sources/TokenDataSource.cjs +1 -0
  17. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  18. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  19. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  20. package/dist/data-sources/TokenDataSource.mjs +1 -0
  21. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +1 -0
  24. package/dist/index.d.cts.map +1 -1
  25. package/dist/index.d.mts +1 -0
  26. package/dist/index.d.mts.map +1 -1
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/middlewares/DetectionMiddleware.cjs +44 -27
  29. package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
  30. package/dist/middlewares/DetectionMiddleware.d.cts +15 -9
  31. package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
  32. package/dist/middlewares/DetectionMiddleware.d.mts +15 -9
  33. package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
  34. package/dist/middlewares/DetectionMiddleware.mjs +44 -27
  35. package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
  36. package/package.json +3 -3
@@ -10,12 +10,19 @@ createModuleLogger(projectLogger, CONTROLLER_NAME);
10
10
  // DETECTION MIDDLEWARE
11
11
  // ============================================================================
12
12
  /**
13
- * DetectionMiddleware identifies assets that do not have metadata.
13
+ * DetectionMiddleware builds the set of assets that downstream sources use for
14
+ * metadata and price fetching.
14
15
  *
15
16
  * This middleware:
16
- * - Checks assets in the response for metadata in state (via ctx.getAssetsState)
17
- * - Assets in response but without metadata are considered "detected"
18
- * - Fills response.detectedAssets with asset IDs per account that lack metadata
17
+ * - Includes every asset that appears in response.assetsBalance (so prices and
18
+ * metadata are fetched for existing assets as well as new ones)
19
+ * - Includes each account's custom assets from state (so custom tokens get
20
+ * metadata and prices even when they have no balance yet)
21
+ * - Fills response.detectedAssets with these asset IDs per account
22
+ *
23
+ * TokenDataSource and PriceDataSource both key off detectedAssets. TokenDataSource
24
+ * then filters to only fetch metadata for assets that lack it; PriceDataSource
25
+ * fetches prices for all detected assets.
19
26
  *
20
27
  * Usage:
21
28
  * ```typescript
@@ -31,45 +38,55 @@ export class DetectionMiddleware {
31
38
  return this.name;
32
39
  }
33
40
  /**
34
- * Get the middleware for detecting assets without metadata.
41
+ * Get the middleware that builds detectedAssets for metadata and price fetching.
35
42
  *
36
43
  * This middleware:
37
- * 1. Extracts the response from context
38
- * 2. Detects assets from the response that don't have metadata
39
- * 3. Fills response.detectedAssets with detected asset IDs per account
40
- * 4. Calls next() to continue the middleware chain
44
+ * 1. Includes all assets from response.assetsBalance (so prices are fetched for existing assets too)
45
+ * 2. Merges each account's custom assets from state
46
+ * 3. Fills response.detectedAssets with these asset IDs per account
41
47
  *
42
48
  * @returns The middleware function for the assets pipeline.
43
49
  */
44
50
  get assetsMiddleware() {
45
51
  return forDataTypes(['balance'], async (ctx, next) => {
46
- // Extract response from context
47
- const { response } = ctx;
48
- // If no balances in response, nothing to detect - pass through
49
- if (!response.assetsBalance) {
50
- return next(ctx);
51
- }
52
- // Get metadata from state
53
- const { assetsInfo: stateMetadata } = ctx.getAssetsState();
52
+ const { request, response } = ctx;
53
+ // Get state for custom assets
54
+ const state = ctx.getAssetsState();
55
+ const { customAssets: stateCustomAssets } = state;
54
56
  const detectedAssets = {};
55
- // Detect assets from the response that don't have metadata
56
- for (const [accountId, accountBalances] of Object.entries(response.assetsBalance)) {
57
- const detected = [];
58
- for (const assetId of Object.keys(accountBalances)) {
59
- // Asset is detected if it does not have metadata in state
60
- if (!stateMetadata[assetId]) {
57
+ // 1. From balance response: include every asset with balance (so prices + metadata path include existing assets)
58
+ if (response.assetsBalance) {
59
+ for (const [accountId, accountBalances] of Object.entries(response.assetsBalance)) {
60
+ const detected = [];
61
+ for (const assetId of Object.keys(accountBalances)) {
61
62
  detected.push(assetId);
62
63
  }
64
+ // Merge this account's custom assets from state
65
+ const customForAccount = stateCustomAssets?.[accountId] ?? [];
66
+ for (const assetId of customForAccount) {
67
+ if (!detected.includes(assetId)) {
68
+ detected.push(assetId);
69
+ }
70
+ }
71
+ if (detected.length > 0) {
72
+ detectedAssets[accountId] = detected;
73
+ }
74
+ }
75
+ }
76
+ // 2. Accounts in request that weren't in balance response: include their custom assets
77
+ for (const { account } of request.accountsWithSupportedChains) {
78
+ const accountId = account.id;
79
+ if (detectedAssets[accountId]) {
80
+ continue;
63
81
  }
64
- if (detected.length > 0) {
65
- detectedAssets[accountId] = detected;
82
+ const customForAccount = stateCustomAssets?.[accountId] ?? [];
83
+ if (customForAccount.length > 0) {
84
+ detectedAssets[accountId] = customForAccount;
66
85
  }
67
86
  }
68
- // Fill detectedAssets in the response
69
87
  if (Object.keys(detectedAssets).length > 0) {
70
88
  response.detectedAssets = detectedAssets;
71
89
  }
72
- // Call next() to continue the middleware chain
73
90
  return next(ctx);
74
91
  });
75
92
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DetectionMiddleware.mjs","sourceRoot":"","sources":["../../src/middlewares/DetectionMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,sBAAkB;AAC9D,OAAO,EAAE,YAAY,EAAE,qBAAiB;AAGxC,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C,uBAAuB;AACvB,kBAAkB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAEnD,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,mBAAmB;IAAhC;QACW,SAAI,GAAG,eAAe,CAAC;IA6DlC,CAAC;IA3DC,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;;;;;;;;;OAUG;IACH,IAAI,gBAAgB;QAClB,OAAO,YAAY,CAAC,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YACnD,gCAAgC;YAChC,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;YAEzB,+DAA+D;YAC/D,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;gBAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;YAED,0BAA0B;YAC1B,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YAE3D,MAAM,cAAc,GAAuC,EAAE,CAAC;YAE9D,2DAA2D;YAC3D,KAAK,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,IAAI,MAAM,CAAC,OAAO,CACvD,QAAQ,CAAC,aAAa,CACvB,EAAE,CAAC;gBACF,MAAM,QAAQ,GAAoB,EAAE,CAAC;gBAErC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAC/B,eAA0C,CAC3C,EAAE,CAAC;oBACF,0DAA0D;oBAC1D,IAAI,CAAC,aAAa,CAAC,OAAwB,CAAC,EAAE,CAAC;wBAC7C,QAAQ,CAAC,IAAI,CAAC,OAAwB,CAAC,CAAC;oBAC1C,CAAC;gBACH,CAAC;gBAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,cAAc,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC;gBACvC,CAAC;YACH,CAAC;YAED,sCAAsC;YACtC,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3C,QAAQ,CAAC,cAAc,GAAG,cAAc,CAAC;YAC3C,CAAC;YAED,+CAA+C;YAC/C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["import { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type { AccountId, Caip19AssetId, Middleware } from '../types';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'DetectionMiddleware';\n\n// Logger for debugging\ncreateModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// DETECTION MIDDLEWARE\n// ============================================================================\n\n/**\n * DetectionMiddleware identifies assets that do not have metadata.\n *\n * This middleware:\n * - Checks assets in the response for metadata in state (via ctx.getAssetsState)\n * - Assets in response but without metadata are considered \"detected\"\n * - Fills response.detectedAssets with asset IDs per account that lack metadata\n *\n * Usage:\n * ```typescript\n * const detectionMiddleware = new DetectionMiddleware();\n * const middleware = detectionMiddleware.assetsMiddleware;\n * ```\n */\nexport class DetectionMiddleware {\n readonly name = CONTROLLER_NAME;\n\n getName(): string {\n return this.name;\n }\n\n /**\n * Get the middleware for detecting assets without metadata.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Detects assets from the response that don't have metadata\n * 3. Fills response.detectedAssets with detected asset IDs per account\n * 4. Calls next() to continue the middleware chain\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['balance'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n // If no balances in response, nothing to detect - pass through\n if (!response.assetsBalance) {\n return next(ctx);\n }\n\n // Get metadata from state\n const { assetsInfo: stateMetadata } = ctx.getAssetsState();\n\n const detectedAssets: Record<AccountId, Caip19AssetId[]> = {};\n\n // Detect assets from the response that don't have metadata\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const detected: Caip19AssetId[] = [];\n\n for (const assetId of Object.keys(\n accountBalances as Record<string, unknown>,\n )) {\n // Asset is detected if it does not have metadata in state\n if (!stateMetadata[assetId as Caip19AssetId]) {\n detected.push(assetId as Caip19AssetId);\n }\n }\n\n if (detected.length > 0) {\n detectedAssets[accountId] = detected;\n }\n }\n\n // Fill detectedAssets in the response\n if (Object.keys(detectedAssets).length > 0) {\n response.detectedAssets = detectedAssets;\n }\n\n // Call next() to continue the middleware chain\n return next(ctx);\n });\n }\n}\n"]}
1
+ {"version":3,"file":"DetectionMiddleware.mjs","sourceRoot":"","sources":["../../src/middlewares/DetectionMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,sBAAkB;AAC9D,OAAO,EAAE,YAAY,EAAE,qBAAiB;AAGxC,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C,uBAAuB;AACvB,kBAAkB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;AAEnD,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,mBAAmB;IAAhC;QACW,SAAI,GAAG,eAAe,CAAC;IAwElC,CAAC;IAtEC,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;;;;;;;;OASG;IACH,IAAI,gBAAgB;QAClB,OAAO,YAAY,CAAC,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YACnD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;YAElC,8BAA8B;YAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YACnC,MAAM,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,KAAK,CAAC;YAElD,MAAM,cAAc,GAAuC,EAAE,CAAC;YAE9D,iHAAiH;YACjH,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;gBAC3B,KAAK,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,IAAI,MAAM,CAAC,OAAO,CACvD,QAAQ,CAAC,aAAa,CACvB,EAAE,CAAC;oBACF,MAAM,QAAQ,GAAoB,EAAE,CAAC;oBAErC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAC/B,eAA0C,CAC3C,EAAE,CAAC;wBACF,QAAQ,CAAC,IAAI,CAAC,OAAwB,CAAC,CAAC;oBAC1C,CAAC;oBAED,gDAAgD;oBAChD,MAAM,gBAAgB,GAAG,iBAAiB,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;oBAC9D,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;wBACvC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;4BAChC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;wBACzB,CAAC;oBACH,CAAC;oBAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACxB,cAAc,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC;oBACvC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,uFAAuF;YACvF,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,OAAO,CAAC,2BAA2B,EAAE,CAAC;gBAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,EAAE,CAAC;gBAC7B,IAAI,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC9B,SAAS;gBACX,CAAC;gBACD,MAAM,gBAAgB,GAAG,iBAAiB,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;gBAC9D,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAChC,cAAc,CAAC,SAAS,CAAC,GAAG,gBAAgB,CAAC;gBAC/C,CAAC;YACH,CAAC;YAED,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3C,QAAQ,CAAC,cAAc,GAAG,cAAc,CAAC;YAC3C,CAAC;YAED,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["import { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type { AccountId, Caip19AssetId, Middleware } from '../types';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'DetectionMiddleware';\n\n// Logger for debugging\ncreateModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// DETECTION MIDDLEWARE\n// ============================================================================\n\n/**\n * DetectionMiddleware builds the set of assets that downstream sources use for\n * metadata and price fetching.\n *\n * This middleware:\n * - Includes every asset that appears in response.assetsBalance (so prices and\n * metadata are fetched for existing assets as well as new ones)\n * - Includes each account's custom assets from state (so custom tokens get\n * metadata and prices even when they have no balance yet)\n * - Fills response.detectedAssets with these asset IDs per account\n *\n * TokenDataSource and PriceDataSource both key off detectedAssets. TokenDataSource\n * then filters to only fetch metadata for assets that lack it; PriceDataSource\n * fetches prices for all detected assets.\n *\n * Usage:\n * ```typescript\n * const detectionMiddleware = new DetectionMiddleware();\n * const middleware = detectionMiddleware.assetsMiddleware;\n * ```\n */\nexport class DetectionMiddleware {\n readonly name = CONTROLLER_NAME;\n\n getName(): string {\n return this.name;\n }\n\n /**\n * Get the middleware that builds detectedAssets for metadata and price fetching.\n *\n * This middleware:\n * 1. Includes all assets from response.assetsBalance (so prices are fetched for existing assets too)\n * 2. Merges each account's custom assets from state\n * 3. Fills response.detectedAssets with these asset IDs per account\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['balance'], async (ctx, next) => {\n const { request, response } = ctx;\n\n // Get state for custom assets\n const state = ctx.getAssetsState();\n const { customAssets: stateCustomAssets } = state;\n\n const detectedAssets: Record<AccountId, Caip19AssetId[]> = {};\n\n // 1. From balance response: include every asset with balance (so prices + metadata path include existing assets)\n if (response.assetsBalance) {\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const detected: Caip19AssetId[] = [];\n\n for (const assetId of Object.keys(\n accountBalances as Record<string, unknown>,\n )) {\n detected.push(assetId as Caip19AssetId);\n }\n\n // Merge this account's custom assets from state\n const customForAccount = stateCustomAssets?.[accountId] ?? [];\n for (const assetId of customForAccount) {\n if (!detected.includes(assetId)) {\n detected.push(assetId);\n }\n }\n\n if (detected.length > 0) {\n detectedAssets[accountId] = detected;\n }\n }\n }\n\n // 2. Accounts in request that weren't in balance response: include their custom assets\n for (const { account } of request.accountsWithSupportedChains) {\n const accountId = account.id;\n if (detectedAssets[accountId]) {\n continue;\n }\n const customForAccount = stateCustomAssets?.[accountId] ?? [];\n if (customForAccount.length > 0) {\n detectedAssets[accountId] = customForAccount;\n }\n }\n\n if (Object.keys(detectedAssets).length > 0) {\n response.detectedAssets = detectedAssets;\n }\n\n return next(ctx);\n });\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/assets-controller",
3
- "version": "2.0.2-preview-980f677",
3
+ "version": "2.0.2-preview-567bc78af",
4
4
  "description": "Tracks assets balances/prices and handles token detection across all digital assets",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -52,7 +52,7 @@
52
52
  "@ethersproject/abi": "^5.7.0",
53
53
  "@ethersproject/providers": "^5.7.0",
54
54
  "@metamask/account-tree-controller": "^4.1.1",
55
- "@metamask/assets-controllers": "^100.0.2",
55
+ "@metamask/assets-controllers": "^100.0.3",
56
56
  "@metamask/base-controller": "^9.0.0",
57
57
  "@metamask/client-controller": "^1.0.0",
58
58
  "@metamask/controller-utils": "^11.19.0",
@@ -69,7 +69,7 @@
69
69
  "@metamask/preferences-controller": "^22.1.0",
70
70
  "@metamask/snaps-controllers": "^17.2.0",
71
71
  "@metamask/snaps-utils": "^11.7.0",
72
- "@metamask/transaction-controller": "^62.18.0",
72
+ "@metamask/transaction-controller": "^62.19.0",
73
73
  "@metamask/utils": "^11.9.0",
74
74
  "async-mutex": "^0.5.0",
75
75
  "bignumber.js": "^9.1.2",