@exodus/assets-feature 8.1.3 → 8.2.0

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [8.2.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@8.1.3...@exodus/assets-feature@8.2.0) (2025-08-07)
7
+
8
+ ### Features
9
+
10
+ - feat(assets-feature): add fetch tokens method (#13362)
11
+
6
12
  ## [8.1.3](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@8.1.2...@exodus/assets-feature@8.1.3) (2025-07-02)
7
13
 
8
14
  ### Bug Fixes
package/api/index.js CHANGED
@@ -12,6 +12,7 @@ const createAssetsApi = ({ assetPreferences, assetsModule }) => {
12
12
  },
13
13
  assets: {
14
14
  fetchToken: (...args) => assetsModule.fetchToken(...args),
15
+ fetchTokens: (...args) => assetsModule.fetchTokens(...args),
15
16
  searchTokens: (...args) => assetsModule.searchTokens(...args),
16
17
  updateTokens: (...args) => assetsModule.updateTokens(...args),
17
18
  addTokens: (...args) => assetsModule.addTokens(...args),
@@ -14,7 +14,12 @@ import {
14
14
  CT_TIMESTAMP_KEY,
15
15
  CT_UPDATE_INTERVAL,
16
16
  } from './constants.js'
17
- import { getAssetFromAssetId, getFetchErrorMessage, isDisabledCustomToken } from './utils.js'
17
+ import {
18
+ filterBuiltInProps,
19
+ getAssetFromAssetId,
20
+ getFetchErrorMessage,
21
+ isDisabledCustomToken,
22
+ } from './utils.js'
18
23
  import createFetchival from '@exodus/fetch/create-fetchival'
19
24
  import { validateCustomToken, isValidCustomToken } from '@exodus/asset-schema-validation'
20
25
  import makeConcurrent from 'make-concurrent'
@@ -22,25 +27,6 @@ import oldToNewStyleTokenNames from '@exodus/asset-legacy-token-name-mapping'
22
27
 
23
28
  const { get, isEmpty, once, uniq } = lodash
24
29
 
25
- const FILTERED_FIELDS = [
26
- 'assetId',
27
- 'baseAssetName',
28
- 'displayName',
29
- 'displayTicker',
30
- 'gradientColors',
31
- 'icon', // there is no icon field in built in assets, but there may be for custom tokens (TODO?)
32
- 'isBuiltIn',
33
- 'isCustomToken',
34
- 'lifecycleStatus',
35
- 'name',
36
- 'primaryColor',
37
- 'properName',
38
- 'properTicker',
39
- 'ticker',
40
- ]
41
-
42
- const filterBuiltInProps = (asset) => ({ ...pick(asset, FILTERED_FIELDS), assetName: asset.name })
43
-
44
30
  const getFetchCacheKey = (baseAssetName, assetId) => `${assetId}-${baseAssetName}`
45
31
 
46
32
  const _isDisabledCustomToken = (token) => token.lifecycleStatus === STATUS.DISABLED
@@ -250,6 +236,75 @@ export class AssetsModule {
250
236
  return this.#getCache(key)
251
237
  }
252
238
 
239
+ #fetchTokens = async (assetDescriptors) => {
240
+ for (const { baseAssetName } of assetDescriptors) {
241
+ this.#assertSupportsCustomTokens(baseAssetName)
242
+ }
243
+
244
+ const [builtInDescriptors, customTokensDescriptors] = partition(
245
+ assetDescriptors,
246
+ ({ assetId, baseAssetName }) => !!this.#getAssetFromAssetId(assetId, baseAssetName)
247
+ )
248
+
249
+ const getBuiltInDefinitions = (descriptors) =>
250
+ descriptors.map(({ assetId, baseAssetName }) =>
251
+ filterBuiltInProps(this.#getAssetFromAssetId(assetId, baseAssetName))
252
+ )
253
+
254
+ const getCustomTokensDefinitions = async (descriptors) => {
255
+ const _tokens = await this.#fetch(
256
+ `tokens`,
257
+ { assetIds: descriptors, lifecycleStatus: ['c', 'v', 'u'] },
258
+ 'tokens'
259
+ )
260
+
261
+ if (this.#shouldValidateCustomToken) {
262
+ for (const token of _tokens) {
263
+ try {
264
+ validateCustomToken(token)
265
+ } catch (e) {
266
+ this.#logger.warn(
267
+ `Token did not pass validation ${token.baseAssetName} ${token.assetId}. Error: ${e.message}`
268
+ )
269
+ throw new Error('Token did not pass validation')
270
+ }
271
+ }
272
+ }
273
+
274
+ const tokens = _tokens.map((token) => normalizeToken(token))
275
+
276
+ try {
277
+ await this.#iconsStorage.storeIcons(tokens)
278
+ } catch (err) {
279
+ this.#logger.warn(`An error occurred while decoding icons`, err.message)
280
+ }
281
+
282
+ for (const token of tokens) {
283
+ const key = getFetchCacheKey(token.baseAssetName, token.assetId)
284
+ this.#setCache(key, token)
285
+ }
286
+
287
+ return tokens
288
+ }
289
+
290
+ const builtInTokens = getBuiltInDefinitions(builtInDescriptors)
291
+ const customTokens = await getCustomTokensDefinitions(customTokensDescriptors)
292
+
293
+ return { builtInTokens, customTokens }
294
+ }
295
+
296
+ fetchTokens = async (assetIds) => {
297
+ const { builtInTokens, customTokens } = await this.#fetchTokens(assetIds)
298
+
299
+ const builtInAssets = builtInTokens.map(({ name }) => this.getAsset(name))
300
+ const customTokenAssets = customTokens.map((definition) => {
301
+ const baseAsset = this.getAsset(definition.baseAssetName)
302
+ return baseAsset.api.createToken(definition)
303
+ })
304
+
305
+ return [...builtInAssets, ...customTokenAssets]
306
+ }
307
+
253
308
  addToken = async (assetId, baseAssetName) => {
254
309
  this.#assertCustomTokensStorageSupported()
255
310
  this.#assertSupportsCustomTokens(baseAssetName)
@@ -328,8 +383,9 @@ export class AssetsModule {
328
383
  : []
329
384
 
330
385
  const validTokens = fetchedTokens.filter(this.#isValidCustomToken).map(normalizeToken)
331
- if (validTokens.length !== fetchedTokens.length)
386
+ if (validTokens.length !== fetchedTokens.length) {
332
387
  this.#logger.warn('Invalid Custom Token schema')
388
+ }
333
389
 
334
390
  const tokens = tokenNamesToUpdate.map((tokenName) => assets[tokenName])
335
391
 
@@ -471,8 +527,9 @@ export class AssetsModule {
471
527
  `${endpoint}${testDataParam}`
472
528
  ).post(body)
473
529
 
474
- if (res.status !== 'OK')
530
+ if (res.status !== 'OK') {
475
531
  throw new Error(`Custom tokens registry ${endpoint} ${res.status} ${res.message}`)
532
+ }
476
533
 
477
534
  return get(res, resultPath)
478
535
  } catch (error) {
package/module/utils.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { CT_STATUS as STATUS } from '@exodus/assets'
2
+ import { pick } from '@exodus/basic-utils'
2
3
  import lodash from 'lodash'
3
4
  import assert from 'minimalistic-assert'
4
5
 
@@ -44,3 +45,25 @@ export async function getFetchErrorMessage(error) {
44
45
  return defaultExtraMessage
45
46
  }
46
47
  }
48
+
49
+ const FILTERED_FIELDS = [
50
+ 'assetId',
51
+ 'baseAssetName',
52
+ 'displayName',
53
+ 'displayTicker',
54
+ 'gradientColors',
55
+ 'icon', // there is no icon field in built in assets, but there may be for custom tokens (TODO?)
56
+ 'isBuiltIn',
57
+ 'isCustomToken',
58
+ 'lifecycleStatus',
59
+ 'name',
60
+ 'primaryColor',
61
+ 'properName',
62
+ 'properTicker',
63
+ 'ticker',
64
+ ]
65
+
66
+ export const filterBuiltInProps = (asset) => ({
67
+ ...pick(asset, FILTERED_FIELDS),
68
+ assetName: asset.name,
69
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/assets-feature",
3
- "version": "8.1.3",
3
+ "version": "8.2.0",
4
4
  "license": "MIT",
5
5
  "description": "This Exodus SDK feature provides access to instances of all blockchain asset adapters supported by the wallet, and enables you to search for and add custom tokens at runtime.",
6
6
  "type": "module",
@@ -58,7 +58,7 @@
58
58
  "@exodus/bitcoin-plugin": "^1.29.1",
59
59
  "@exodus/bitcoinregtest-plugin": "^1.11.0",
60
60
  "@exodus/bitcointestnet-plugin": "^1.13.1",
61
- "@exodus/blockchain-metadata": "^15.12.0",
61
+ "@exodus/blockchain-metadata": "^15.14.0",
62
62
  "@exodus/cardano-lib": "^3.4.1",
63
63
  "@exodus/combined-assets-meta": "^3.0.0",
64
64
  "@exodus/cosmos-plugin": "^1.3.3",
@@ -68,12 +68,12 @@
68
68
  "@exodus/fusion-local": "^2.1.0",
69
69
  "@exodus/keychain": "^7.3.0",
70
70
  "@exodus/logger": "^1.2.3",
71
- "@exodus/models": "^12.14.0",
71
+ "@exodus/models": "^12.15.0",
72
72
  "@exodus/osmosis-plugin": "^1.3.3",
73
73
  "@exodus/public-key-provider": "^4.2.0",
74
74
  "@exodus/redux-dependency-injection": "^4.1.1",
75
- "@exodus/storage-memory": "^2.2.2",
76
- "@exodus/wallet-accounts": "^17.6.1",
75
+ "@exodus/storage-memory": "^2.3.0",
76
+ "@exodus/wallet-accounts": "^17.6.2",
77
77
  "@exodus/wild-emitter": "^1.0.0",
78
78
  "events": "^3.3.0",
79
79
  "msw": "^2.0.0",
@@ -82,5 +82,5 @@
82
82
  "publishConfig": {
83
83
  "access": "public"
84
84
  },
85
- "gitHead": "c557b881c9c696fff090c233121160d689f2bc95"
85
+ "gitHead": "fb7a01b2e840d775c17311f1bc4e87f465a98816"
86
86
  }