@exodus/assets-feature 1.4.1 → 1.6.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,23 @@
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
+ ## [1.6.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@1.5.0...@exodus/assets-feature@1.6.0) (2023-09-07)
7
+
8
+ ### Features
9
+
10
+ - add asset preferences to assets-feature redux module ([#3879](https://github.com/ExodusMovement/exodus-hydra/issues/3879)) ([6b60a16](https://github.com/ExodusMovement/exodus-hydra/commit/6b60a162a2af845374911ccacf1c58dbf2620523))
11
+ - asset preferences api ([#3877](https://github.com/ExodusMovement/exodus-hydra/issues/3877)) ([5f1798b](https://github.com/ExodusMovement/exodus-hydra/commit/5f1798bc4ce616e4c762203b8f1940b898231aa1))
12
+
13
+ ### Bug Fixes
14
+
15
+ - asset-feature tests ([#3911](https://github.com/ExodusMovement/exodus-hydra/issues/3911)) ([c26d1ec](https://github.com/ExodusMovement/exodus-hydra/commit/c26d1ec7e0b32e1940c8dc6e969a5cb815661e20))
16
+
17
+ ## [1.5.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@1.4.1...@exodus/assets-feature@1.5.0) (2023-08-30)
18
+
19
+ ### Features
20
+
21
+ - always emit assets-load onStart and onLoad ([#3766](https://github.com/ExodusMovement/exodus-hydra/issues/3766)) ([54eafe5](https://github.com/ExodusMovement/exodus-hydra/commit/54eafe503e1149c8e35e7bf3b5aff275af62e0f4))
22
+
6
23
  ## [1.4.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@1.4.0...@exodus/assets-feature@1.4.1) (2023-08-30)
7
24
 
8
25
  **Note:** Version bump only for package @exodus/assets-feature
package/api/index.js ADDED
@@ -0,0 +1,19 @@
1
+ const createAssetsApi = ({ assetPreferences }) => {
2
+ return {
3
+ assetPreferences: {
4
+ enableMultiAddressMode: assetPreferences.enableMultiAddressMode,
5
+ disableMultiAddressMode: assetPreferences.disableMultiAddressMode,
6
+ disablePurpose: assetPreferences.disablePurpose,
7
+ enablePurpose: assetPreferences.enablePurpose,
8
+ },
9
+ }
10
+ }
11
+
12
+ const assetsApiDefinition = {
13
+ id: 'assetsApi',
14
+ type: 'api',
15
+ factory: createAssetsApi,
16
+ dependencies: ['assetPreferences'],
17
+ }
18
+
19
+ export default assetsApiDefinition
@@ -0,0 +1,18 @@
1
+ import { createStorageAtomFactory } from '@exodus/atoms'
2
+
3
+ const createDisabledPurposesAtom = ({ storage, logger, config }) => {
4
+ return createStorageAtomFactory({ storage, logger })({
5
+ key: 'disabledPurposes',
6
+ defaultValue: config.defaults ?? {},
7
+ isSoleWriter: true,
8
+ })
9
+ }
10
+
11
+ const disabledPurposesAtomDefinition = {
12
+ id: 'disabledPurposesAtom',
13
+ type: 'atom',
14
+ factory: createDisabledPurposesAtom,
15
+ dependencies: ['storage', 'logger', 'config'],
16
+ }
17
+
18
+ export default disabledPurposesAtomDefinition
@@ -0,0 +1,18 @@
1
+ import { createStorageAtomFactory } from '@exodus/atoms'
2
+
3
+ const createMultiAddressModeAtom = ({ storage, logger, config }) => {
4
+ return createStorageAtomFactory({ storage, logger })({
5
+ key: 'multiAddressMode',
6
+ defaultValue: config.defaults ?? {},
7
+ isSoleWriter: true,
8
+ })
9
+ }
10
+
11
+ const multiAddressModeAtomDefinition = {
12
+ id: 'multiAddressModeAtom',
13
+ type: 'atom',
14
+ factory: createMultiAddressModeAtom,
15
+ dependencies: ['storage', 'logger', 'config'],
16
+ }
17
+
18
+ export default multiAddressModeAtomDefinition
package/index.js CHANGED
@@ -1,12 +1,31 @@
1
1
  import assetsClientInterfaceDefinition from './client'
2
2
  import assetsPluginDefinition from './plugin'
3
+ import multiAddressModeAtomDefinition from './atoms/multi-address-mode'
4
+ import disabledPurposesAtomDefinition from './atoms/disabled-purposes'
5
+ import assetsApiDefinition from './api'
6
+ import assetPreferencesDefinition from './module/asset-preferences'
3
7
 
4
- const assets = () => {
8
+ const assets = ({ config = {} } = {}) => {
5
9
  return {
6
10
  id: 'assets',
7
11
  definitions: [
8
12
  { definition: assetsClientInterfaceDefinition },
9
13
  { definition: assetsPluginDefinition },
14
+ {
15
+ definition: multiAddressModeAtomDefinition,
16
+ storage: { namespace: 'assetPreferences' },
17
+ config: config.multiAddressMode || {},
18
+ },
19
+ {
20
+ definition: disabledPurposesAtomDefinition,
21
+ storage: { namespace: 'assetPreferences' },
22
+ config: config.disabledPurposes || {},
23
+ },
24
+ { definition: assetsApiDefinition },
25
+ {
26
+ definition: assetPreferencesDefinition,
27
+ writesAtoms: ['multiAddressModeAtom', 'disabledPurposesAtom'],
28
+ },
10
29
  ],
11
30
  }
12
31
  }
@@ -0,0 +1,61 @@
1
+ import ExodusModule from '@exodus/module'
2
+ import { omit } from '@exodus/basic-utils'
3
+
4
+ const MODULE_ID = 'assetPreferences'
5
+
6
+ class AssetPreferences extends ExodusModule {
7
+ #disabledPurposesAtom
8
+ #multiAddressModeAtom
9
+
10
+ constructor({ disabledPurposesAtom, multiAddressModeAtom, logger }) {
11
+ super({ name: MODULE_ID, logger })
12
+
13
+ this.#disabledPurposesAtom = disabledPurposesAtom
14
+ this.#multiAddressModeAtom = multiAddressModeAtom
15
+ }
16
+
17
+ enableMultiAddressMode = ({ assetNames }) =>
18
+ this.#multiAddressModeAtom.set((value) => ({
19
+ ...value,
20
+ ...assetNames.reduce((acc, assetName) => {
21
+ acc[assetName] = true
22
+ return acc
23
+ }, {}),
24
+ }))
25
+
26
+ disableMultiAddressMode = ({ assetNames }) =>
27
+ this.#multiAddressModeAtom.set((value) => omit(value, assetNames))
28
+
29
+ disablePurpose = ({ assetName, purpose }) =>
30
+ this.#disabledPurposesAtom.set((value) => {
31
+ const assetValue = value[assetName] || []
32
+ if (assetValue.includes(purpose)) return value
33
+
34
+ return {
35
+ ...value,
36
+ [assetName]: [...assetValue, purpose],
37
+ }
38
+ })
39
+
40
+ enablePurpose = ({ assetName, purpose }) =>
41
+ this.#disabledPurposesAtom.set((value) => {
42
+ const assetValue = value[assetName] || []
43
+ if (assetValue.includes(purpose)) {
44
+ return {
45
+ ...value,
46
+ [assetName]: assetValue.filter((disabledPurpose) => disabledPurpose !== purpose),
47
+ }
48
+ }
49
+
50
+ return value
51
+ })
52
+ }
53
+
54
+ const assetPreferencesDefinition = {
55
+ id: MODULE_ID,
56
+ type: 'module',
57
+ factory: (opts) => new AssetPreferences(opts),
58
+ dependencies: ['disabledPurposesAtom', 'multiAddressModeAtom', 'logger'],
59
+ }
60
+
61
+ export default assetPreferencesDefinition
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/assets-feature",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Assets module, clients and apis",
6
6
  "main": "index.js",
@@ -15,6 +15,8 @@
15
15
  "module",
16
16
  "plugin",
17
17
  "redux",
18
+ "api",
19
+ "atoms",
18
20
  "README.md",
19
21
  "CHANGELOG.md",
20
22
  "!**/__tests__/**"
@@ -35,10 +37,12 @@
35
37
  },
36
38
  "devDependencies": {
37
39
  "@exodus/assets": "^8.0.94",
40
+ "@exodus/atoms": "^5.6.0",
38
41
  "@exodus/available-assets": "^5.1.1",
39
42
  "@exodus/bitcoin-meta": "^1.0.1",
40
43
  "@exodus/ethereum-meta": "^1.0.30",
41
44
  "@exodus/models": "^9.1.1",
45
+ "@exodus/module": "^1.2.0",
42
46
  "@exodus/redux-dependency-injection": "^3.0.0",
43
47
  "@exodus/storage-memory": "^2.1.1",
44
48
  "@exodus/wallet-accounts": "^14.0.0",
@@ -48,5 +52,5 @@
48
52
  "jest": "^29.1.2",
49
53
  "redux": "^4.0.0"
50
54
  },
51
- "gitHead": "6671ae7aa9740e9492555099f43f5727d977edef"
55
+ "gitHead": "7c733496bd1e1748b59f2c30c51f9bb850035975"
52
56
  }
