@exodus/assets-feature 2.0.2 → 3.1.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,32 @@
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
+ ## [3.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@3.0.0...@exodus/assets-feature@3.1.0) (2023-09-20)
7
+
8
+ ### Features
9
+
10
+ - add custom tokens monitor ([#4150](https://github.com/ExodusMovement/exodus-hydra/issues/4150)) ([f9d8bee](https://github.com/ExodusMovement/exodus-hydra/commit/f9d8bee4b0aecdf8c04bb03b960316ce64e24b91))
11
+ - support external asset registry ([#4138](https://github.com/ExodusMovement/exodus-hydra/issues/4138)) ([3100890](https://github.com/ExodusMovement/exodus-hydra/commit/3100890ed264cf670cad1c76290067f58bf8cd62))
12
+
13
+ ### Bug Fixes
14
+
15
+ - ensure tokens have display properties ([#4149](https://github.com/ExodusMovement/exodus-hydra/issues/4149)) ([4f39d42](https://github.com/ExodusMovement/exodus-hydra/commit/4f39d42b7446b89638791d1c01af1fe035898b2d))
16
+ - minor custom token bugs ([#13202](https://github.com/ExodusMovement/exodus-hydra/issues/13202)) ([876214a](https://github.com/ExodusMovement/exodus-hydra/commit/876214a8e04e4fb84b729cabd804b4345f03a51d))
17
+
18
+ ## [3.0.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@2.0.2...@exodus/assets-feature@3.0.0) (2023-09-19)
19
+
20
+ ### ⚠ BREAKING CHANGES
21
+
22
+ - emit defaultAccountStates from assets-load (#4072)
23
+
24
+ ### Features
25
+
26
+ - emit defaultAccountStates from assets-load ([#4072](https://github.com/ExodusMovement/exodus-hydra/issues/4072)) ([1b3887a](https://github.com/ExodusMovement/exodus-hydra/commit/1b3887ab0d10c14ee90622121bf2fa6847f53b17))
27
+
28
+ ### Bug Fixes
29
+
30
+ - update assets module ([#4123](https://github.com/ExodusMovement/exodus-hydra/issues/4123)) ([8f1cd56](https://github.com/ExodusMovement/exodus-hydra/commit/8f1cd56d774336e389cf932944755c4670356dcc))
31
+
6
32
  ## [2.0.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@2.0.1...@exodus/assets-feature@2.0.2) (2023-09-14)
7
33
 
8
34
  ### Bug Fixes
@@ -192,6 +192,7 @@ class AssetClientInterface {
192
192
  }
193
193
 
194
194
  signTransaction = async ({ assetName, unsignedTx, walletAccount }) => {
195
+ // eslint-disable-next-line unicorn/no-await-expression-member
195
196
  const accountIndex = (await this.#getWalletAccount(walletAccount)).index
196
197
  const baseAssetName = this.assetsModule.getAsset(assetName).baseAsset.name
197
198
  return this.wallet.signTransaction({ baseAssetName, unsignedTx, accountIndex })
package/index.js CHANGED
@@ -4,6 +4,7 @@ import multiAddressModeAtomDefinition from './atoms/multi-address-mode'
4
4
  import disabledPurposesAtomDefinition from './atoms/disabled-purposes'
5
5
  import assetsApiDefinition from './api'
6
6
  import assetModuleDefinition from './module'
7
+ import customTokensMonitorDefinition from './monitor'
7
8
  import assetPreferencesDefinition from './module/asset-preferences'
8
9
 
9
10
  const assets = ({ config = {} } = {}) => {
@@ -34,6 +35,7 @@ const assets = ({ config = {} } = {}) => {
34
35
  definition: assetPreferencesDefinition,
35
36
  writesAtoms: ['multiAddressModeAtom', 'disabledPurposesAtom'],
36
37
  },
38
+ { definition: customTokensMonitorDefinition },
37
39
  ],
38
40
  }
39
41
  }
@@ -12,16 +12,44 @@ import ExodusModule from '@exodus/module'
12
12
  // eslint-disable-next-line @exodus/restricted-imports/prefer-basic-utils
13
13
  import { get, isEmpty, keyBy, once } from 'lodash'
14
14
  import assert from 'minimalistic-assert'
15
- import ms from 'ms'
16
15
 
17
- import { CT_DATA_KEY, CT_TIMESTAMP_KEY, CT_UPDATE_INTERVAL } from './constants'
16
+ import {
17
+ CT_DATA_KEY,
18
+ CT_FETCH_CACHE_EXPIRY,
19
+ CT_TIMESTAMP_KEY,
20
+ CT_UPDATE_INTERVAL,
21
+ } from './constants'
18
22
  import { getAssetFromAssetId, getFetchErrorMessage, isDisabledCustomToken } from './utils'
19
23
 
20
24
  const getFetchCacheKey = (baseAssetName, assetId) => `${assetId}-${baseAssetName}`
21
25
 
22
26
  const _isDisabledCustomToken = (token) => token.lifecycleStatus === STATUS.DISABLED
23
27
 
24
- const normalizeToken = (token) => (token.name ? token : { ...token, name: token.assetName })
28
+ const normalizeToken = (token) => ({
29
+ ...token,
30
+ name: token.name || token.assetName,
31
+ displayName: token.displayName || token.properName,
32
+ displayTicker: token.displayTicker || token.properTicker,
33
+ })
34
+
35
+ const initialAssetRegistry = {
36
+ getAsset: (assetName) => {
37
+ try {
38
+ throw new Error(`accessing asset ${assetName} too early`)
39
+ } catch (e) {
40
+ console.warn(e.message, e.stack)
41
+ }
42
+ },
43
+ getAssets: () => {
44
+ try {
45
+ throw new Error(`accessing assets too early`)
46
+ } catch (e) {
47
+ console.warn(e.message, e.stack)
48
+ }
49
+
50
+ return {}
51
+ },
52
+ }
25
53
 
26
54
  export class AssetsModule extends ExodusModule {
27
55
  #registry
@@ -37,11 +65,14 @@ export class AssetsModule extends ExodusModule {
37
65
  #storageDataKey
38
66
  #storageTimestampKey
39
67
  #customTokenUpdateInterval
68
+ #fetchCacheExpiry
40
69
  #globalAssetRegistry // temporary
70
+ #isExternalRegistry
41
71
 
42
72
  constructor({
43
73
  storage,
44
74
  iconsStorage,
75
+ assetRegistry, // temporary
45
76
  assetPlugins,
46
77
  combinedAssetsList,
47
78
  globalAssetRegistry, // temporary
@@ -50,24 +81,8 @@ export class AssetsModule extends ExodusModule {
50
81
  }) {
51
82
  super({ name: 'AssetsModule' })
52
83
  this.#storage = storage
53
- this.#registry = {
54
- getAsset: (assetName) => {
55
- try {
56
- throw new Error(`accessing asset ${assetName} too early`)
57
- } catch (e) {
58
- console.warn(e.message, e.stack)
59
- }
60
- },
61
- getAssets: () => {
62
- try {
63
- throw new Error(`accessing assets too early`)
64
- } catch (e) {
65
- console.warn(e.message, e.stack)
66
- }
67
-
68
- return {}
69
- },
70
- }
84
+ this.#isExternalRegistry = !!assetRegistry
85
+ this.#registry = this.#isExternalRegistry ? assetRegistry : initialAssetRegistry
71
86
  this.#assetPlugins = assetPlugins
72
87
  this.#combinedAssetsList = combinedAssetsList
73
88
  this.#fetchCache = {}
@@ -79,12 +94,17 @@ export class AssetsModule extends ExodusModule {
79
94
  this.#storageDataKey = config.storageDataKey || CT_DATA_KEY
80
95
  this.#storageTimestampKey = config.storageTimestampKey || CT_TIMESTAMP_KEY
81
96
  this.#customTokenUpdateInterval = config.customTokenUpdateInterval || CT_UPDATE_INTERVAL
97
+ this.#fetchCacheExpiry = config.fetchCacheExpiry ?? CT_FETCH_CACHE_EXPIRY
82
98
  this.#globalAssetRegistry = globalAssetRegistry // temporary
83
99
  }
84
100
 
85
101
  // Assets Registry API
86
102
 
87
103
  initialize = ({ assetClientInterface }) => {
104
+ assert(
105
+ !this.#isExternalRegistry,
106
+ 'initialize(): cannot initialize when using external registry'
107
+ )
88
108
  // TODO: pass asset specific config to assets module in `config.assetsConfig`
89
109
  const { assetsConfig = {} } = this.#config
90
110
  const assetsList = Object.entries(this.#assetPlugins)
@@ -159,6 +179,7 @@ export class AssetsModule extends ExodusModule {
159
179
  'icon', // there is no icon field in built in assets, but there may be for custom tokens (TODO?)
160
180
  'isBuiltIn',
161
181
  'isCustomToken',
182
+ 'lifecycleStatus',
162
183
  'name',
163
184
  'primaryColor',
164
185
  'properName',
@@ -254,9 +275,11 @@ export class AssetsModule extends ExodusModule {
254
275
  addRemoteTokens = async ({ tokenNames }) => {
255
276
  const assets = this.getAssets()
256
277
  const tokenNamesToFetch = tokenNames.filter((tokenName) => !assets[tokenName])
257
- if (tokenNamesToFetch.length === 0) return
258
278
 
259
- const tokensToAdd = await this.#fetch('tokens', { tokenNames: tokenNamesToFetch }, 'tokens')
279
+ const tokensToAdd =
280
+ tokenNamesToFetch.length > 0
281
+ ? await this.#fetch('tokens', { tokenNames: tokenNamesToFetch }, 'tokens')
282
+ : []
260
283
  const tokensToUpdate = tokenNames
261
284
  .map((tokenName) => assets[tokenName])
262
285
  .filter((token) => !!token)
@@ -337,8 +360,8 @@ export class AssetsModule extends ExodusModule {
337
360
  #getAssetNamesBy = (filter) =>
338
361
  Object.keys(this.getAssets()).filter((assetName) => filter(this.getAsset(assetName)))
339
362
 
340
- #setCache = (key, value, ttl = ms('5m')) => {
341
- this.#fetchCache[key] = { value, expiry: Date.now() + ttl }
363
+ #setCache = (key, value) => {
364
+ this.#fetchCache[key] = { value, expiry: Date.now() + this.#fetchCacheExpiry }
342
365
  }
343
366
 
344
367
  #getCache = (key) => {
@@ -3,3 +3,4 @@ import ms from 'ms'
3
3
  export const CT_DATA_KEY = 'customTokens'
4
4
  export const CT_TIMESTAMP_KEY = 'customTokensLastUpdate'
5
5
  export const CT_UPDATE_INTERVAL = ms('8h')
6
+ export const CT_FETCH_CACHE_EXPIRY = ms('1h')
@@ -0,0 +1,22 @@
1
+ import { Timer } from '@exodus/timer'
2
+ import ms from 'ms'
3
+
4
+ const createCustomTokensMonitor = ({ assetsModule, appProcess }) => {
5
+ const timer = new Timer(ms('1m'))
6
+
7
+ timer.callback = async () => {
8
+ await appProcess?.awaitState('active')
9
+ assetsModule.updateTokens()
10
+ }
11
+
12
+ return timer
13
+ }
14
+
15
+ const customTokensMonitorDefinition = {
16
+ id: 'customTokensMonitor',
17
+ type: 'monitor',
18
+ factory: createCustomTokensMonitor,
19
+ dependencies: ['assetsModule', 'appProcess?'],
20
+ }
21
+
22
+ export default customTokensMonitorDefinition
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/assets-feature",
3
- "version": "2.0.2",
3
+ "version": "3.1.0",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Assets module, clients and apis",
6
6
  "main": "index.js",
@@ -13,6 +13,7 @@
13
13
  "files": [
14
14
  "client",
15
15
  "module",
16
+ "monitor",
16
17
  "plugin",
17
18
  "redux",
18
19
  "api",
@@ -32,6 +33,7 @@
32
33
  "dependencies": {
33
34
  "@exodus/basic-utils": "^2.1.0",
34
35
  "@exodus/fetch": "^1.2.1",
36
+ "@exodus/timer": "^1.0.0",
35
37
  "lodash": "^4.17.21",
36
38
  "minimalistic-assert": "^1.0.1",
37
39
  "ms": "^2.1.3",
@@ -60,5 +62,5 @@
60
62
  "jest": "^29.1.2",
61
63
  "redux": "^4.0.0"
62
64
  },
63
- "gitHead": "7957536bb53e03341f88ca866bb706e45c4d2003"
65
+ "gitHead": "c2300eac2bdc89cb16b5976a0de5d14005ad720a"
64
66
  }
package/plugin/index.js CHANGED
@@ -1,7 +1,18 @@
1
+ import { mapValues, pickBy } from '@exodus/basic-utils'
1
2
  import { createAtomObserver } from '@exodus/atoms'
2
3
 
3
4
  const createAssetsPlugin = ({ port, assetsModule, disabledPurposesAtom, multiAddressModeAtom }) => {
4
- const emitAssetsLoad = () => port.emit('assets-load', Object.values(assetsModule.getAssets()))
5
+ const emitAssetsLoad = () => {
6
+ const assets = assetsModule.getAssets()
7
+ port.emit('assets-load', {
8
+ assets,
9
+ defaultAccountStates: mapValues(
10
+ pickBy(assets, (asset) => asset.api.hasFeature('accountState')),
11
+ (asset) => asset?.api?.createAccountState?.()?.create?.()
12
+ ),
13
+ })
14
+ }
15
+
5
16
  const listeners = [
6
17
  ['assets-add', (data) => port.emit('assets-add', data)],
7
18
  ['assets-update', (data) => port.emit('assets-update', data)],
package/redux/index.js CHANGED
@@ -16,11 +16,11 @@ const assetsReduxDefinition = {
16
16
  type: 'redux-module',
17
17
  initialState,
18
18
  eventReducers: {
19
- 'assets-load': (state, payload) => ({
19
+ 'assets-load': (state, { assets }) => ({
20
20
  ...state,
21
21
  error: null,
22
22
  loaded: true,
23
- data: keyBy(payload, 'name'),
23
+ data: assets,
24
24
  }),
25
25
  'assets-add': mergeAssets,
26
26
  'assets-update': mergeAssets,