package/plugin/index.js CHANGED
@@ -1,6 +1,8 @@
1
- const createAssetsPlugin = ({ port, assetsModule }) => {
1
+ import { createAtomObserver } from '@exodus/atoms'
2
+
3
+ const createAssetsPlugin = ({ port, assetsModule, disabledPurposesAtom, multiAddressModeAtom }) => {
4
+ const emitAssetsLoad = () => port.emit('assets-load', Object.values(assetsModule.getAssets()))
2
5
  const listeners = [
3
- ['assets-load', () => port.emit('assets-load', Object.values(assetsModule.getAssets()))],
4
6
  ['assets-add', (data) => port.emit('assets-add', data)],
5
7
  ['assets-update', (data) => port.emit('assets-update', data)],
6
8
  ]
@@ -9,18 +11,31 @@ const createAssetsPlugin = ({ port, assetsModule }) => {
9
11
  assetsModule.on(event, callback)
10
12
  })
11
13
 
14
+ const observers = [
15
+ createAtomObserver({ atom: disabledPurposesAtom, port, event: 'disabledPurposes' }),
16
+ createAtomObserver({ atom: multiAddressModeAtom, port, event: 'multiAddressMode' }),
17
+ ]
18
+
12
19
  const onStart = async () => {
20
+ observers.forEach((observer) => observer.register())
21
+
13
22
  await assetsModule.load()
23
+ emitAssetsLoad()
14
24
  }
15
25
 
16
26
  const onLoad = async () => {
27
+ observers.forEach((observer) => observer.start())
28
+
17
29
  await assetsModule.load()
30
+ emitAssetsLoad()
18
31
  }
19
32
 
20
33
  const onStop = () => {
21
34
  listeners.forEach(([event, callback]) => {
22
35
  assetsModule.removeListener(event, callback)
23
36
  })
37
+
38
+ observers.forEach((observer) => observer.unregister())
24
39
  }
25
40
 
26
41
  return { onStart, onLoad, onStop }
@@ -30,7 +45,7 @@ const assetsPluginDefinition = {
30
45
  id: 'assetsPlugin',
31
46
  type: 'plugin',
32
47
  factory: createAssetsPlugin,
33
- dependencies: ['port', 'assetsModule'],
48
+ dependencies: ['port', 'assetsModule', 'disabledPurposesAtom', 'multiAddressModeAtom'],
34
49
  }
35
50
 
36
51
  export default assetsPluginDefinition
package/redux/index.js CHANGED
@@ -17,12 +17,21 @@ const assetsReduxDefinition = {
17
17
  initialState,
18
18
  eventReducers: {
19
19
  'assets-load': (state, payload) => ({
20
+ ...state,
20
21
  error: null,
21
22
  loaded: true,
22
23
  data: keyBy(payload, 'name'),
23
24
  }),
24
25
  'assets-add': mergeAssets,
25
26
  'assets-update': mergeAssets,
27
+ multiAddressMode: (state, payload) => ({
28
+ ...state,
29
+ multiAddressMode: payload,
30
+ }),
31
+ disabledPurposes: (state, payload) => ({
32
+ ...state,
33
+ disabledPurposes: payload,
34
+ }),
26
35
  },
27
36
  selectorDefinitions,
28
37
  }
@@ -2,6 +2,9 @@ const initialState = {
2
2
  loaded: false,
3
3
  data: {},
4
4
  error: null,
5
+ // asset preferences
6
+ multiAddressMode: {},
7
+ disabledPurposes: {},
5
8
  }
6
9
 
7
10
  export default initialState
@@ -49,6 +49,34 @@ const getAssetFromTickerSelectorDefinition = {
49
49
  dependencies: [{ selector: 'allByTicker' }],
50
50
  }
51
51
 
52
+ const createMultiAddressModeSelectorDefinition = {
53
+ id: 'createMultiAddressMode',
54
+ selectorFactory: (multiAddressModeDataSelector) =>
55
+ memoize((assetName) =>
56
+ createSelector(
57
+ multiAddressModeDataSelector,
58
+ (multiAddressModeData) => multiAddressModeData[assetName] || false
59
+ )
60
+ ),
61
+
62
+ dependencies: [{ selector: 'multiAddressMode' }],
63
+ }
64
+
65
+ const createDisabledPurposesSelectorDefinition = {
66
+ id: 'createDisabledPurposes',
67
+ selectorFactory: (disabledPurposesDataSelector) => {
68
+ const disabledPurposesDefaultValue = []
69
+ return memoize((assetName) =>
70
+ createSelector(
71
+ disabledPurposesDataSelector,
72
+ (disabledPurposesData) => disabledPurposesData[assetName] || disabledPurposesDefaultValue
73
+ )
74
+ )
75
+ },
76
+
77
+ dependencies: [{ selector: 'disabledPurposes' }],
78
+ }
79
+
52
80
  const assetSelectors = [
53
81
  allAssetsSelectorDefinition,
54
82
  allByTickerSelectorDefinition,
@@ -57,6 +85,8 @@ const assetSelectors = [
57
85
  createFeeAssetSelectorDefinition,
58
86
  getAssetSelectorDefinition,
59
87
  getAssetFromTickerSelectorDefinition,
88
+ createMultiAddressModeSelectorDefinition,
89
+ createDisabledPurposesSelectorDefinition,
60
90
  ]
61
91
 
62
92
  export default assetSelectors